KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <jon@craftyjon.com>
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>
27#include <settings/parameters.h>
29#include <wx/config.h>
30#include <wx/log.h>
31
32
35
36
37PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) :
39 m_ErcSettings( nullptr ), m_SchematicSettings( nullptr ), m_BoardSettings(),
40 m_project( nullptr ), m_wasMigrated( false )
41{
42 // Keep old files around
44
45 m_params.emplace_back( new PARAM_LIST<FILE_INFO_PAIR>( "sheets", &m_sheets, {} ) );
46
47 m_params.emplace_back( new PARAM_LIST<FILE_INFO_PAIR>( "boards", &m_boards, {} ) );
48
49 m_params.emplace_back( new PARAM_WXSTRING_MAP( "text_variables",
50 &m_TextVars, {}, false, true /* array behavior, even though stored as a map */ ) );
51
52 m_params.emplace_back( new PARAM_LIST<wxString>( "libraries.pinned_symbol_libs",
53 &m_PinnedSymbolLibs, {} ) );
54
55 m_params.emplace_back( new PARAM_LIST<wxString>( "libraries.pinned_footprint_libs",
56 &m_PinnedFootprintLibs, {} ) );
57
58 m_params.emplace_back( new PARAM_PATH_LIST( "cvpcb.equivalence_files",
59 &m_EquivalenceFiles, {} ) );
60
61 m_params.emplace_back( new PARAM_PATH( "pcbnew.page_layout_descr_file",
63
64 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.netlist",
66
67 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.step",
69
70 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.idf",
72
73 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.vrml",
75
76 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.specctra_dsn",
78
79 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.gencad",
81
82 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.pos_files",
84
85 m_params.emplace_back( new PARAM_PATH( "pcbnew.last_paths.svg",
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_NetSettings = std::make_shared<NET_SETTINGS>( this, "net_settings" );
116
118 std::make_shared<COMPONENT_CLASS_SETTINGS>( this, "component_class_settings" );
119
120 m_params.emplace_back( new PARAM_LAYER_PRESET( "board.layer_presets", &m_LayerPresets ) );
121
122 m_params.emplace_back( new PARAM_VIEWPORT( "board.viewports", &m_Viewports ) );
123
124 m_params.emplace_back( new PARAM_VIEWPORT3D( "board.3dviewports", &m_Viewports3D ) );
125
126 m_params.emplace_back( new PARAM_LAYER_PAIRS( "board.layer_pairs", m_LayerPairInfos ) );
127
128 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.internal_id",
129 &m_IP2581Bom.id, wxEmptyString ) );
130
131 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mpn",
132 &m_IP2581Bom.MPN, wxEmptyString ) );
133
134 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mfg",
135 &m_IP2581Bom.mfg, wxEmptyString ) );
136
137 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.distpn",
138 &m_IP2581Bom.distPN, wxEmptyString ) );
139
140 m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.dist",
141 &m_IP2581Bom.dist, wxEmptyString ) );
142
143 registerMigration( 1, 2, std::bind( &PROJECT_FILE::migrateSchema1To2, this ) );
144 registerMigration( 2, 3, std::bind( &PROJECT_FILE::migrateSchema2To3, this ) );
145}
146
147
149{
150 auto p( "/board/layer_presets"_json_pointer );
151
152 if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
153 return true;
154
155 nlohmann::json& presets = m_internals->at( p );
156
157 for( nlohmann::json& entry : presets )
159
160 m_wasMigrated = true;
161
162 return true;
163}
164
165
167{
168 auto p( "/board/layer_presets"_json_pointer );
169
170 if( !m_internals->contains( p ) || !m_internals->at( p ).is_array() )
171 return true;
172
173 nlohmann::json& presets = m_internals->at( p );
174
175 for( nlohmann::json& entry : presets )
177
178 m_wasMigrated = true;
179
180 return true;
181}
182
183
184bool PROJECT_FILE::MigrateFromLegacy( wxConfigBase* aCfg )
185{
186 bool ret = true;
187 wxString str;
188 long index = 0;
189
190 std::set<wxString> group_blacklist;
191
192 // Legacy files don't store board info; they assume board matches project name
193 // We will leave m_boards empty here so it can be populated with other code
194
195 // First handle migration of data that will be stored locally in this object
196
197 auto loadPinnedLibs =
198 [&]( const std::string& aDest )
199 {
200 int libIndex = 1;
201 wxString libKey = wxT( "PinnedItems" );
202 libKey << libIndex;
203
204 nlohmann::json libs = nlohmann::json::array();
205
206 while( aCfg->Read( libKey, &str ) )
207 {
208 libs.push_back( str );
209
210 aCfg->DeleteEntry( libKey, true );
211
212 libKey = wxT( "PinnedItems" );
213 libKey << ++libIndex;
214 }
215
216 Set( aDest, libs );
217 };
218
219 aCfg->SetPath( wxT( "/LibeditFrame" ) );
220 loadPinnedLibs( "libraries.pinned_symbol_libs" );
221
222 aCfg->SetPath( wxT( "/ModEditFrame" ) );
223 loadPinnedLibs( "libraries.pinned_footprint_libs" );
224
225 aCfg->SetPath( wxT( "/cvpcb/equfiles" ) );
226
227 {
228 int eqIdx = 1;
229 wxString eqKey = wxT( "EquName" );
230 eqKey << eqIdx;
231
232 nlohmann::json eqs = nlohmann::json::array();
233
234 while( aCfg->Read( eqKey, &str ) )
235 {
236 eqs.push_back( str );
237
238 eqKey = wxT( "EquName" );
239 eqKey << ++eqIdx;
240 }
241
242 Set( "cvpcb.equivalence_files", eqs );
243 }
244
245 // All CvPcb params that we want to keep have been migrated above
246 group_blacklist.insert( wxT( "/cvpcb" ) );
247
248 aCfg->SetPath( wxT( "/eeschema" ) );
249 fromLegacyString( aCfg, "LibDir", "schematic.legacy_lib_dir" );
250
251 aCfg->SetPath( wxT( "/eeschema/libraries" ) );
252
253 {
254 int libIdx = 1;
255 wxString libKey = wxT( "LibName" );
256 libKey << libIdx;
257
258 nlohmann::json libs = nlohmann::json::array();
259
260 while( aCfg->Read( libKey, &str ) )
261 {
262 libs.push_back( str );
263
264 libKey = wxT( "LibName" );
265 libKey << ++libIdx;
266 }
267
268 Set( "schematic.legacy_lib_list", libs );
269 }
270
271 group_blacklist.insert( wxT( "/eeschema" ) );
272
273 aCfg->SetPath( wxT( "/text_variables" ) );
274
275 {
276 int txtIdx = 1;
277 wxString txtKey;
278 txtKey << txtIdx;
279
280 nlohmann::json vars = nlohmann::json();
281
282 while( aCfg->Read( txtKey, &str ) )
283 {
284 wxArrayString tokens = wxSplit( str, ':' );
285
286 if( tokens.size() == 2 )
287 vars[ tokens[0].ToStdString() ] = tokens[1];
288
289 txtKey.clear();
290 txtKey << ++txtIdx;
291 }
292
293 Set( "text_variables", vars );
294 }
295
296 group_blacklist.insert( wxT( "/text_variables" ) );
297
298 aCfg->SetPath( wxT( "/schematic_editor" ) );
299
300 fromLegacyString( aCfg, "PageLayoutDescrFile", "schematic.page_layout_descr_file" );
301 fromLegacyString( aCfg, "PlotDirectoryName", "schematic.plot_directory" );
302 fromLegacyString( aCfg, "NetFmtName", "schematic.net_format_name" );
303 fromLegacy<bool>( aCfg, "SpiceAjustPassiveValues", "schematic.spice_adjust_passive_values" );
304 fromLegacy<int>( aCfg, "SubpartIdSeparator", "schematic.subpart_id_separator" );
305 fromLegacy<int>( aCfg, "SubpartFirstId", "schematic.subpart_first_id" );
306
307 fromLegacy<int>( aCfg, "LineThickness", "schematic.drawing.default_line_thickness" );
308 fromLegacy<int>( aCfg, "WireThickness", "schematic.drawing.default_wire_thickness" );
309 fromLegacy<int>( aCfg, "BusThickness", "schematic.drawing.default_bus_thickness" );
310 fromLegacy<int>( aCfg, "LabSize", "schematic.drawing.default_text_size" );
311
312 if( !fromLegacy<int>( aCfg, "PinSymbolSize", "schematic.drawing.pin_symbol_size" ) )
313 {
314 // Use the default symbol size algorithm of Eeschema V5 (based on pin name/number size)
315 Set( "schematic.drawing.pin_symbol_size", 0 );
316 }
317
318 fromLegacy<int>( aCfg, "JunctionSize", "schematic.drawing.default_junction_size" );
319
320 fromLegacyString( aCfg, "FieldNameTemplates", "schematic.drawing.field_names" );
321
322 if( !fromLegacy<double>( aCfg, "TextOffsetRatio", "schematic.drawing.text_offset_ratio" ) )
323 {
324 // Use the spacing of Eeschema V5
325 Set( "schematic.drawing.text_offset_ratio", 0.08 );
326 Set( "schematic.drawing.label_size_ratio", 0.25 );
327 }
328
329 // All schematic_editor keys we keep are migrated above
330 group_blacklist.insert( wxT( "/schematic_editor" ) );
331
332 aCfg->SetPath( wxT( "/pcbnew" ) );
333
334 fromLegacyString( aCfg, "PageLayoutDescrFile", "pcbnew.page_layout_descr_file" );
335 fromLegacyString( aCfg, "LastNetListRead", "pcbnew.last_paths.netlist" );
336 fromLegacyString( aCfg, "LastSTEPExportPath", "pcbnew.last_paths.step" );
337 fromLegacyString( aCfg, "LastIDFExportPath", "pcbnew.last_paths.idf" );
338 fromLegacyString( aCfg, "LastVRMLExportPath", "pcbnew.last_paths.vmrl" );
339 fromLegacyString( aCfg, "LastSpecctraDSNExportPath", "pcbnew.last_paths.specctra_dsn" );
340 fromLegacyString( aCfg, "LastGenCADExportPath", "pcbnew.last_paths.gencad" );
341
342 std::string bp = "board.design_settings.";
343
344 {
345 int idx = 1;
346 wxString key = wxT( "DRCExclusion" );
347 key << idx;
348
349 nlohmann::json exclusions = nlohmann::json::array();
350
351 while( aCfg->Read( key, &str ) )
352 {
353 exclusions.push_back( str );
354
355 key = wxT( "DRCExclusion" );
356 key << ++idx;
357 }
358
359 Set( bp + "drc_exclusions", exclusions );
360 }
361
362 fromLegacy<bool>( aCfg, "AllowMicroVias", bp + "rules.allow_microvias" );
363 fromLegacy<bool>( aCfg, "AllowBlindVias", bp + "rules.allow_blind_buried_vias" );
364 fromLegacy<double>( aCfg, "MinClearance", bp + "rules.min_clearance" );
365 fromLegacy<double>( aCfg, "MinTrackWidth", bp + "rules.min_track_width" );
366 fromLegacy<double>( aCfg, "MinViaAnnulus", bp + "rules.min_via_annulus" );
367 fromLegacy<double>( aCfg, "MinViaDiameter", bp + "rules.min_via_diameter" );
368
369 if( !fromLegacy<double>( aCfg, "MinThroughDrill", bp + "rules.min_through_hole_diameter" ) )
370 fromLegacy<double>( aCfg, "MinViaDrill", bp + "rules.min_through_hole_diameter" );
371
372 fromLegacy<double>( aCfg, "MinMicroViaDiameter", bp + "rules.min_microvia_diameter" );
373 fromLegacy<double>( aCfg, "MinMicroViaDrill", bp + "rules.min_microvia_drill" );
374 fromLegacy<double>( aCfg, "MinHoleToHole", bp + "rules.min_hole_to_hole" );
375 fromLegacy<double>( aCfg, "CopperEdgeClearance", bp + "rules.min_copper_edge_clearance" );
376 fromLegacy<double>( aCfg, "SolderMaskClearance", bp + "rules.solder_mask_clearance" );
377 fromLegacy<double>( aCfg, "SolderMaskMinWidth", bp + "rules.solder_mask_min_width" );
378 fromLegacy<double>( aCfg, "SolderPasteClearance", bp + "rules.solder_paste_clearance" );
379 fromLegacy<double>( aCfg, "SolderPasteRatio", bp + "rules.solder_paste_margin_ratio" );
380
381 if( !fromLegacy<double>( aCfg, "SilkLineWidth", bp + "defaults.silk_line_width" ) )
382 fromLegacy<double>( aCfg, "ModuleOutlineThickness", bp + "defaults.silk_line_width" );
383
384 if( !fromLegacy<double>( aCfg, "SilkTextSizeV", bp + "defaults.silk_text_size_v" ) )
385 fromLegacy<double>( aCfg, "ModuleTextSizeV", bp + "defaults.silk_text_size_v" );
386
387 if( !fromLegacy<double>( aCfg, "SilkTextSizeH", bp + "defaults.silk_text_size_h" ) )
388 fromLegacy<double>( aCfg, "ModuleTextSizeH", bp + "defaults.silk_text_size_h" );
389
390 if( !fromLegacy<double>( aCfg, "SilkTextSizeThickness", bp + "defaults.silk_text_thickness" ) )
391 fromLegacy<double>( aCfg, "ModuleTextSizeThickness", bp + "defaults.silk_text_thickness" );
392
393 fromLegacy<bool>( aCfg, "SilkTextItalic", bp + "defaults.silk_text_italic" );
394 fromLegacy<bool>( aCfg, "SilkTextUpright", bp + "defaults.silk_text_upright" );
395
396 if( !fromLegacy<double>( aCfg, "CopperLineWidth", bp + "defaults.copper_line_width" ) )
397 fromLegacy<double>( aCfg, "DrawSegmentWidth", bp + "defaults.copper_line_width" );
398
399 if( !fromLegacy<double>( aCfg, "CopperTextSizeV", bp + "defaults.copper_text_size_v" ) )
400 fromLegacy<double>( aCfg, "PcbTextSizeV", bp + "defaults.copper_text_size_v" );
401
402 if( !fromLegacy<double>( aCfg, "CopperTextSizeH", bp + "defaults.copper_text_size_h" ) )
403 fromLegacy<double>( aCfg, "PcbTextSizeH", bp + "defaults.copper_text_size_h" );
404
405 if( !fromLegacy<double>( aCfg, "CopperTextThickness", bp + "defaults.copper_text_thickness" ) )
406 fromLegacy<double>( aCfg, "PcbTextThickness", bp + "defaults.copper_text_thickness" );
407
408 fromLegacy<bool>( aCfg, "CopperTextItalic", bp + "defaults.copper_text_italic" );
409 fromLegacy<bool>( aCfg, "CopperTextUpright", bp + "defaults.copper_text_upright" );
410
411 if( !fromLegacy<double>( aCfg, "EdgeCutLineWidth", bp + "defaults.board_outline_line_width" ) )
412 fromLegacy<double>( aCfg, "BoardOutlineThickness",
413 bp + "defaults.board_outline_line_width" );
414
415 fromLegacy<double>( aCfg, "CourtyardLineWidth", bp + "defaults.courtyard_line_width" );
416
417 fromLegacy<double>( aCfg, "FabLineWidth", bp + "defaults.fab_line_width" );
418 fromLegacy<double>( aCfg, "FabTextSizeV", bp + "defaults.fab_text_size_v" );
419 fromLegacy<double>( aCfg, "FabTextSizeH", bp + "defaults.fab_text_size_h" );
420 fromLegacy<double>( aCfg, "FabTextSizeThickness", bp + "defaults.fab_text_thickness" );
421 fromLegacy<bool>( aCfg, "FabTextItalic", bp + "defaults.fab_text_italic" );
422 fromLegacy<bool>( aCfg, "FabTextUpright", bp + "defaults.fab_text_upright" );
423
424 if( !fromLegacy<double>( aCfg, "OthersLineWidth", bp + "defaults.other_line_width" ) )
425 fromLegacy<double>( aCfg, "ModuleOutlineThickness", bp + "defaults.other_line_width" );
426
427 fromLegacy<double>( aCfg, "OthersTextSizeV", bp + "defaults.other_text_size_v" );
428 fromLegacy<double>( aCfg, "OthersTextSizeH", bp + "defaults.other_text_size_h" );
429 fromLegacy<double>( aCfg, "OthersTextSizeThickness", bp + "defaults.other_text_thickness" );
430 fromLegacy<bool>( aCfg, "OthersTextItalic", bp + "defaults.other_text_italic" );
431 fromLegacy<bool>( aCfg, "OthersTextUpright", bp + "defaults.other_text_upright" );
432
433 fromLegacy<int>( aCfg, "DimensionUnits", bp + "defaults.dimension_units" );
434 fromLegacy<int>( aCfg, "DimensionPrecision", bp + "defaults.dimension_precision" );
435
436 std::string sev = bp + "rule_severities";
437
438 fromLegacy<bool>( aCfg, "RequireCourtyardDefinitions", sev + "legacy_no_courtyard_defined" );
439
440 fromLegacy<bool>( aCfg, "ProhibitOverlappingCourtyards", sev + "legacy_courtyards_overlap" );
441
442 {
443 int idx = 1;
444 wxString keyBase = "TrackWidth";
445 wxString key = keyBase;
446 double val;
447
448 nlohmann::json widths = nlohmann::json::array();
449
450 key << idx;
451
452 while( aCfg->Read( key, &val ) )
453 {
454 widths.push_back( val );
455 key = keyBase;
456 key << ++idx;
457 }
458
459 Set( bp + "track_widths", widths );
460 }
461
462 {
463 int idx = 1;
464 wxString keyBase = "ViaDiameter";
465 wxString key = keyBase;
466 double diameter;
467 double drill = 1.0;
468
469 nlohmann::json vias = nlohmann::json::array();
470
471 key << idx;
472
473 while( aCfg->Read( key, &diameter ) )
474 {
475 key = "ViaDrill";
476 aCfg->Read( key << idx, &drill );
477
478 nlohmann::json via = { { "diameter", diameter }, { "drill", drill } };
479 vias.push_back( via );
480
481 key = keyBase;
482 key << ++idx;
483 }
484
485 Set( bp + "via_dimensions", vias );
486 }
487
488 {
489 int idx = 1;
490 wxString keyBase = "dPairWidth";
491 wxString key = keyBase;
492 double width;
493 double gap = 1.0;
494 double via_gap = 1.0;
495
496 nlohmann::json pairs = nlohmann::json::array();
497
498 key << idx;
499
500 while( aCfg->Read( key, &width ) )
501 {
502 key = "dPairGap";
503 aCfg->Read( key << idx, &gap );
504
505 key = "dPairViaGap";
506 aCfg->Read( key << idx, &via_gap );
507
508 nlohmann::json pair = { { "width", width }, { "gap", gap }, { "via_gap", via_gap } };
509 pairs.push_back( pair );
510
511 key = keyBase;
512 key << ++idx;
513 }
514
515 Set( bp + "diff_pair_dimensions", pairs );
516 }
517
518 group_blacklist.insert( wxT( "/pcbnew" ) );
519
520 // General group is unused these days, we can throw it away
521 group_blacklist.insert( wxT( "/general" ) );
522
523 // Next load sheet names and put all other legacy data in the legacy dict
524 aCfg->SetPath( wxT( "/" ) );
525
526 auto loadSheetNames =
527 [&]() -> bool
528 {
529 int sheet = 1;
530 wxString entry;
531 nlohmann::json arr = nlohmann::json::array();
532
533 wxLogTrace( traceSettings, wxT( "Migrating sheet names" ) );
534
535 aCfg->SetPath( wxT( "/sheetnames" ) );
536
537 while( aCfg->Read( wxString::Format( "%d", sheet++ ), &entry ) )
538 {
539 wxArrayString tokens = wxSplit( entry, ':' );
540
541 if( tokens.size() == 2 )
542 {
543 wxLogTrace( traceSettings, wxT( "%d: %s = %s" ), sheet, tokens[0],
544 tokens[1] );
545 arr.push_back( nlohmann::json::array( { tokens[0], tokens[1] } ) );
546 }
547 }
548
549 Set( "sheets", arr );
550
551 aCfg->SetPath( "/" );
552
553 // TODO: any reason we want to fail on this?
554 return true;
555 };
556
557 std::vector<wxString> groups;
558
559 groups.emplace_back( wxEmptyString );
560
561 auto loadLegacyPairs =
562 [&]( const std::string& aGroup ) -> bool
563 {
564 wxLogTrace( traceSettings, wxT( "Migrating group %s" ), aGroup );
565 bool success = true;
566 wxString keyStr;
567 wxString val;
568
569 index = 0;
570
571 while( aCfg->GetNextEntry( keyStr, index ) )
572 {
573 if( !aCfg->Read( keyStr, &val ) )
574 continue;
575
576 std::string key( keyStr.ToUTF8() );
577
578 wxLogTrace( traceSettings, wxT( " %s = %s" ), key, val );
579
580 try
581 {
582 Set( "legacy." + aGroup + "." + key, val );
583 }
584 catch( ... )
585 {
586 success = false;
587 }
588 }
589
590 return success;
591 };
592
593 for( size_t i = 0; i < groups.size(); i++ )
594 {
595 aCfg->SetPath( groups[i] );
596
597 if( groups[i] == wxT( "/sheetnames" ) )
598 {
599 ret |= loadSheetNames();
600 continue;
601 }
602
603 aCfg->DeleteEntry( wxT( "last_client" ), true );
604 aCfg->DeleteEntry( wxT( "update" ), true );
605 aCfg->DeleteEntry( wxT( "version" ), true );
606
607 ret &= loadLegacyPairs( groups[i].ToStdString() );
608
609 index = 0;
610
611 while( aCfg->GetNextGroup( str, index ) )
612 {
613 wxString group = groups[i] + "/" + str;
614
615 if( !group_blacklist.count( group ) )
616 groups.emplace_back( group );
617 }
618
619 aCfg->SetPath( "/" );
620 }
621
622 return ret;
623}
624
625
626bool PROJECT_FILE::SaveToFile( const wxString& aDirectory, bool aForce )
627{
628 wxASSERT( m_project );
629
630 Set( "meta.filename", m_project->GetProjectName() + "." + FILEEXT::ProjectFileExtension );
631
632 // Even if parameters were not modified, we should resave after migration
633 bool force = aForce || m_wasMigrated;
634
635 // If we're actually going ahead and doing the save, the flag that keeps code from doing the
636 // save should be cleared at this.
637 m_wasMigrated = false;
638
639 return JSON_SETTINGS::SaveToFile( aDirectory, force );
640}
641
642
643bool PROJECT_FILE::SaveAs( const wxString& aDirectory, const wxString& aFile )
644{
645 wxFileName oldFilename( GetFilename() );
646 wxString oldProjectName = oldFilename.GetName();
647 wxString oldProjectPath = oldFilename.GetPath();
648
649 Set( "meta.filename", aFile + "." + FILEEXT::ProjectFileExtension );
650 SetFilename( aFile );
651
652 auto updatePath =
653 [&]( wxString& aPath )
654 {
655 if( aPath.StartsWith( oldProjectName + wxS( "." ) ) )
656 aPath.Replace( oldProjectName, aFile, false );
657 else if( aPath.StartsWith( oldProjectPath + wxS( "/" ) ) )
658 aPath.Replace( oldProjectPath, aDirectory, false );
659 };
660
661 updatePath( m_BoardDrawingSheetFile );
662
663 for( int ii = LAST_PATH_FIRST; ii < (int) LAST_PATH_SIZE; ++ii )
664 updatePath( m_PcbLastPath[ ii ] );
665
666 auto updatePathByPtr =
667 [&]( const std::string& aPtr )
668 {
669 if( std::optional<wxString> path = Get<wxString>( aPtr ) )
670 {
671 updatePath( path.value() );
672 Set( aPtr, path.value() );
673 }
674 };
675
676 updatePathByPtr( "schematic.page_layout_descr_file" );
677 updatePathByPtr( "schematic.plot_directory" );
678 updatePathByPtr( "schematic.ngspice.workbook_filename" );
679 updatePathByPtr( "pcbnew.page_layout_descr_file" );
680
681 // If we're actually going ahead and doing the save, the flag that keeps code from doing the save
682 // should be cleared at this point
683 m_wasMigrated = false;
684
685 // While performing Save As, we have already checked that we can write to the directory
686 // so don't carry the previous flag
687 SetReadOnly( false );
688 return JSON_SETTINGS::SaveToFile( aDirectory, true );
689}
690
691
693{
695}
696
697
699{
701}
702
703
704void to_json( nlohmann::json& aJson, const FILE_INFO_PAIR& aPair )
705{
706 aJson = nlohmann::json::array( { aPair.first.AsString().ToUTF8(), aPair.second.ToUTF8() } );
707}
708
709
710void from_json( const nlohmann::json& aJson, FILE_INFO_PAIR& aPair )
711{
712 wxCHECK( aJson.is_array() && aJson.size() == 2, /* void */ );
713 aPair.first = KIID( wxString( aJson[0].get<std::string>().c_str(), wxConvUTF8 ) );
714 aPair.second = wxString( aJson[1].get<std::string>().c_str(), wxConvUTF8 );
715}
bool fromLegacyString(wxConfigBase *aConfig, const std::string &aKey, const std::string &aDest)
Translates a legacy wxConfig string 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)
Definition: json_settings.h:93
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.
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)
Definition: json_settings.h:85
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: json_settings.h:81
Definition: kiid.h:49
Like a normal param, but with custom getter and setter functions.
Definition: parameters.h:295
static void MigrateToV9Layers(nlohmann::json &aJson)
static void MigrateToNamedRenderLayers(nlohmann::json &aJson)
Represents a list of strings holding directory paths.
Definition: parameters.h:667
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:814
std::map< wxString, wxString > m_TextVars
Definition: project_file.h:141
wxString getFileExt() const override
std::vector< LAYER_PAIR_INFO > m_LayerPairInfos
List of stored 3D viewports (view matrixes)
Definition: project_file.h:199
wxString m_LegacyLibDir
Definition: project_file.h:154
bool migrateSchema1To2()
IPC-2581 BOM settings.
wxString m_BoardDrawingSheetFile
PcbNew params.
Definition: project_file.h:170
std::shared_ptr< NET_SETTINGS > m_NetSettings
Net settings for this project (owned here)
Definition: project_file.h:189
struct IP2581_BOM m_IP2581Bom
Layer pair list for the board.
Definition: project_file.h:201
wxString m_PcbLastPath[LAST_PATH_SIZE]
MRU path storage.
Definition: project_file.h:173
PROJECT * m_project
A link to the owning PROJECT.
Definition: project_file.h:223
std::vector< VIEWPORT > m_Viewports
List of stored layer presets.
Definition: project_file.h:197
bool SaveAs(const wxString &aDirectory, const wxString &aFile)
std::vector< wxString > m_EquivalenceFiles
CvPcb params.
Definition: project_file.h:163
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.
Definition: project_file.h:136
std::vector< FILE_INFO_PAIR > m_sheets
An list of schematic sheets in this project.
Definition: project_file.h:217
virtual bool MigrateFromLegacy(wxConfigBase *aCfg) override
Migrates from wxConfig to JSON-based configuration.
bool m_wasMigrated
Definition: project_file.h:225
std::vector< LAYER_PRESET > m_LayerPresets
Definition: project_file.h:196
std::vector< FILE_INFO_PAIR > m_boards
A list of board files in this project.
Definition: project_file.h:220
wxArrayString m_LegacyLibNames
Definition: project_file.h:156
std::vector< wxString > m_PinnedSymbolLibs
Below are project-level settings that have not been moved to a dedicated file.
Definition: project_file.h:133
std::vector< VIEWPORT3D > m_Viewports3D
List of stored viewports (pos + zoom)
Definition: project_file.h:198
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)
Definition: project_file.h:194
Container for project specific data.
Definition: project.h:64
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:158
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
SETTINGS_LOC
Definition: json_settings.h:54
#define traceSettings
Definition: json_settings.h:52
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
Definition: project_file.h:59
@ LAST_PATH_SPECCTRADSN
Definition: project_file.h:55
@ LAST_PATH_GENCAD
Definition: project_file.h:56
@ LAST_PATH_SIZE
Definition: project_file.h:63
@ LAST_PATH_FIRST
Definition: project_file.h:50
@ LAST_PATH_POS_FILES
Definition: project_file.h:57
@ LAST_PATH_IDF
Definition: project_file.h:53
@ LAST_PATH_VRML
Definition: project_file.h:54
@ LAST_PATH_NETLIST
Definition: project_file.h:51
@ LAST_PATH_STEP
Definition: project_file.h:52
@ LAST_PATH_SVG
Definition: project_file.h:58
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: project_file.h:43
wxString mfg
Manufacturer name column.
wxString MPN
Manufacturer part number column.
wxString id
Internal ID column.
wxString dist
Distributor name column.
wxString distPN
Distributor part number column.
Definition of file extensions used in Kicad.