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}
int index
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:65
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.
std::string path
Definition of file extensions used in Kicad.