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(),
47 m_boards(),
48 m_project( nullptr ),
49 m_wasMigrated( false )
50{
51 // Keep old files around
53
54 m_params.emplace_back( new PARAM_LIST<FILE_INFO_PAIR>( "sheets", &m_sheets, {} ) );
55
56 m_params.emplace_back( new PARAM_LIST<TOP_LEVEL_SHEET_INFO>( "schematic.top_level_sheets",
57 &m_topLevelSheets, {} ) );
58
59 m_params.emplace_back( new PARAM_LIST<FILE_INFO_PAIR>( "boards", &m_boards, {} ) );
60
61 m_params.emplace_back( new PARAM_WXSTRING_MAP( "text_variables",
62 &m_TextVars, {}, false, true /* array behavior, even though stored as a map */ ) );
63
64 m_params.emplace_back( new PARAM_LIST<wxString>( "libraries.pinned_symbol_libs",
65 &m_PinnedSymbolLibs, {} ) );
66
67 m_params.emplace_back( new PARAM_LIST<wxString>( "libraries.pinned_footprint_libs",
68 &m_PinnedFootprintLibs, {} ) );
69
70 m_params.emplace_back( new PARAM_PATH_LIST( "cvpcb.equivalence_files",
71 &m_EquivalenceFiles, {} ) );
72
73 m_params.emplace_back( new PARAM_PATH( "pcbnew.page_layout_descr_file",
75
76 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.netlist",
78
79 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.idf",
81
82 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.vrml",
84
85 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.specctra_dsn",
87
88 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.plot",
90
91 m_params.emplace_back( new PARAM<wxString>( "schematic.legacy_lib_dir",
92 &m_LegacyLibDir, "" ) );
93
94 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "schematic.legacy_lib_list",
95 [&]() -> nlohmann::json
96 {
97 nlohmann::json ret = nlohmann::json::array();
98
99 for( const wxString& libName : m_LegacyLibNames )
100 ret.push_back( libName );
101
102 return ret;
103 },
104 [&]( const nlohmann::json& aJson )
105 {
106 if( aJson.empty() || !aJson.is_array() )
107 return;
108
109 m_LegacyLibNames.clear();
110
111 for( const nlohmann::json& entry : aJson )
112 m_LegacyLibNames.push_back( entry.get<wxString>() );
113 }, {} ) );
114
115 m_params.emplace_back( new PARAM_LAMBDA<nlohmann::json>( "schematic.bus_aliases",
116 [&]() -> nlohmann::json
117 {
118 nlohmann::json ret = nlohmann::json::object();
119
120 for( const auto& alias : m_BusAliases )
121 {
122 nlohmann::json members = nlohmann::json::array();
123
124 for( const wxString& member : alias.second )
125 members.push_back( member );
126
127 ret[ alias.first.ToStdString() ] = members;
128 }
129
130 return ret;
131 },
132 [&]( const nlohmann::json& aJson )
133 {
134 if( aJson.empty() || !aJson.is_object() )
135 return;
136
137 m_BusAliases.clear();
138
139 for( auto it = aJson.begin(); it != aJson.end(); ++it )
140 {
141 const nlohmann::json& membersJson = it.value();
142
143 if( !membersJson.is_array() )
144 continue;
145
146 std::vector<wxString> members;
147
148 for( const nlohmann::json& entry : membersJson )
149 {
150 if( entry.is_string() )
151 members.push_back( entry.get<wxString>() );
152 }
153
154 m_BusAliases.emplace( wxString::FromUTF8( it.key().c_str() ), std::move( members ) );
155 }
156 }, {} ) );
157
158 m_NetSettings = std::make_shared<NET_SETTINGS>( this, "net_settings" );
159
161 std::make_shared<COMPONENT_CLASS_SETTINGS>( this, "component_class_settings" );
162
163 m_tuningProfileParameters = std::make_shared<TUNING_PROFILES>( this, "tuning_profiles" );
164
165 m_params.emplace_back( new PARAM_LAYER_PRESET( "board.layer_presets", &m_LayerPresets ) );
166
167 m_params.emplace_back( new PARAM_VIEWPORT( "board.viewports", &m_Viewports ) );
168
169 m_params.emplace_back( new PARAM_VIEWPORT3D( "board.3dviewports", &m_Viewports3D ) );
170
171 m_params.emplace_back( new PARAM_LAYER_PAIRS( "board.layer_pairs", m_LayerPairInfos ) );
172
173 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.internal_id",
174 &m_IP2581Bom.id, wxEmptyString ) );
175
176 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mpn",
177 &m_IP2581Bom.MPN, wxEmptyString ) );
178
179 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mfg",
180 &m_IP2581Bom.mfg, wxEmptyString ) );
181
182 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.distpn",
183 &m_IP2581Bom.distPN, wxEmptyString ) );
184
185 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.dist",
186 &m_IP2581Bom.dist, wxEmptyString ) );
187
188
189 registerMigration( 1, 2, std::bind( &PROJECT_FILE::migrateSchema1To2, this ) );
190 registerMigration( 2, 3, std::bind( &PROJECT_FILE::migrateSchema2To3, this ) );
191}
192
193
195{
196 auto p( "/board/layer_presets"_json_pointer );
197
198 if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
199 return true;
200
201 nlohmann::json& presets = m_internals->at( p );
202
203 for( nlohmann::json& entry : presets )
205
206 m_wasMigrated = true;
207
208 return true;
209}
210
211
213{
214 auto p( "/board/layer_presets"_json_pointer );
215
216 if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
217 return true;
218
219 nlohmann::json& presets = m_internals->at( p );
220
221 for( nlohmann::json& entry : presets )
223
224 m_wasMigrated = true;
225
226 return true;
227}
228
229
230bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
231{
232 bool ret = true;
233 wxString str;
234 long index = 0;
235
236 std::set<wxString> group_blacklist;
237
238 // Legacy files don't store board info; they assume board matches project name
239 // We will leave m_boards empty here so it can be populated with other code
240
241 // First handle migration of data that will be stored locally in this object
242
243 auto loadPinnedLibs =
244 [&]( const std::string& aDest )
245 {
246 int libIndex = 1;
247 wxString libKey = wxT( "PinnedItems" );
248 libKey << libIndex;
249
250 nlohmann::json libs = nlohmann::json::array();
251
252 while( aCfg->Read( libKey, &str ) )
253 {
254 libs.push_back( str );
255
256 aCfg->DeleteEntry( libKey, true );
257
258 libKey = wxT( "PinnedItems" );
259 libKey << ++libIndex;
260 }
261
262 Set( aDest, libs );
263 };
264
265 aCfg->SetPath( wxT( "/LibeditFrame" ) );
266 loadPinnedLibs( "libraries.pinned_symbol_libs" );
267
268 aCfg->SetPath( wxT( "/ModEditFrame" ) );
269 loadPinnedLibs( "libraries.pinned_footprint_libs" );
270
271 aCfg->SetPath( wxT( "/cvpcb/equfiles" ) );
272
273 {
274 int eqIdx = 1;
275 wxString eqKey = wxT( "EquName" );
276 eqKey << eqIdx;
277
278 nlohmann::json eqs = nlohmann::json::array();
279
280 while( aCfg->Read( eqKey, &str ) )
281 {
282 eqs.push_back( str );
283
284 eqKey = wxT( "EquName" );
285 eqKey << ++eqIdx;
286 }
287
288 Set( "cvpcb.equivalence_files", eqs );
289 }
290
291 // All CvPcb params that we want to keep have been migrated above
292 group_blacklist.insert( wxT( "/cvpcb" ) );
293
294 aCfg->SetPath( wxT( "/eeschema" ) );
295 fromLegacyString( aCfg, "LibDir", "schematic.legacy_lib_dir" );
296
297 aCfg->SetPath( wxT( "/eeschema/libraries" ) );
298
299 {
300 int libIdx = 1;
301 wxString libKey = wxT( "LibName" );
302 libKey << libIdx;
303
304 nlohmann::json libs = nlohmann::json::array();
305
306 while( aCfg->Read( libKey, &str ) )
307 {
308 libs.push_back( str );
309
310 libKey = wxT( "LibName" );
311 libKey << ++libIdx;
312 }
313
314 Set( "schematic.legacy_lib_list", libs );
315 }
316
317 group_blacklist.insert( wxT( "/eeschema" ) );
318
319 aCfg->SetPath( wxT( "/text_variables" ) );
320
321 {
322 int txtIdx = 1;
323 wxString txtKey;
324 txtKey << txtIdx;
325
326 nlohmann::json vars = nlohmann::json();
327
328 while( aCfg->Read( txtKey, &str ) )
329 {
330 wxArrayString tokens = wxSplit( str, ':' );
331
332 if( tokens.size() == 2 )
333 vars[ tokens[0].ToStdString() ] = tokens[1];
334
335 txtKey.clear();
336 txtKey << ++txtIdx;
337 }
338
339 Set( "text_variables", vars );
340 }
341
342 group_blacklist.insert( wxT( "/text_variables" ) );
343
344 aCfg->SetPath( wxT( "/schematic_editor" ) );
345
346 fromLegacyString( aCfg, "PageLayoutDescrFile", "schematic.page_layout_descr_file" );
347 fromLegacyString( aCfg, "PlotDirectoryName", "schematic.plot_directory" );
348 fromLegacyString( aCfg, "NetFmtName", "schematic.net_format_name" );
349 fromLegacy<bool>( aCfg, "SpiceAjustPassiveValues", "schematic.spice_adjust_passive_values" );
350 fromLegacy<int>( aCfg, "SubpartIdSeparator", "schematic.subpart_id_separator" );
351 fromLegacy<int>( aCfg, "SubpartFirstId", "schematic.subpart_first_id" );
352
353 fromLegacy<int>( aCfg, "LineThickness", "schematic.drawing.default_line_thickness" );
354 fromLegacy<int>( aCfg, "WireThickness", "schematic.drawing.default_wire_thickness" );
355 fromLegacy<int>( aCfg, "BusThickness", "schematic.drawing.default_bus_thickness" );
356 fromLegacy<int>( aCfg, "LabSize", "schematic.drawing.default_text_size" );
357
358 if( !fromLegacy<int>( aCfg, "PinSymbolSize", "schematic.drawing.pin_symbol_size" ) )
359 {
360 // Use the default symbol size algorithm of Eeschema V5 (based on pin name/number size)
361 Set( "schematic.drawing.pin_symbol_size", 0 );
362 }
363
364 fromLegacy<int>( aCfg, "JunctionSize", "schematic.drawing.default_junction_size" );
365
366 fromLegacyString( aCfg, "FieldNameTemplates", "schematic.drawing.field_names" );
367
368 if( !fromLegacy<double>( aCfg, "TextOffsetRatio", "schematic.drawing.text_offset_ratio" ) )
369 {
370 // Use the spacing of Eeschema V5
371 Set( "schematic.drawing.text_offset_ratio", 0.08 );
372 Set( "schematic.drawing.label_size_ratio", 0.25 );
373 }
374
375 // All schematic_editor keys we keep are migrated above
376 group_blacklist.insert( wxT( "/schematic_editor" ) );
377
378 aCfg->SetPath( wxT( "/pcbnew" ) );
379
380 fromLegacyString( aCfg, "PageLayoutDescrFile", "pcbnew.page_layout_descr_file" );
381 fromLegacyString( aCfg, "LastNetListRead", "pcbnew.last_paths.netlist" );
382 fromLegacyString( aCfg, "LastSTEPExportPath", "pcbnew.last_paths.step" );
383 fromLegacyString( aCfg, "LastIDFExportPath", "pcbnew.last_paths.idf" );
384 fromLegacyString( aCfg, "LastVRMLExportPath", "pcbnew.last_paths.vmrl" );
385 fromLegacyString( aCfg, "LastSpecctraDSNExportPath", "pcbnew.last_paths.specctra_dsn" );
386 fromLegacyString( aCfg, "LastGenCADExportPath", "pcbnew.last_paths.gencad" );
387
388 std::string bp = "board.design_settings.";
389
390 {
391 int idx = 1;
392 wxString key = wxT( "DRCExclusion" );
393 key << idx;
394
395 nlohmann::json exclusions = nlohmann::json::array();
396
397 while( aCfg->Read( key, &str ) )
398 {
399 exclusions.push_back( str );
400
401 key = wxT( "DRCExclusion" );
402 key << ++idx;
403 }
404
405 Set( bp + "drc_exclusions", exclusions );
406 }
407
408 fromLegacy<bool>( aCfg, "AllowMicroVias", bp + "rules.allow_microvias" );
409 fromLegacy<bool>( aCfg, "AllowBlindVias", bp + "rules.allow_blind_buried_vias" );
410 fromLegacy<double>( aCfg, "MinClearance", bp + "rules.min_clearance" );
411 fromLegacy<double>( aCfg, "MinTrackWidth", bp + "rules.min_track_width" );
412 fromLegacy<double>( aCfg, "MinViaAnnulus", bp + "rules.min_via_annulus" );
413 fromLegacy<double>( aCfg, "MinViaDiameter", bp + "rules.min_via_diameter" );
414
415 if( !fromLegacy<double>( aCfg, "MinThroughDrill", bp + "rules.min_through_hole_diameter" ) )
416 fromLegacy<double>( aCfg, "MinViaDrill", bp + "rules.min_through_hole_diameter" );
417
418 fromLegacy<double>( aCfg, "MinMicroViaDiameter", bp + "rules.min_microvia_diameter" );
419 fromLegacy<double>( aCfg, "MinMicroViaDrill", bp + "rules.min_microvia_drill" );
420 fromLegacy<double>( aCfg, "MinHoleToHole", bp + "rules.min_hole_to_hole" );
421 fromLegacy<double>( aCfg, "CopperEdgeClearance", bp + "rules.min_copper_edge_clearance" );
422 fromLegacy<double>( aCfg, "SolderMaskClearance", bp + "rules.solder_mask_clearance" );
423 fromLegacy<double>( aCfg, "SolderMaskMinWidth", bp + "rules.solder_mask_min_width" );
424 fromLegacy<double>( aCfg, "SolderPasteClearance", bp + "rules.solder_paste_clearance" );
425 fromLegacy<double>( aCfg, "SolderPasteRatio", bp + "rules.solder_paste_margin_ratio" );
426
427 if( !fromLegacy<double>( aCfg, "SilkLineWidth", bp + "defaults.silk_line_width" ) )
428 fromLegacy<double>( aCfg, "ModuleOutlineThickness", bp + "defaults.silk_line_width" );
429
430 if( !fromLegacy<double>( aCfg, "SilkTextSizeV", bp + "defaults.silk_text_size_v" ) )
431 fromLegacy<double>( aCfg, "ModuleTextSizeV", bp + "defaults.silk_text_size_v" );
432
433 if( !fromLegacy<double>( aCfg, "SilkTextSizeH", bp + "defaults.silk_text_size_h" ) )
434 fromLegacy<double>( aCfg, "ModuleTextSizeH", bp + "defaults.silk_text_size_h" );
435
436 if( !fromLegacy<double>( aCfg, "SilkTextSizeThickness", bp + "defaults.silk_text_thickness" ) )
437 fromLegacy<double>( aCfg, "ModuleTextSizeThickness", bp + "defaults.silk_text_thickness" );
438
439 fromLegacy<bool>( aCfg, "SilkTextItalic", bp + "defaults.silk_text_italic" );
440 fromLegacy<bool>( aCfg, "SilkTextUpright", bp + "defaults.silk_text_upright" );
441
442 if( !fromLegacy<double>( aCfg, "CopperLineWidth", bp + "defaults.copper_line_width" ) )
443 fromLegacy<double>( aCfg, "DrawSegmentWidth", bp + "defaults.copper_line_width" );
444
445 if( !fromLegacy<double>( aCfg, "CopperTextSizeV", bp + "defaults.copper_text_size_v" ) )
446 fromLegacy<double>( aCfg, "PcbTextSizeV", bp + "defaults.copper_text_size_v" );
447
448 if( !fromLegacy<double>( aCfg, "CopperTextSizeH", bp + "defaults.copper_text_size_h" ) )
449 fromLegacy<double>( aCfg, "PcbTextSizeH", bp + "defaults.copper_text_size_h" );
450
451 if( !fromLegacy<double>( aCfg, "CopperTextThickness", bp + "defaults.copper_text_thickness" ) )
452 fromLegacy<double>( aCfg, "PcbTextThickness", bp + "defaults.copper_text_thickness" );
453
454 fromLegacy<bool>( aCfg, "CopperTextItalic", bp + "defaults.copper_text_italic" );
455 fromLegacy<bool>( aCfg, "CopperTextUpright", bp + "defaults.copper_text_upright" );
456
457 if( !fromLegacy<double>( aCfg, "EdgeCutLineWidth", bp + "defaults.board_outline_line_width" ) )
458 fromLegacy<double>( aCfg, "BoardOutlineThickness",
459 bp + "defaults.board_outline_line_width" );
460
461 fromLegacy<double>( aCfg, "CourtyardLineWidth", bp + "defaults.courtyard_line_width" );
462
463 fromLegacy<double>( aCfg, "FabLineWidth", bp + "defaults.fab_line_width" );
464 fromLegacy<double>( aCfg, "FabTextSizeV", bp + "defaults.fab_text_size_v" );
465 fromLegacy<double>( aCfg, "FabTextSizeH", bp + "defaults.fab_text_size_h" );
466 fromLegacy<double>( aCfg, "FabTextSizeThickness", bp + "defaults.fab_text_thickness" );
467 fromLegacy<bool>( aCfg, "FabTextItalic", bp + "defaults.fab_text_italic" );
468 fromLegacy<bool>( aCfg, "FabTextUpright", bp + "defaults.fab_text_upright" );
469
470 if( !fromLegacy<double>( aCfg, "OthersLineWidth", bp + "defaults.other_line_width" ) )
471 fromLegacy<double>( aCfg, "ModuleOutlineThickness", bp + "defaults.other_line_width" );
472
473 fromLegacy<double>( aCfg, "OthersTextSizeV", bp + "defaults.other_text_size_v" );
474 fromLegacy<double>( aCfg, "OthersTextSizeH", bp + "defaults.other_text_size_h" );
475 fromLegacy<double>( aCfg, "OthersTextSizeThickness", bp + "defaults.other_text_thickness" );
476 fromLegacy<bool>( aCfg, "OthersTextItalic", bp + "defaults.other_text_italic" );
477 fromLegacy<bool>( aCfg, "OthersTextUpright", bp + "defaults.other_text_upright" );
478
479 fromLegacy<int>( aCfg, "DimensionUnits", bp + "defaults.dimension_units" );
480 fromLegacy<int>( aCfg, "DimensionPrecision", bp + "defaults.dimension_precision" );
481
482 std::string sev = bp + "rule_severities";
483
484 fromLegacy<bool>( aCfg, "RequireCourtyardDefinitions", sev + "legacy_no_courtyard_defined" );
485
486 fromLegacy<bool>( aCfg, "ProhibitOverlappingCourtyards", sev + "legacy_courtyards_overlap" );
487
488 {
489 int idx = 1;
490 wxString keyBase = "TrackWidth";
491 wxString key = keyBase;
492 double val;
493
494 nlohmann::json widths = nlohmann::json::array();
495
496 key << idx;
497
498 while( aCfg->Read( key, &val ) )
499 {
500 widths.push_back( val );
501 key = keyBase;
502 key << ++idx;
503 }
504
505 Set( bp + "track_widths", widths );
506 }
507
508 {
509 int idx = 1;
510 wxString keyBase = "ViaDiameter";
511 wxString key = keyBase;
512 double diameter;
513 double drill = 1.0;
514
515 nlohmann::json vias = nlohmann::json::array();
516
517 key << idx;
518
519 while( aCfg->Read( key, &diameter ) )
520 {
521 key = "ViaDrill";
522 aCfg->Read( key << idx, &drill );
523
524 nlohmann::json via = { { "diameter", diameter }, { "drill", drill } };
525 vias.push_back( via );
526
527 key = keyBase;
528 key << ++idx;
529 }
530
531 Set( bp + "via_dimensions", vias );
532 }
533
534 {
535 int idx = 1;
536 wxString keyBase = "dPairWidth";
537 wxString key = keyBase;
538 double width;
539 double gap = 1.0;
540 double via_gap = 1.0;
541
542 nlohmann::json pairs = nlohmann::json::array();
543
544 key << idx;
545
546 while( aCfg->Read( key, &width ) )
547 {
548 key = "dPairGap";
549 aCfg->Read( key << idx, &gap );
550
551 key = "dPairViaGap";
552 aCfg->Read( key << idx, &via_gap );
553
554 nlohmann::json pair = { { "width", width }, { "gap", gap }, { "via_gap", via_gap } };
555 pairs.push_back( pair );
556
557 key = keyBase;
558 key << ++idx;
559 }
560
561 Set( bp + "diff_pair_dimensions", pairs );
562 }
563
564 group_blacklist.insert( wxT( "/pcbnew" ) );
565
566 // General group is unused these days, we can throw it away
567 group_blacklist.insert( wxT( "/general" ) );
568
569 // Next load sheet names and put all other legacy data in the legacy dict
570 aCfg->SetPath( wxT( "/" ) );
571
572 auto loadSheetNames =
573 [&]() -> bool
574 {
575 int sheet = 1;
576 wxString entry;
577 nlohmann::json arr = nlohmann::json::array();
578
579 wxLogTrace( traceSettings, wxT( "Migrating sheet names" ) );
580
581 aCfg->SetPath( wxT( "/sheetnames" ) );
582
583 while( aCfg->Read( wxString::Format( "%d", sheet++ ), &entry ) )
584 {
585 wxArrayString tokens = wxSplit( entry, ':' );
586
587 if( tokens.size() == 2 )
588 {
589 wxLogTrace( traceSettings, wxT( "%d: %s = %s" ), sheet, tokens[0],
590 tokens[1] );
591 arr.push_back( nlohmann::json::array( { tokens[0], tokens[1] } ) );
592 }
593 }
594
595 Set( "sheets", arr );
596
597 aCfg->SetPath( "/" );
598
599 // TODO: any reason we want to fail on this?
600 return true;
601 };
602
603 std::vector<wxString> groups;
604
605 groups.emplace_back( wxEmptyString );
606
607 auto loadLegacyPairs =
608 [&]( const std::string& aGroup ) -> bool
609 {
610 wxLogTrace( traceSettings, wxT( "Migrating group %s" ), aGroup );
611 bool success = true;
612 wxString keyStr;
613 wxString val;
614
615 index = 0;
616
617 while( aCfg->GetNextEntry( keyStr, index ) )
618 {
619 if( !aCfg->Read( keyStr, &val ) )
620 continue;
621
622 std::string key( keyStr.ToUTF8() );
623
624 wxLogTrace( traceSettings, wxT( " %s = %s" ), key, val );
625
626 try
627 {
628 Set( "legacy." + aGroup + "." + key, val );
629 }
630 catch( ... )
631 {
632 success = false;
633 }
634 }
635
636 return success;
637 };
638
639 for( size_t i = 0; i < groups.size(); i++ )
640 {
641 aCfg->SetPath( groups[i] );
642
643 if( groups[i] == wxT( "/sheetnames" ) )
644 {
645 ret |= loadSheetNames();
646 continue;
647 }
648
649 aCfg->DeleteEntry( wxT( "last_client" ), true );
650 aCfg->DeleteEntry( wxT( "update" ), true );
651 aCfg->DeleteEntry( wxT( "version" ), true );
652
653 ret &= loadLegacyPairs( groups[i].ToStdString() );
654
655 index = 0;
656
657 while( aCfg->GetNextGroup( str, index ) )
658 {
659 wxString group = groups[i] + "/" + str;
660
661 if( !group_blacklist.count( group ) )
662 groups.emplace_back( group );
663 }
664
665 aCfg->SetPath( "/" );
666 }
667
668 return ret;
669}
670
671
672bool PROJECT_FILE::LoadFromFile( const wxString& aDirectory )
673{
674 bool success = JSON_SETTINGS::LoadFromFile( aDirectory );
675
676 if( success )
677 {
678 // Migrate from old single-root format to top_level_sheets format
679 if( m_topLevelSheets.empty() && m_project )
680 {
681 // Create a default top-level sheet entry based on the project name
682 wxString projectName = m_project->GetProjectName();
683
684 TOP_LEVEL_SHEET_INFO defaultSheet;
685 defaultSheet.uuid = niluuid; // Use niluuid for the first/default sheet
686 defaultSheet.name = projectName;
687 defaultSheet.filename = projectName + ".kicad_sch";
688
689 m_topLevelSheets.push_back( std::move( defaultSheet ) );
690
691 // Mark as migrated so it will be saved with the new format
692 m_wasMigrated = true;
693
694 wxLogTrace( traceSettings, wxT( "PROJECT_FILE: Migrated old single-root format to top_level_sheets" ) );
695 }
696 }
697
698 return success;
699}
700
701
702bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
703{
704 wxASSERT( m_project );
705
706 Set( "meta.filename", m_project->GetProjectName() + "." + FILEEXT::ProjectFileExtension );
707
708 // Even if parameters were not modified, we should resave after migration
709 bool force = aForce || m_wasMigrated;
710
711 // If we're actually going ahead and doing the save, the flag that keeps code from doing the
712 // save should be cleared at this.
713 m_wasMigrated = false;
714
715 return JSON_SETTINGS::SaveToFile( aDirectory, force );
716}
717
718
719bool PROJECT_FILE::SaveAs( const wxString& aDirectory, const wxString& aFile )
720{
721 wxFileName oldFilename( GetFilename() );
722 wxString oldProjectName = oldFilename.GetName();
723 wxString oldProjectPath = oldFilename.GetPath();
724
725 Set( "meta.filename", aFile + "." + FILEEXT::ProjectFileExtension );
726 SetFilename( aFile );
727
728 auto updatePath =
729 [&]( wxString& aPath )
730 {
731 if( aPath.StartsWith( oldProjectName + wxS( "." ) ) )
732 aPath.Replace( oldProjectName, aFile, false );
733 else if( aPath.StartsWith( oldProjectPath + wxS( "/" ) ) )
734 aPath.Replace( oldProjectPath, aDirectory, false );
735 };
736
737 updatePath( m_BoardDrawingSheetFile );
738
739 for( int ii = LAST_PATH_FIRST; ii < (int) LAST_PATH_SIZE; ++ii )
740 updatePath( m_PcbLastPath[ ii ] );
741
742 auto updatePathByPtr =
743 [&]( const std::string& aPtr )
744 {
745 if( std::optional<wxString> path = Get<wxString>( aPtr ) )
746 {
747 updatePath( path.value() );
748 Set( aPtr, path.value() );
749 }
750 };
751
752 updatePathByPtr( "schematic.page_layout_descr_file" );
753 updatePathByPtr( "schematic.plot_directory" );
754 updatePathByPtr( "schematic.ngspice.workbook_filename" );
755 updatePathByPtr( "pcbnew.page_layout_descr_file" );
756
757 for( auto& sheetInfo : m_topLevelSheets )
758 updatePath( sheetInfo.filename );
759
760 // If we're actually going ahead and doing the save, the flag that keeps code from doing the save
761 // should be cleared at this point
762 m_wasMigrated = false;
763
764 // While performing Save As, we have already checked that we can write to the directory
765 // so don't carry the previous flag
766 SetReadOnly( false );
767 return JSON_SETTINGS::SaveToFile( aDirectory, true );
768}
769
770
772{
774}
775
776
781
782
783void to_json( nlohmann::json& aJson, const FILE_INFO_PAIR& aPair )
784{
785 aJson = nlohmann::json::array( { aPair.first.AsString().ToUTF8(), aPair.second.ToUTF8() } );
786}
787
788
789void from_json( const nlohmann::json& aJson, FILE_INFO_PAIR& aPair )
790{
791 wxCHECK( aJson.is_array() && aJson.size() == 2, /* void */ );
792 aPair.first = KIID( wxString( aJson[0].get<std::string>().c_str(), wxConvUTF8 ) );
793 aPair.second = wxString( aJson[1].get<std::string>().c_str(), wxConvUTF8 );
794}
795
796
797void to_json( nlohmann::json& aJson, const TOP_LEVEL_SHEET_INFO& aInfo )
798{
799 aJson = nlohmann::json::object();
800 aJson["uuid"] = aInfo.uuid.AsString().ToUTF8();
801 aJson["name"] = aInfo.name.ToUTF8();
802 aJson["filename"] = aInfo.filename.ToUTF8();
803}
804
805
806void from_json( const nlohmann::json& aJson, TOP_LEVEL_SHEET_INFO& aInfo )
807{
808 wxCHECK( aJson.is_object(), /* void */ );
809
810 if( aJson.contains( "uuid" ) )
811 aInfo.uuid = KIID( wxString( aJson["uuid"].get<std::string>().c_str(), wxConvUTF8 ) );
812
813 if( aJson.contains( "name" ) )
814 aInfo.name = wxString( aJson["name"].get<std::string>().c_str(), wxConvUTF8 );
815
816 if( aJson.contains( "filename" ) )
817 aInfo.filename = wxString( aJson["filename"].get<std::string>().c_str(), wxConvUTF8 );
818}
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...
virtual bool LoadFromFile(const wxString &aDirectory="")
Loads the backing file from disk and then calls Load()
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
wxString AsString() const
Definition kiid.cpp:246
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::vector< TOP_LEVEL_SHEET_INFO > m_topLevelSheets
A list of top-level schematic sheets in 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.
bool LoadFromFile(const wxString &aDirectory="") override
Loads the backing file from disk and then calls Load()
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.
std::shared_ptr< TUNING_PROFILES > m_tuningProfileParameters
Tuning profile parameters for 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:66
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
SETTINGS_LOC
#define traceSettings
KIID niluuid(0)
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...
Information about a top-level schematic sheet.
KIID uuid
Unique identifier for the sheet.
wxString name
Display name for the sheet.
wxString filename
Relative path to the sheet file.
Definition of file extensions used in Kicad.