KiCad PCB EDA Suite
Loading...
Searching...
No Matches
project_file.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020 CERN
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 * @author Jon Evans <[email protected]>
7 *
8 * This program is free software: you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation, either version 3 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include <project.h>
29#include <settings/parameters.h>
32#include <wx/config.h>
33#include <wx/log.h>
34
35
38
39
40PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) :
42 m_ErcSettings( nullptr ),
43 m_SchematicSettings( nullptr ),
45 m_sheets(),
46 m_boards(),
47 m_project( nullptr ),
48 m_wasMigrated( false )
49{
50 // Keep old files around
52
53 m_params.emplace_back( new PARAM_LIST<FILE_INFO_PAIR>( "sheets", &m_sheets, {} ) );
54
55 m_params.emplace_back( new PARAM_LIST<FILE_INFO_PAIR>( "boards", &m_boards, {} ) );
56
57 m_params.emplace_back( new PARAM_WXSTRING_MAP( "text_variables",
58 &m_TextVars, {}, false, true /* array behavior, even though stored as a map */ ) );
59
60 m_params.emplace_back( new PARAM_LIST<wxString>( "libraries.pinned_symbol_libs",
61 &m_PinnedSymbolLibs, {} ) );
62
63 m_params.emplace_back( new PARAM_LIST<wxString>( "libraries.pinned_footprint_libs",
64 &m_PinnedFootprintLibs, {} ) );
65
66 m_params.emplace_back( new PARAM_PATH_LIST( "cvpcb.equivalence_files",
67 &m_EquivalenceFiles, {} ) );
68
69 m_params.emplace_back( new PARAM_PATH( "pcbnew.page_layout_descr_file",
71
72 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.netlist",
74
75 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.idf",
77
78 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.vrml",
80
81 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.specctra_dsn",
83
84 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.plot",
86
87 m_params.emplace_back( new PARAM<wxString>( "schematic.legacy_lib_dir",
88 &m_LegacyLibDir, "" ) );
89
90 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "schematic.legacy_lib_list",
91 [&]() -> nlohmann::json
92 {
93 nlohmann::json ret = nlohmann::json::array();
94
95 for( const wxString& libName : m_LegacyLibNames )
96 ret.push_back( libName );
97
98 return ret;
99 },
100 [&]( const nlohmann::json& aJson )
101 {
102 if( aJson.empty() || !aJson.is_array() )
103 return;
104
105 m_LegacyLibNames.clear();
106
107 for( const nlohmann::json& entry : aJson )
108 m_LegacyLibNames.push_back( entry.get<wxString>() );
109 }, {} ) );
110
111 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "schematic.bus_aliases",
112 [&]() -> nlohmann::json
113 {
114 nlohmann::json ret = nlohmann::json::object();
115
116 for( const auto& alias : m_BusAliases )
117 {
118 nlohmann::json members = nlohmann::json::array();
119
120 for( const wxString& member : alias.second )
121 members.push_back( member );
122
123 ret[ alias.first.ToStdString() ] = members;
124 }
125
126 return ret;
127 },
128 [&]( const nlohmann::json& aJson )
129 {
130 if( aJson.empty() || !aJson.is_object() )
131 return;
132
133 m_BusAliases.clear();
134
135 for( auto it = aJson.begin(); it != aJson.end(); ++it )
136 {
137 const nlohmann::json& membersJson = it.value();
138
139 if( !membersJson.is_array() )
140 continue;
141
142 std::vector<wxString> members;
143
144 for( const nlohmann::json& entry : membersJson )
145 {
146 if( entry.is_string() )
147 members.push_back( entry.get<wxString>() );
148 }
149
150 m_BusAliases.emplace( wxString::FromUTF8( it.key().c_str() ), std::move( members ) );
151 }
152 }, {} ) );
153
154 m_NetSettings = std::make_shared<NET_SETTINGS>( this, "net_settings" );
155
157 std::make_shared<COMPONENT_CLASS_SETTINGS>( this, "component_class_settings" );
158
160 std::make_shared<TIME_DOMAIN_PARAMETERS>( this, "time_domain_parameters" );
161
162 m_params.emplace_back( new PARAM_LAYER_PRESET( "board.layer_presets", &m_LayerPresets ) );
163
164 m_params.emplace_back( new PARAM_VIEWPORT( "board.viewports", &m_Viewports ) );
165
166 m_params.emplace_back( new PARAM_VIEWPORT3D( "board.3dviewports", &m_Viewports3D ) );
167
168 m_params.emplace_back( new PARAM_LAYER_PAIRS( "board.layer_pairs", m_LayerPairInfos ) );
169
170 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.internal_id",
171 &m_IP2581Bom.id, wxEmptyString ) );
172
173 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mpn",
174 &m_IP2581Bom.MPN, wxEmptyString ) );
175
176 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mfg",
177 &m_IP2581Bom.mfg, wxEmptyString ) );
178
179 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.distpn",
180 &m_IP2581Bom.distPN, wxEmptyString ) );
181
182 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.dist",
183 &m_IP2581Bom.dist, wxEmptyString ) );
184
185
186 registerMigration( 1, 2, std::bind( &PROJECT_FILE::migrateSchema1To2, this ) );
187 registerMigration( 2, 3, std::bind( &PROJECT_FILE::migrateSchema2To3, this ) );
188}
189
190
192{
193 auto p( "/board/layer_presets"_json_pointer );
194
195 if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
196 return true;
197
198 nlohmann::json& presets = m_internals->at( p );
199
200 for( nlohmann::json& entry : presets )
202
203 m_wasMigrated = true;
204
205 return true;
206}
207
208
210{
211 auto p( "/board/layer_presets"_json_pointer );
212
213 if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
214 return true;
215
216 nlohmann::json& presets = m_internals->at( p );
217
218 for( nlohmann::json& entry : presets )
220
221 m_wasMigrated = true;
222
223 return true;
224}
225
226
227bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
228{
229 bool ret = true;
230 wxString str;
231 long index = 0;
232
233 std::set<wxString> group_blacklist;
234
235 // Legacy files don't store board info; they assume board matches project name
236 // We will leave m_boards empty here so it can be populated with other code
237
238 // First handle migration of data that will be stored locally in this object
239
240 auto loadPinnedLibs =
241 [&]( const std::string& aDest )
242 {
243 int libIndex = 1;
244 wxString libKey = wxT( "PinnedItems" );
245 libKey << libIndex;
246
247 nlohmann::json libs = nlohmann::json::array();
248
249 while( aCfg->Read( libKey, &str ) )
250 {
251 libs.push_back( str );
252
253 aCfg->DeleteEntry( libKey, true );
254
255 libKey = wxT( "PinnedItems" );
256 libKey << ++libIndex;
257 }
258
259 Set( aDest, libs );
260 };
261
262 aCfg->SetPath( wxT( "/LibeditFrame" ) );
263 loadPinnedLibs( "libraries.pinned_symbol_libs" );
264
265 aCfg->SetPath( wxT( "/ModEditFrame" ) );
266 loadPinnedLibs( "libraries.pinned_footprint_libs" );
267
268 aCfg->SetPath( wxT( "/cvpcb/equfiles" ) );
269
270 {
271 int eqIdx = 1;
272 wxString eqKey = wxT( "EquName" );
273 eqKey << eqIdx;
274
275 nlohmann::json eqs = nlohmann::json::array();
276
277 while( aCfg->Read( eqKey, &str ) )
278 {
279 eqs.push_back( str );
280
281 eqKey = wxT( "EquName" );
282 eqKey << ++eqIdx;
283 }
284
285 Set( "cvpcb.equivalence_files", eqs );
286 }
287
288 // All CvPcb params that we want to keep have been migrated above
289 group_blacklist.insert( wxT( "/cvpcb" ) );
290
291 aCfg->SetPath( wxT( "/eeschema" ) );
292 fromLegacyString( aCfg, "LibDir", "schematic.legacy_lib_dir" );
293
294 aCfg->SetPath( wxT( "/eeschema/libraries" ) );
295
296 {
297 int libIdx = 1;
298 wxString libKey = wxT( "LibName" );
299 libKey << libIdx;
300
301 nlohmann::json libs = nlohmann::json::array();
302
303 while( aCfg->Read( libKey, &str ) )
304 {
305 libs.push_back( str );
306
307 libKey = wxT( "LibName" );
308 libKey << ++libIdx;
309 }
310
311 Set( "schematic.legacy_lib_list", libs );
312 }
313
314 group_blacklist.insert( wxT( "/eeschema" ) );
315
316 aCfg->SetPath( wxT( "/text_variables" ) );
317
318 {
319 int txtIdx = 1;
320 wxString txtKey;
321 txtKey << txtIdx;
322
323 nlohmann::json vars = nlohmann::json();
324
325 while( aCfg->Read( txtKey, &str ) )
326 {
327 wxArrayString tokens = wxSplit( str, ':' );
328
329 if( tokens.size() == 2 )
330 vars[ tokens[0].ToStdString() ] = tokens[1];
331
332 txtKey.clear();
333 txtKey << ++txtIdx;
334 }
335
336 Set( "text_variables", vars );
337 }
338
339 group_blacklist.insert( wxT( "/text_variables" ) );
340
341 aCfg->SetPath( wxT( "/schematic_editor" ) );
342
343 fromLegacyString( aCfg, "PageLayoutDescrFile", "schematic.page_layout_descr_file" );
344 fromLegacyString( aCfg, "PlotDirectoryName", "schematic.plot_directory" );
345 fromLegacyString( aCfg, "NetFmtName", "schematic.net_format_name" );
346 fromLegacy<bool>( aCfg, "SpiceAjustPassiveValues", "schematic.spice_adjust_passive_values" );
347 fromLegacy<int>( aCfg, "SubpartIdSeparator", "schematic.subpart_id_separator" );
348 fromLegacy<int>( aCfg, "SubpartFirstId", "schematic.subpart_first_id" );
349
350 fromLegacy<int>( aCfg, "LineThickness", "schematic.drawing.default_line_thickness" );
351 fromLegacy<int>( aCfg, "WireThickness", "schematic.drawing.default_wire_thickness" );
352 fromLegacy<int>( aCfg, "BusThickness", "schematic.drawing.default_bus_thickness" );
353 fromLegacy<int>( aCfg, "LabSize", "schematic.drawing.default_text_size" );
354
355 if( !fromLegacy<int>( aCfg, "PinSymbolSize", "schematic.drawing.pin_symbol_size" ) )
356 {
357 // Use the default symbol size algorithm of Eeschema V5 (based on pin name/number size)
358 Set( "schematic.drawing.pin_symbol_size", 0 );
359 }
360
361 fromLegacy<int>( aCfg, "JunctionSize", "schematic.drawing.default_junction_size" );
362
363 fromLegacyString( aCfg, "FieldNameTemplates", "schematic.drawing.field_names" );
364
365 if( !fromLegacy<double>( aCfg, "TextOffsetRatio", "schematic.drawing.text_offset_ratio" ) )
366 {
367 // Use the spacing of Eeschema V5
368 Set( "schematic.drawing.text_offset_ratio", 0.08 );
369 Set( "schematic.drawing.label_size_ratio", 0.25 );
370 }
371
372 // All schematic_editor keys we keep are migrated above
373 group_blacklist.insert( wxT( "/schematic_editor" ) );
374
375 aCfg->SetPath( wxT( "/pcbnew" ) );
376
377 fromLegacyString( aCfg, "PageLayoutDescrFile", "pcbnew.page_layout_descr_file" );
378 fromLegacyString( aCfg, "LastNetListRead", "pcbnew.last_paths.netlist" );
379 fromLegacyString( aCfg, "LastSTEPExportPath", "pcbnew.last_paths.step" );
380 fromLegacyString( aCfg, "LastIDFExportPath", "pcbnew.last_paths.idf" );
381 fromLegacyString( aCfg, "LastVRMLExportPath", "pcbnew.last_paths.vmrl" );
382 fromLegacyString( aCfg, "LastSpecctraDSNExportPath", "pcbnew.last_paths.specctra_dsn" );
383 fromLegacyString( aCfg, "LastGenCADExportPath", "pcbnew.last_paths.gencad" );
384
385 std::string bp = "board.design_settings.";
386
387 {
388 int idx = 1;
389 wxString key = wxT( "DRCExclusion" );
390 key << idx;
391
392 nlohmann::json exclusions = nlohmann::json::array();
393
394 while( aCfg->Read( key, &str ) )
395 {
396 exclusions.push_back( str );
397
398 key = wxT( "DRCExclusion" );
399 key << ++idx;
400 }
401
402 Set( bp + "drc_exclusions", exclusions );
403 }
404
405 fromLegacy<bool>( aCfg, "AllowMicroVias", bp + "rules.allow_microvias" );
406 fromLegacy<bool>( aCfg, "AllowBlindVias", bp + "rules.allow_blind_buried_vias" );
407 fromLegacy<double>( aCfg, "MinClearance", bp + "rules.min_clearance" );
408 fromLegacy<double>( aCfg, "MinTrackWidth", bp + "rules.min_track_width" );
409 fromLegacy<double>( aCfg, "MinViaAnnulus", bp + "rules.min_via_annulus" );
410 fromLegacy<double>( aCfg, "MinViaDiameter", bp + "rules.min_via_diameter" );
411
412 if( !fromLegacy<double>( aCfg, "MinThroughDrill", bp + "rules.min_through_hole_diameter" ) )
413 fromLegacy<double>( aCfg, "MinViaDrill", bp + "rules.min_through_hole_diameter" );
414
415 fromLegacy<double>( aCfg, "MinMicroViaDiameter", bp + "rules.min_microvia_diameter" );
416 fromLegacy<double>( aCfg, "MinMicroViaDrill", bp + "rules.min_microvia_drill" );
417 fromLegacy<double>( aCfg, "MinHoleToHole", bp + "rules.min_hole_to_hole" );
418 fromLegacy<double>( aCfg, "CopperEdgeClearance", bp + "rules.min_copper_edge_clearance" );
419 fromLegacy<double>( aCfg, "SolderMaskClearance", bp + "rules.solder_mask_clearance" );
420 fromLegacy<double>( aCfg, "SolderMaskMinWidth", bp + "rules.solder_mask_min_width" );
421 fromLegacy<double>( aCfg, "SolderPasteClearance", bp + "rules.solder_paste_clearance" );
422 fromLegacy<double>( aCfg, "SolderPasteRatio", bp + "rules.solder_paste_margin_ratio" );
423
424 if( !fromLegacy<double>( aCfg, "SilkLineWidth", bp + "defaults.silk_line_width" ) )
425 fromLegacy<double>( aCfg, "ModuleOutlineThickness", bp + "defaults.silk_line_width" );
426
427 if( !fromLegacy<double>( aCfg, "SilkTextSizeV", bp + "defaults.silk_text_size_v" ) )
428 fromLegacy<double>( aCfg, "ModuleTextSizeV", bp + "defaults.silk_text_size_v" );
429
430 if( !fromLegacy<double>( aCfg, "SilkTextSizeH", bp + "defaults.silk_text_size_h" ) )
431 fromLegacy<double>( aCfg, "ModuleTextSizeH", bp + "defaults.silk_text_size_h" );
432
433 if( !fromLegacy<double>( aCfg, "SilkTextSizeThickness", bp + "defaults.silk_text_thickness" ) )
434 fromLegacy<double>( aCfg, "ModuleTextSizeThickness", bp + "defaults.silk_text_thickness" );
435
436 fromLegacy<bool>( aCfg, "SilkTextItalic", bp + "defaults.silk_text_italic" );
437 fromLegacy<bool>( aCfg, "SilkTextUpright", bp + "defaults.silk_text_upright" );
438
439 if( !fromLegacy<double>( aCfg, "CopperLineWidth", bp + "defaults.copper_line_width" ) )
440 fromLegacy<double>( aCfg, "DrawSegmentWidth", bp + "defaults.copper_line_width" );
441
442 if( !fromLegacy<double>( aCfg, "CopperTextSizeV", bp + "defaults.copper_text_size_v" ) )
443 fromLegacy<double>( aCfg, "PcbTextSizeV", bp + "defaults.copper_text_size_v" );
444
445 if( !fromLegacy<double>( aCfg, "CopperTextSizeH", bp + "defaults.copper_text_size_h" ) )
446 fromLegacy<double>( aCfg, "PcbTextSizeH", bp + "defaults.copper_text_size_h" );
447
448 if( !fromLegacy<double>( aCfg, "CopperTextThickness", bp + "defaults.copper_text_thickness" ) )
449 fromLegacy<double>( aCfg, "PcbTextThickness", bp + "defaults.copper_text_thickness" );
450
451 fromLegacy<bool>( aCfg, "CopperTextItalic", bp + "defaults.copper_text_italic" );
452 fromLegacy<bool>( aCfg, "CopperTextUpright", bp + "defaults.copper_text_upright" );
453
454 if( !fromLegacy<double>( aCfg, "EdgeCutLineWidth", bp + "defaults.board_outline_line_width" ) )
455 fromLegacy<double>( aCfg, "BoardOutlineThickness",
456 bp + "defaults.board_outline_line_width" );
457
458 fromLegacy<double>( aCfg, "CourtyardLineWidth", bp + "defaults.courtyard_line_width" );
459
460 fromLegacy<double>( aCfg, "FabLineWidth", bp + "defaults.fab_line_width" );
461 fromLegacy<double>( aCfg, "FabTextSizeV", bp + "defaults.fab_text_size_v" );
462 fromLegacy<double>( aCfg, "FabTextSizeH", bp + "defaults.fab_text_size_h" );
463 fromLegacy<double>( aCfg, "FabTextSizeThickness", bp + "defaults.fab_text_thickness" );
464 fromLegacy<bool>( aCfg, "FabTextItalic", bp + "defaults.fab_text_italic" );
465 fromLegacy<bool>( aCfg, "FabTextUpright", bp + "defaults.fab_text_upright" );
466
467 if( !fromLegacy<double>( aCfg, "OthersLineWidth", bp + "defaults.other_line_width" ) )
468 fromLegacy<double>( aCfg, "ModuleOutlineThickness", bp + "defaults.other_line_width" );
469
470 fromLegacy<double>( aCfg, "OthersTextSizeV", bp + "defaults.other_text_size_v" );
471 fromLegacy<double>( aCfg, "OthersTextSizeH", bp + "defaults.other_text_size_h" );
472 fromLegacy<double>( aCfg, "OthersTextSizeThickness", bp + "defaults.other_text_thickness" );
473 fromLegacy<bool>( aCfg, "OthersTextItalic", bp + "defaults.other_text_italic" );
474 fromLegacy<bool>( aCfg, "OthersTextUpright", bp + "defaults.other_text_upright" );
475
476 fromLegacy<int>( aCfg, "DimensionUnits", bp + "defaults.dimension_units" );
477 fromLegacy<int>( aCfg, "DimensionPrecision", bp + "defaults.dimension_precision" );
478
479 std::string sev = bp + "rule_severities";
480
481 fromLegacy<bool>( aCfg, "RequireCourtyardDefinitions", sev + "legacy_no_courtyard_defined" );
482
483 fromLegacy<bool>( aCfg, "ProhibitOverlappingCourtyards", sev + "legacy_courtyards_overlap" );
484
485 {
486 int idx = 1;
487 wxString keyBase = "TrackWidth";
488 wxString key = keyBase;
489 double val;
490
491 nlohmann::json widths = nlohmann::json::array();
492
493 key << idx;
494
495 while( aCfg->Read( key, &val ) )
496 {
497 widths.push_back( val );
498 key = keyBase;
499 key << ++idx;
500 }
501
502 Set( bp + "track_widths", widths );
503 }
504
505 {
506 int idx = 1;
507 wxString keyBase = "ViaDiameter";
508 wxString key = keyBase;
509 double diameter;
510 double drill = 1.0;
511
512 nlohmann::json vias = nlohmann::json::array();
513
514 key << idx;
515
516 while( aCfg->Read( key, &diameter ) )
517 {
518 key = "ViaDrill";
519 aCfg->Read( key << idx, &drill );
520
521 nlohmann::json via = { { "diameter", diameter }, { "drill", drill } };
522 vias.push_back( via );
523
524 key = keyBase;
525 key << ++idx;
526 }
527
528 Set( bp + "via_dimensions", vias );
529 }
530
531 {
532 int idx = 1;
533 wxString keyBase = "dPairWidth";
534 wxString key = keyBase;
535 double width;
536 double gap = 1.0;
537 double via_gap = 1.0;
538
539 nlohmann::json pairs = nlohmann::json::array();
540
541 key << idx;
542
543 while( aCfg->Read( key, &width ) )
544 {
545 key = "dPairGap";
546 aCfg->Read( key << idx, &gap );
547
548 key = "dPairViaGap";
549 aCfg->Read( key << idx, &via_gap );
550
551 nlohmann::json pair = { { "width", width }, { "gap", gap }, { "via_gap", via_gap } };
552 pairs.push_back( pair );
553
554 key = keyBase;
555 key << ++idx;
556 }
557
558 Set( bp + "diff_pair_dimensions", pairs );
559 }
560
561 group_blacklist.insert( wxT( "/pcbnew" ) );
562
563 // General group is unused these days, we can throw it away
564 group_blacklist.insert( wxT( "/general" ) );
565
566 // Next load sheet names and put all other legacy data in the legacy dict
567 aCfg->SetPath( wxT( "/" ) );
568
569 auto loadSheetNames =
570 [&]() -> bool
571 {
572 int sheet = 1;
573 wxString entry;
574 nlohmann::json arr = nlohmann::json::array();
575
576 wxLogTrace( traceSettings, wxT( "Migrating sheet names" ) );
577
578 aCfg->SetPath( wxT( "/sheetnames" ) );
579
580 while( aCfg->Read( wxString::Format( "%d", sheet++ ), &entry ) )
581 {
582 wxArrayString tokens = wxSplit( entry, ':' );
583
584 if( tokens.size() == 2 )
585 {
586 wxLogTrace( traceSettings, wxT( "%d: %s = %s" ), sheet, tokens[0],
587 tokens[1] );
588 arr.push_back( nlohmann::json::array( { tokens[0], tokens[1] } ) );
589 }
590 }
591
592 Set( "sheets", arr );
593
594 aCfg->SetPath( "/" );
595
596 // TODO: any reason we want to fail on this?
597 return true;
598 };
599
600 std::vector<wxString> groups;
601
602 groups.emplace_back( wxEmptyString );
603
604 auto loadLegacyPairs =
605 [&]( const std::string& aGroup ) -> bool
606 {
607 wxLogTrace( traceSettings, wxT( "Migrating group %s" ), aGroup );
608 bool success = true;
609 wxString keyStr;
610 wxString val;
611
612 index = 0;
613
614 while( aCfg->GetNextEntry( keyStr, index ) )
615 {
616 if( !aCfg->Read( keyStr, &val ) )
617 continue;
618
619 std::string key( keyStr.ToUTF8() );
620
621 wxLogTrace( traceSettings, wxT( " %s = %s" ), key, val );
622
623 try
624 {
625 Set( "legacy." + aGroup + "." + key, val );
626 }
627 catch( ... )
628 {
629 success = false;
630 }
631 }
632
633 return success;
634 };
635
636 for( size_t i = 0; i < groups.size(); i++ )
637 {
638 aCfg->SetPath( groups[i] );
639
640 if( groups[i] == wxT( "/sheetnames" ) )
641 {
642 ret |= loadSheetNames();
643 continue;
644 }
645
646 aCfg->DeleteEntry( wxT( "last_client" ), true );
647 aCfg->DeleteEntry( wxT( "update" ), true );
648 aCfg->DeleteEntry( wxT( "version" ), true );
649
650 ret &= loadLegacyPairs( groups[i].ToStdString() );
651
652 index = 0;
653
654 while( aCfg->GetNextGroup( str, index ) )
655 {
656 wxString group = groups[i] + "/" + str;
657
658 if( !group_blacklist.count( group ) )
659 groups.emplace_back( group );
660 }
661
662 aCfg->SetPath( "/" );
663 }
664
665 return ret;
666}
667
668
669bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
670{
671 wxASSERT( m_project );
672
673 Set( "meta.filename", m_project->GetProjectName() + "." + FILEEXT::ProjectFileExtension );
674
675 // Even if parameters were not modified, we should resave after migration
676 bool force = aForce || m_wasMigrated;
677
678 // If we're actually going ahead and doing the save, the flag that keeps code from doing the
679 // save should be cleared at this.
680 m_wasMigrated = false;
681
682 return JSON_SETTINGS::SaveToFile( aDirectory, force );
683}
684
685
686bool PROJECT_FILE::SaveAs( const wxString& aDirectory, const wxString& aFile )
687{
688 wxFileName oldFilename( GetFilename() );
689 wxString oldProjectName = oldFilename.GetName();
690 wxString oldProjectPath = oldFilename.GetPath();
691
692 Set( "meta.filename", aFile + "." + FILEEXT::ProjectFileExtension );
693 SetFilename( aFile );
694
695 auto updatePath =
696 [&]( wxString& aPath )
697 {
698 if( aPath.StartsWith( oldProjectName + wxS( "." ) ) )
699 aPath.Replace( oldProjectName, aFile, false );
700 else if( aPath.StartsWith( oldProjectPath + wxS( "/" ) ) )
701 aPath.Replace( oldProjectPath, aDirectory, false );
702 };
703
704 updatePath( m_BoardDrawingSheetFile );
705
706 for( int ii = LAST_PATH_FIRST; ii < (int) LAST_PATH_SIZE; ++ii )
707 updatePath( m_PcbLastPath[ ii ] );
708
709 auto updatePathByPtr =
710 [&]( const std::string& aPtr )
711 {
712 if( std::optional<wxString> path = Get<wxString>( aPtr ) )
713 {
714 updatePath( path.value() );
715 Set( aPtr, path.value() );
716 }
717 };
718
719 updatePathByPtr( "schematic.page_layout_descr_file" );
720 updatePathByPtr( "schematic.plot_directory" );
721 updatePathByPtr( "schematic.ngspice.workbook_filename" );
722 updatePathByPtr( "pcbnew.page_layout_descr_file" );
723
724 // If we're actually going ahead and doing the save, the flag that keeps code from doing the save
725 // should be cleared at this point
726 m_wasMigrated = false;
727
728 // While performing Save As, we have already checked that we can write to the directory
729 // so don't carry the previous flag
730 SetReadOnly( false );
731 return JSON_SETTINGS::SaveToFile( aDirectory, true );
732}
733
734
736{
738}
739
740
745
746
747void to_json( nlohmann::json& aJson, const FILE_INFO_PAIR& aPair )
748{
749 aJson = nlohmann::json::array( { aPair.first.AsString().ToUTF8(), aPair.second.ToUTF8() } );
750}
751
752
753void from_json( const nlohmann::json& aJson, FILE_INFO_PAIR& aPair )
754{
755 wxCHECK( aJson.is_array() && aJson.size() == 2, /* void */ );
756 aPair.first = KIID( wxString( aJson[0].get<std::string>().c_str(), wxConvUTF8 ) );
757 aPair.second = wxString( aJson[1].get<std::string>().c_str(), wxConvUTF8 );
758}
bool fromLegacyString(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig string value to a given JSON pointer value.
bool fromLegacy(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig value to a given JSON pointer value.
void Set(const std::string &aPath, ValueType aVal)
Stores a value into the JSON document Will throw an exception if ValueType isn't something that the l...
void SetReadOnly(bool aReadOnly)
std::optional< ValueType > Get(const std::string &aPath) const
Fetches a value from within the JSON document.
std::vector< PARAM_BASE * > m_params
The list of parameters (owned by this object)
void registerMigration(int aOldSchemaVersion, int aNewSchemaVersion, std::function< bool(void)> aMigrator)
Registers a migration from one schema version to another.
JSON_SETTINGS(const wxString &aFilename, SETTINGS_LOC aLocation, int aSchemaVersion)
bool m_deleteLegacyAfterMigration
Whether or not to delete legacy file after migration.
std::unique_ptr< JSON_SETTINGS_INTERNALS > m_internals
void SetFilename(const wxString &aFilename)
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
Calls Store() and then writes the contents of the JSON document to a file.
wxString GetFilename() const
Definition kiid.h:49
Like a normal param, but with custom getter and setter functions.
Definition parameters.h:296
static void MigrateToV9Layers(nlohmann::json &aJson)
static void MigrateToNamedRenderLayers(nlohmann::json &aJson)
Represents a list of strings holding directory paths.
Definition parameters.h:676
Stores a path as a string with directory separators normalized to unix-style.
Definition parameters.h:175
A helper for <wxString, wxString> maps.
Definition parameters.h:823
std::map< wxString, wxString > m_TextVars
wxString getFileExt() const override
std::vector< LAYER_PAIR_INFO > m_LayerPairInfos
List of stored 3D viewports (view matrixes)
ERC_SETTINGS * m_ErcSettings
Eeschema params.
wxString m_LegacyLibDir
SCHEMATIC_SETTINGS * m_SchematicSettings
bool migrateSchema1To2()
IPC-2581 BOM settings.
wxString m_BoardDrawingSheetFile
PcbNew params.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
struct IP2581_BOM m_IP2581Bom
Layer pair list for the board.
wxString m_PcbLastPath[LAST_PATH_SIZE]
MRU path storage.
PROJECT * m_project
A link to the owning PROJECT.
std::shared_ptr< TIME_DOMAIN_PARAMETERS > m_timeDomainParameters
Time domain parameters for this project.
std::vector< VIEWPORT > m_Viewports
List of stored layer presets.
BOARD_DESIGN_SETTINGS * m_BoardSettings
Board design settings for this project's board.
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
std::map< wxString, std::vector< wxString > > m_BusAliases
Bus alias definitions for the schematic project.
std::vector< wxString > m_EquivalenceFiles
CvPcb params.
bool migrateSchema2To3()
Schema version 3: move layer presets to use named render layers.
wxString getLegacyFileExt() const override
std::vector< wxString > m_PinnedFootprintLibs
The list of pinned footprint libraries.
std::vector< FILE_INFO_PAIR > m_sheets
An list of schematic sheets in this project.
virtual bool MigrateFromLegacy(wxConfigBase *aCfg) override
Migrates from wxConfig to JSON-based configuration.
std::vector< LAYER_PRESET > m_LayerPresets
std::vector< FILE_INFO_PAIR > m_boards
A list of board files in this project.
wxArrayString m_LegacyLibNames
std::vector< wxString > m_PinnedSymbolLibs
Below are project-level settings that have not been moved to a dedicated file.
std::vector< VIEWPORT3D > m_Viewports3D
List of stored viewports (pos + zoom)
bool SaveToFile(const wxString &aDirectory="", bool aForce=false) override
Calls Store() and then writes the contents of the JSON document to a file.
PROJECT_FILE(const wxString &aFullPath)
Construct the project file for a project.
std::shared_ptr< COMPONENT_CLASS_SETTINGS > m_ComponentClassSettings
Component class settings for the project (owned here)
Container for project specific data.
Definition project.h:65
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
SETTINGS_LOC
#define traceSettings
void to_json(nlohmann::json &aJson, const FILE_INFO_PAIR &aPair)
void from_json(const nlohmann::json &aJson, FILE_INFO_PAIR &aPair)
const int projectFileSchemaVersion
! Update the schema version whenever a migration is required
@ LAST_PATH_PLOT
@ LAST_PATH_SPECCTRADSN
@ LAST_PATH_SIZE
@ LAST_PATH_FIRST
@ LAST_PATH_IDF
@ LAST_PATH_VRML
@ LAST_PATH_NETLIST
std::pair< KIID, wxString > FILE_INFO_PAIR
For files like sheets and boards, a pair of that object KIID and display name Display name is typical...
Definition of file extensions used in Kicad.