KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eeschema_jobs_handler.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) 2022 Mark Roszko <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
22#include <common.h>
23#include <pgm_base.h>
24#include <cli/exit_codes.h>
25#include <sch_plotter.h>
32#include <jobs/job_sch_erc.h>
36#include <schematic.h>
37#include <schematic_settings.h>
38#include <sch_screen.h>
39#include <wx/dir.h>
40#include <wx/file.h>
41#include <memory>
42#include <connection_graph.h>
43#include "eeschema_helpers.h"
44#include <filename_resolver.h>
45#include <kiway.h>
46#include <sch_painter.h>
47#include <locale_io.h>
48#include <erc/erc.h>
49#include <erc/erc_report.h>
53#include <paths.h>
54#include <reporter.h>
55#include <string_utils.h>
56
58
59#include <sch_file_versions.h>
60#include <sch_io/sch_io.h>
62
63#include <netlist.h>
73
74#include <fields_data_model.h>
75
80#include <confirm.h>
81#include <project_sch.h>
82
84
85
87 JOB_DISPATCHER( aKiway ),
88 m_cliSchematic( nullptr )
89{
90 Register( "bom",
91 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportBom, this, std::placeholders::_1 ),
92 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
93 {
94 JOB_EXPORT_SCH_BOM* bomJob = dynamic_cast<JOB_EXPORT_SCH_BOM*>( job );
95
96 SCH_EDIT_FRAME* editFrame =
97 static_cast<SCH_EDIT_FRAME*>( aKiway->Player( FRAME_SCH, false ) );
98
99 wxCHECK( bomJob && editFrame, false );
100
101 DIALOG_SYMBOL_FIELDS_TABLE dlg( editFrame, bomJob );
102 return dlg.ShowModal() == wxID_OK;
103 } );
104 Register( "pythonbom",
105 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportPythonBom, this, std::placeholders::_1 ),
106 []( JOB* job, wxWindow* aParent ) -> bool
107 {
108 return true;
109 } );
110 Register( "netlist",
111 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportNetlist, this, std::placeholders::_1 ),
112 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
113 {
114 JOB_EXPORT_SCH_NETLIST* netJob = dynamic_cast<JOB_EXPORT_SCH_NETLIST*>( job );
115
116 SCH_EDIT_FRAME* editFrame =
117 static_cast<SCH_EDIT_FRAME*>( aKiway->Player( FRAME_SCH, false ) );
118
119 wxCHECK( netJob && editFrame, false );
120
121 DIALOG_EXPORT_NETLIST dlg( editFrame, aParent, netJob );
122 return dlg.ShowModal() == wxID_OK;
123 } );
124 Register( "plot",
125 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportPlot, this, std::placeholders::_1 ),
126 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
127 {
128 JOB_EXPORT_SCH_PLOT* plotJob = dynamic_cast<JOB_EXPORT_SCH_PLOT*>( job );
129
130 SCH_EDIT_FRAME* editFrame =
131 static_cast<SCH_EDIT_FRAME*>( aKiway->Player( FRAME_SCH, false ) );
132
133 wxCHECK( plotJob && editFrame, false );
134
135 if( plotJob->m_plotFormat == SCH_PLOT_FORMAT::HPGL )
136 {
137 DisplayErrorMessage( editFrame,
138 _( "Plotting to HPGL is no longer supported as of KiCad 10.0." ) );
139 return false;
140 }
141
142 DIALOG_PLOT_SCHEMATIC dlg( editFrame, aParent, plotJob );
143 return dlg.ShowModal() == wxID_OK;
144 } );
145 Register( "symupgrade",
146 std::bind( &EESCHEMA_JOBS_HANDLER::JobSymUpgrade, this, std::placeholders::_1 ),
147 []( JOB* job, wxWindow* aParent ) -> bool
148 {
149 return true;
150 } );
151 Register( "symsvg",
152 std::bind( &EESCHEMA_JOBS_HANDLER::JobSymExportSvg, this, std::placeholders::_1 ),
153 []( JOB* job, wxWindow* aParent ) -> bool
154 {
155 return true;
156 } );
157 Register( "erc", std::bind( &EESCHEMA_JOBS_HANDLER::JobSchErc, this, std::placeholders::_1 ),
158 []( JOB* job, wxWindow* aParent ) -> bool
159 {
160 JOB_SCH_ERC* ercJob = dynamic_cast<JOB_SCH_ERC*>( job );
161
162 wxCHECK( ercJob, false );
163
164 DIALOG_ERC_JOB_CONFIG dlg( aParent, ercJob );
165 return dlg.ShowModal() == wxID_OK;
166 } );
167 Register( "upgrade", std::bind( &EESCHEMA_JOBS_HANDLER::JobUpgrade, this, std::placeholders::_1 ),
168 []( JOB* job, wxWindow* aParent ) -> bool
169 {
170 return true;
171 } );
172}
173
174
180
181
183{
184 SCHEMATIC* sch = nullptr;
185
186 if( !Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpenNotDummy() )
187 {
189 wxString schPath = aPath;
190
191 if( schPath.IsEmpty() )
192 {
193 wxFileName path = project.GetProjectFullName();
195 path.MakeAbsolute();
196 schPath = path.GetFullPath();
197 }
198
199 if( !m_cliSchematic )
200 m_cliSchematic = EESCHEMA_HELPERS::LoadSchematic( schPath, true, false, &project );
201
202 sch = m_cliSchematic;
203 }
204 else if( Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
205 {
206 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_kiway->Player( FRAME_SCH, false ) );
207
208 if( editFrame )
209 sch = &editFrame->Schematic();
210 }
211 else if( !aPath.IsEmpty() )
212 {
213 sch = EESCHEMA_HELPERS::LoadSchematic( aPath, true, false );
214 }
215
216 if( !sch )
217 m_reporter->Report( _( "Failed to load schematic\n" ), RPT_SEVERITY_ERROR );
218
219 return sch;
220}
221
223 const wxString& aTheme, SCHEMATIC* aSch,
224 const wxString& aDrawingSheetOverride )
225{
226 COLOR_SETTINGS* cs = ::GetColorSettings( aTheme );
227 aRenderSettings->LoadColors( cs );
228 aRenderSettings->m_ShowHiddenPins = false;
229 aRenderSettings->m_ShowHiddenFields = false;
230 aRenderSettings->m_ShowPinAltIcons = false;
231
232 aRenderSettings->SetDefaultPenWidth( aSch->Settings().m_DefaultLineWidth );
233 aRenderSettings->m_LabelSizeRatio = aSch->Settings().m_LabelSizeRatio;
234 aRenderSettings->m_TextOffsetRatio = aSch->Settings().m_TextOffsetRatio;
235 aRenderSettings->m_PinSymbolSize = aSch->Settings().m_PinSymbolSize;
236
237 aRenderSettings->SetDashLengthRatio( aSch->Settings().m_DashedLineDashRatio );
238 aRenderSettings->SetGapLengthRatio( aSch->Settings().m_DashedLineGapRatio );
239
240 // Load the drawing sheet from the filename stored in BASE_SCREEN::m_DrawingSheetFileName.
241 // If empty, or not existing, the default drawing sheet is loaded.
242
243 auto loadSheet =
244 [&]( const wxString& path ) -> bool
245 {
246 wxString msg;
247 FILENAME_RESOLVER resolve;
248 resolve.SetProject( &aSch->Project() );
249 resolve.SetProgramBase( &Pgm() );
250
251 wxString absolutePath = resolve.ResolvePath( path, wxGetCwd(),
252 { aSch->GetEmbeddedFiles() } );
253
254 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( absolutePath, &msg ) )
255 {
256 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ), path )
257 + wxS( "\n" ) + msg + wxS( "\n" ),
259 return false;
260 }
261
262 return true;
263 };
264
265 // try to load the override first
266 if( !aDrawingSheetOverride.IsEmpty() && loadSheet( aDrawingSheetOverride ) )
267 return;
268
269 // no override or failed override continues here
270 loadSheet( aSch->Settings().m_SchDrawingSheetFileName );
271}
272
273
275{
276 JOB_EXPORT_SCH_PLOT* aPlotJob = dynamic_cast<JOB_EXPORT_SCH_PLOT*>( aJob );
277
278 wxCHECK( aPlotJob, CLI::EXIT_CODES::ERR_UNKNOWN );
279
280 if( aPlotJob->m_plotFormat == SCH_PLOT_FORMAT::HPGL )
281 {
282 m_reporter->Report( _( "Plotting to HPGL is no longer supported as of KiCad 10.0.\n" ),
285 }
286
287 SCHEMATIC* sch = getSchematic( aPlotJob->m_filename );
288
289 if( !sch )
291
292 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
293 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
294
295 // Determine the variant to use. The CLI path populates m_variantNames directly, while
296 // the jobset path serializes into m_variant. Use whichever is available.
297 wxString variantName;
298
299 if( !aPlotJob->m_variantNames.empty() )
300 variantName = aPlotJob->m_variantNames.front();
301 else if( !aPlotJob->m_variant.IsEmpty() )
302 variantName = aPlotJob->m_variant;
303
304 if( !variantName.IsEmpty() && variantName != wxS( "all" ) )
305 sch->SetCurrentVariant( variantName );
306
307 std::unique_ptr<SCH_RENDER_SETTINGS> renderSettings = std::make_unique<SCH_RENDER_SETTINGS>();
308 InitRenderSettings( renderSettings.get(), aPlotJob->m_theme, sch, aPlotJob->m_drawingSheet );
309
310 wxString font = aPlotJob->m_defaultFont;
311
312 if( font.IsEmpty() )
313 {
315 font = cfg ? cfg->m_Appearance.default_font : wxString( KICAD_FONT_NAME );
316 }
317
318 renderSettings->SetDefaultFont( font );
319 renderSettings->SetMinPenWidth( aPlotJob->m_minPenWidth );
320
321 // Clear cached bounding boxes for all text items so they're recomputed with the correct
322 // default font. This is necessary because text bounding boxes may have been cached during
323 // schematic loading before the render settings (and thus default font) were configured.
324 SCH_SCREENS screens( sch->Root() );
325
326 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
327 {
328 for( SCH_ITEM* item : screen->Items() )
329 item->ClearCaches();
330
331 for( const auto& [libItemName, libSymbol] : screen->GetLibSymbols() )
332 libSymbol->ClearCaches();
333 }
334
335 std::unique_ptr<SCH_PLOTTER> schPlotter = std::make_unique<SCH_PLOTTER>( sch );
336
338
339 switch( aPlotJob->m_plotFormat )
340 {
341 case SCH_PLOT_FORMAT::DXF: format = PLOT_FORMAT::DXF; break;
342 case SCH_PLOT_FORMAT::PDF: format = PLOT_FORMAT::PDF; break;
343 case SCH_PLOT_FORMAT::SVG: format = PLOT_FORMAT::SVG; break;
344 case SCH_PLOT_FORMAT::POST: format = PLOT_FORMAT::POST; break;
345 case SCH_PLOT_FORMAT::HPGL: /* no longer supported */ break;
346 }
347
348 int pageSizeSelect = PageFormatReq::PAGE_SIZE_AUTO;
349
350 switch( aPlotJob->m_pageSizeSelect )
351 {
352 case JOB_PAGE_SIZE::PAGE_SIZE_A: pageSizeSelect = PageFormatReq::PAGE_SIZE_A; break;
353 case JOB_PAGE_SIZE::PAGE_SIZE_A4: pageSizeSelect = PageFormatReq::PAGE_SIZE_A4; break;
355 }
356
357 if( !aPlotJob->GetOutputPathIsDirectory() && aPlotJob->GetConfiguredOutputPath().IsEmpty() )
358 {
359 wxFileName fn = sch->GetFileName();
360 fn.SetName( fn.GetName() );
361 fn.SetExt( GetDefaultPlotExtension( format ) );
362
363 aPlotJob->SetConfiguredOutputPath( fn.GetFullName() );
364 }
365
366 wxString outPath = aPlotJob->GetFullOutputPath( &sch->Project() );
367
368 if( !PATHS::EnsurePathExists( outPath, !aPlotJob->GetOutputPathIsDirectory() ) )
369 {
370 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
372 }
373
374 SCH_PLOT_OPTS plotOpts;
375 plotOpts.m_blackAndWhite = aPlotJob->m_blackAndWhite;
376 plotOpts.m_PDFPropertyPopups = aPlotJob->m_PDFPropertyPopups;
378 plotOpts.m_PDFMetadata = aPlotJob->m_PDFMetadata;
379
380 if( aPlotJob->GetOutputPathIsDirectory() )
381 {
382 plotOpts.m_outputDirectory = outPath;
383 plotOpts.m_outputFile = wxEmptyString;
384 }
385 else
386 {
387 plotOpts.m_outputDirectory = wxEmptyString;
388 plotOpts.m_outputFile = outPath;
389 }
390
391 plotOpts.m_pageSizeSelect = pageSizeSelect;
392 plotOpts.m_plotAll = aPlotJob->m_plotAll;
393 plotOpts.m_plotDrawingSheet = aPlotJob->m_plotDrawingSheet;
394 plotOpts.m_plotPages = aPlotJob->m_plotPages;
395 plotOpts.m_theme = aPlotJob->m_theme;
396 plotOpts.m_useBackgroundColor = aPlotJob->m_useBackgroundColor;
397 plotOpts.m_plotHopOver = aPlotJob->m_show_hop_over;
398
399 if( !variantName.IsEmpty() )
400 plotOpts.m_variant = variantName;
401
402 // Always export dxf in mm by kicad-cli (similar to Pcbnew)
404
405 schPlotter->Plot( format, plotOpts, renderSettings.get(), m_reporter );
406
407 if( m_reporter->HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
409
410 for( const wxString& outputPath : schPlotter->GetOutputFilePaths() )
411 aJob->AddOutput( outputPath );
412
413 return CLI::EXIT_CODES::OK;
414}
415
416
418{
419 JOB_EXPORT_SCH_NETLIST* aNetJob = dynamic_cast<JOB_EXPORT_SCH_NETLIST*>( aJob );
420
421 wxCHECK( aNetJob, CLI::EXIT_CODES::ERR_UNKNOWN );
422
423 SCHEMATIC* sch = getSchematic( aNetJob->m_filename );
424
425 if( !sch )
427
428 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
429 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
430
431 // Apply variant if specified
432 if( !aNetJob->m_variantNames.empty() )
433 {
434 // For netlist export, we use the first variant name from the set
435 wxString variantName = *aNetJob->m_variantNames.begin();
436
437 if( variantName != wxS( "all" ) )
438 sch->SetCurrentVariant( variantName );
439 }
440
441 // Annotation warning check
442 SCH_REFERENCE_LIST referenceList;
443 sch->Hierarchy().GetSymbols( referenceList, SYMBOL_FILTER_ALL );
444
445 if( referenceList.GetCount() > 0 )
446 {
447 if( referenceList.CheckAnnotation(
448 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
449 {
450 // We're only interested in the end result -- either errors or not
451 } )
452 > 0 )
453 {
454 m_reporter->Report( _( "Warning: schematic has annotation errors, please use the "
455 "schematic editor to fix them\n" ),
457 }
458 }
459
460 // Test duplicate sheet names:
461 ERC_TESTER erc( sch );
462
463 if( erc.TestDuplicateSheetNames( false ) > 0 )
464 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
465
466 std::unique_ptr<NETLIST_EXPORTER_BASE> helper;
467 unsigned netlistOption = 0;
468
469 wxString fileExt;
470
471 switch( aNetJob->format )
472 {
475 helper = std::make_unique<NETLIST_EXPORTER_KICAD>( sch );
476 break;
477
480 helper = std::make_unique<NETLIST_EXPORTER_ORCADPCB2>( sch );
481 break;
482
485 helper = std::make_unique<NETLIST_EXPORTER_CADSTAR>( sch );
486 break;
487
491 helper = std::make_unique<NETLIST_EXPORTER_SPICE>( sch );
492 break;
493
496 helper = std::make_unique<NETLIST_EXPORTER_SPICE_MODEL>( sch );
497 break;
498
500 fileExt = wxS( "xml" );
501 helper = std::make_unique<NETLIST_EXPORTER_XML>( sch );
502 break;
503
505 fileExt = wxS( "asc" );
506 helper = std::make_unique<NETLIST_EXPORTER_PADS>( sch );
507 break;
508
510 fileExt = wxS( "txt" );
511 helper = std::make_unique<NETLIST_EXPORTER_ALLEGRO>( sch );
512 break;
513
514 default:
515 m_reporter->Report( _( "Unknown netlist format.\n" ), RPT_SEVERITY_ERROR );
517 }
518
519 if( aNetJob->GetConfiguredOutputPath().IsEmpty() )
520 {
521 wxFileName fn = sch->GetFileName();
522 fn.SetName( fn.GetName() );
523 fn.SetExt( fileExt );
524
525 aNetJob->SetConfiguredOutputPath( fn.GetFullName() );
526 }
527
528 wxString outPath = aNetJob->GetFullOutputPath( &sch->Project() );
529
530 if( !PATHS::EnsurePathExists( outPath, true ) )
531 {
532 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
534 }
535
536 bool res = helper->WriteNetlist( outPath, netlistOption, *m_reporter );
537
538 if( !res )
540
541 aJob->AddOutput( outPath );
542
543 return CLI::EXIT_CODES::OK;
544}
545
546
548{
549 JOB_EXPORT_SCH_BOM* aBomJob = dynamic_cast<JOB_EXPORT_SCH_BOM*>( aJob );
550
551 wxCHECK( aBomJob, CLI::EXIT_CODES::ERR_UNKNOWN );
552
553 SCHEMATIC* sch = getSchematic( aBomJob->m_filename );
554
555 if( !sch )
557
558 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
559 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
560
561 wxString currentVariant;
562
563 if( !aBomJob->m_variantNames.empty() )
564 {
565 currentVariant = aBomJob->m_variantNames.front();
566
567 if( currentVariant != wxS( "all" ) )
568 sch->SetCurrentVariant( currentVariant );
569 }
570
571 // Annotation warning check
572 SCH_REFERENCE_LIST referenceList;
573 sch->Hierarchy().GetSymbols( referenceList, SYMBOL_FILTER_NON_POWER, false );
574
575 if( referenceList.GetCount() > 0 )
576 {
577 SCH_REFERENCE_LIST copy = referenceList;
578
579 // Check annotation splits references...
580 if( copy.CheckAnnotation(
581 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
582 {
583 // We're only interested in the end result -- either errors or not
584 } )
585 > 0 )
586 {
587 m_reporter->Report(
588 _( "Warning: schematic has annotation errors, please use the schematic "
589 "editor to fix them\n" ),
591 }
592 }
593
594 // Test duplicate sheet names:
595 ERC_TESTER erc( sch );
596
597 if( erc.TestDuplicateSheetNames( false ) > 0 )
598 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
599
600 // Build our data model
601 FIELDS_EDITOR_GRID_DATA_MODEL dataModel( referenceList, nullptr );
602
603 // Mandatory fields first
604 for( FIELD_T fieldId : MANDATORY_FIELDS )
605 {
606 dataModel.AddColumn( GetCanonicalFieldName( fieldId ),
607 GetDefaultFieldName( fieldId, DO_TRANSLATE ), false, currentVariant );
608 }
609
610 // Generated/virtual fields (e.g. ${QUANTITY}, ${ITEM_NUMBER}) present only in the fields table
613 false, currentVariant );
616 false, currentVariant );
617
618 // Attribute fields (boolean flags on symbols)
619 dataModel.AddColumn( wxS( "${DNP}" ), GetGeneratedFieldDisplayName( wxS( "${DNP}" ) ),
620 false, currentVariant );
621 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_BOM}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_BOM}" ) ),
622 false, currentVariant );
623 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_BOARD}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_BOARD}" ) ),
624 false, currentVariant );
625 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_SIM}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_SIM}" ) ),
626 false, currentVariant );
627
628 // User field names in symbols second
629 std::set<wxString> userFieldNames;
630
631 for( size_t i = 0; i < referenceList.GetCount(); ++i )
632 {
633 SCH_SYMBOL* symbol = referenceList[i].GetSymbol();
634
635 for( SCH_FIELD& field : symbol->GetFields() )
636 {
637 if( !field.IsMandatory() && !field.IsPrivate() )
638 userFieldNames.insert( field.GetName() );
639 }
640 }
641
642 for( const wxString& fieldName : userFieldNames )
643 dataModel.AddColumn( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, currentVariant );
644
645 // Add any templateFieldNames which aren't already present in the userFieldNames
646 for( const TEMPLATE_FIELDNAME& templateFieldname :
648 {
649 if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
650 {
651 dataModel.AddColumn( templateFieldname.m_Name, GetGeneratedFieldDisplayName( templateFieldname.m_Name ),
652 false, currentVariant );
653 }
654 }
655
656 BOM_PRESET preset;
657
658 // Load a preset if one is specified
659 if( !aBomJob->m_bomPresetName.IsEmpty() )
660 {
661 // Find the preset
662 const BOM_PRESET* schPreset = nullptr;
663
664 for( const BOM_PRESET& p : BOM_PRESET::BuiltInPresets() )
665 {
666 if( p.name == aBomJob->m_bomPresetName )
667 {
668 schPreset = &p;
669 break;
670 }
671 }
672
673 for( const BOM_PRESET& p : sch->Settings().m_BomPresets )
674 {
675 if( p.name == aBomJob->m_bomPresetName )
676 {
677 schPreset = &p;
678 break;
679 }
680 }
681
682 if( !schPreset )
683 {
684 m_reporter->Report( wxString::Format( _( "BOM preset '%s' not found" ) + wxS( "\n" ),
685 aBomJob->m_bomPresetName ),
687
689 }
690
691 preset = *schPreset;
692 }
693 else
694 {
695 // Normalize field names so that bare generated-field tokens (e.g. "QUANTITY") are
696 // accepted alongside the canonical "${QUANTITY}" form. Shell expansion of ${VAR}
697 // inside double quotes silently produces an empty string, so this also guards against
698 // that common CLI pitfall.
699 auto normalizeFieldName = [&dataModel]( const wxString& aName ) -> wxString
700 {
701 if( aName.IsEmpty() )
702 return wxEmptyString;
703
704 if( IsGeneratedField( aName ) )
705 return aName;
706
707 wxString wrapped = wxS( "${" ) + aName + wxS( "}" );
708
709 if( IsGeneratedField( wrapped ) && dataModel.GetFieldNameCol( wrapped ) != -1 )
710 return wrapped;
711
712 return aName;
713 };
714
715 size_t i = 0;
716
717 for( const wxString& rawFieldName : aBomJob->m_fieldsOrdered )
718 {
719 wxString fieldName = normalizeFieldName( rawFieldName );
720
721 if( fieldName.IsEmpty() )
722 {
723 i++;
724 continue;
725 }
726
727 // Handle wildcard. We allow the wildcard anywhere in the list, but it needs to respect
728 // fields that come before and after the wildcard.
729 if( fieldName == wxS( "*" ) )
730 {
731 for( const BOM_FIELD& modelField : dataModel.GetFieldsOrdered() )
732 {
733 struct BOM_FIELD field;
734
735 field.name = modelField.name;
736 field.show = true;
737 field.groupBy = false;
738 field.label = field.name;
739
740 bool fieldAlreadyPresent = false;
741
742 for( BOM_FIELD& presetField : preset.fieldsOrdered )
743 {
744 if( presetField.name == field.name )
745 {
746 fieldAlreadyPresent = true;
747 break;
748 }
749 }
750
751 bool fieldLaterInList = false;
752
753 for( const wxString& fieldInList : aBomJob->m_fieldsOrdered )
754 {
755 if( normalizeFieldName( fieldInList ) == field.name )
756 {
757 fieldLaterInList = true;
758 break;
759 }
760 }
761
762 if( !fieldAlreadyPresent && !fieldLaterInList )
763 preset.fieldsOrdered.emplace_back( field );
764 }
765
766 continue;
767 }
768
769 struct BOM_FIELD field;
770
771 field.name = fieldName;
772 field.show = !fieldName.StartsWith( wxT( "__" ), &field.name );
773
774 field.groupBy = alg::contains( aBomJob->m_fieldsGroupBy, field.name )
775 || alg::contains( aBomJob->m_fieldsGroupBy, rawFieldName );
776
777 if( ( aBomJob->m_fieldsLabels.size() > i ) && !aBomJob->m_fieldsLabels[i].IsEmpty() )
778 field.label = aBomJob->m_fieldsLabels[i];
779 else if( IsGeneratedField( field.name ) )
780 field.label = GetGeneratedFieldDisplayName( field.name );
781 else
782 field.label = field.name;
783
784 preset.fieldsOrdered.emplace_back( field );
785 i++;
786 }
787
788 preset.sortAsc = aBomJob->m_sortAsc;
789 preset.sortField = normalizeFieldName( aBomJob->m_sortField );
790 preset.filterString = aBomJob->m_filterString;
791 preset.groupSymbols = aBomJob->m_groupSymbols;
792 preset.excludeDNP = aBomJob->m_excludeDNP;
793 }
794
795 BOM_FMT_PRESET fmt;
796
797 // Load a format preset if one is specified
798 if( !aBomJob->m_bomFmtPresetName.IsEmpty() )
799 {
800 std::optional<BOM_FMT_PRESET> schFmtPreset;
801
803 {
804 if( p.name == aBomJob->m_bomFmtPresetName )
805 {
806 schFmtPreset = p;
807 break;
808 }
809 }
810
811 for( const BOM_FMT_PRESET& p : sch->Settings().m_BomFmtPresets )
812 {
813 if( p.name == aBomJob->m_bomFmtPresetName )
814 {
815 schFmtPreset = p;
816 break;
817 }
818 }
819
820 if( !schFmtPreset )
821 {
822 m_reporter->Report( wxString::Format( _( "BOM format preset '%s' not found" ) + wxS( "\n" ),
823 aBomJob->m_bomFmtPresetName ),
825
827 }
828
829 fmt = *schFmtPreset;
830 }
831 else
832 {
833 fmt.fieldDelimiter = aBomJob->m_fieldDelimiter;
834 fmt.stringDelimiter = aBomJob->m_stringDelimiter;
835 fmt.refDelimiter = aBomJob->m_refDelimiter;
837 fmt.keepTabs = aBomJob->m_keepTabs;
838 fmt.keepLineBreaks = aBomJob->m_keepLineBreaks;
839 }
840
841 if( aBomJob->GetConfiguredOutputPath().IsEmpty() )
842 {
843 wxFileName fn = sch->GetFileName();
844 fn.SetName( fn.GetName() );
845 fn.SetExt( FILEEXT::CsvFileExtension );
846
847 aBomJob->SetConfiguredOutputPath( fn.GetFullName() );
848 }
849
850 wxString configuredPath = aBomJob->GetConfiguredOutputPath();
851 bool hasVariantPlaceholder = configuredPath.Contains( wxS( "${VARIANT}" ) );
852
853 // Determine which variants to process
854 std::vector<wxString> variantsToProcess;
855
856 if( aBomJob->m_variantNames.size() > 1 && hasVariantPlaceholder )
857 {
858 variantsToProcess = aBomJob->m_variantNames;
859 }
860 else
861 {
862 variantsToProcess.push_back( currentVariant );
863 }
864
865 for( const wxString& variantName : variantsToProcess )
866 {
867 std::vector<wxString> singleVariant = { variantName };
868 dataModel.SetVariantNames( singleVariant );
869 dataModel.SetCurrentVariant( variantName );
870 dataModel.ApplyBomPreset( preset, variantName );
871
872 wxString outPath;
873
874 if( hasVariantPlaceholder )
875 {
876 wxString variantPath = configuredPath;
877 variantPath.Replace( wxS( "${VARIANT}" ), variantName );
878 aBomJob->SetConfiguredOutputPath( variantPath );
879 outPath = aBomJob->GetFullOutputPath( &sch->Project() );
880 aBomJob->SetConfiguredOutputPath( configuredPath );
881 }
882 else
883 {
884 outPath = aBomJob->GetFullOutputPath( &sch->Project() );
885 }
886
887 if( !PATHS::EnsurePathExists( outPath, true ) )
888 {
889 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
891 }
892
893 wxFile f;
894
895 if( !f.Open( outPath, wxFile::write ) )
896 {
897 m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ), outPath ),
899
901 }
902
903 bool res = f.Write( dataModel.Export( fmt ) );
904
905 if( !res )
907
908 aJob->AddOutput( outPath );
909
910 m_reporter->Report( wxString::Format( _( "Wrote bill of materials to '%s'." ), outPath ),
912 }
913
914 return CLI::EXIT_CODES::OK;
915}
916
917
919{
920 JOB_EXPORT_SCH_PYTHONBOM* aNetJob = dynamic_cast<JOB_EXPORT_SCH_PYTHONBOM*>( aJob );
921
922 wxCHECK( aNetJob, CLI::EXIT_CODES::ERR_UNKNOWN );
923
924 SCHEMATIC* sch = getSchematic( aNetJob->m_filename );
925
926 if( !sch )
928
929 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
930 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
931
932 // Annotation warning check
933 SCH_REFERENCE_LIST referenceList;
934 sch->Hierarchy().GetSymbols( referenceList, SYMBOL_FILTER_ALL );
935
936 if( referenceList.GetCount() > 0 )
937 {
938 if( referenceList.CheckAnnotation(
939 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
940 {
941 // We're only interested in the end result -- either errors or not
942 } )
943 > 0 )
944 {
945 m_reporter->Report( _( "Warning: schematic has annotation errors, please use the "
946 "schematic editor to fix them\n" ),
948 }
949 }
950
951 // Test duplicate sheet names:
952 ERC_TESTER erc( sch );
953
954 if( erc.TestDuplicateSheetNames( false ) > 0 )
955 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
956
957 std::unique_ptr<NETLIST_EXPORTER_XML> xmlNetlist =
958 std::make_unique<NETLIST_EXPORTER_XML>( sch );
959
960 if( aNetJob->GetConfiguredOutputPath().IsEmpty() )
961 {
962 wxFileName fn = sch->GetFileName();
963 fn.SetName( fn.GetName() + "-bom" );
964 fn.SetExt( FILEEXT::XmlFileExtension );
965
966 aNetJob->SetConfiguredOutputPath( fn.GetFullName() );
967 }
968
969 wxString outPath = aNetJob->GetFullOutputPath( &sch->Project() );
970
971 if( !PATHS::EnsurePathExists( outPath, true ) )
972 {
973 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
975 }
976
977 bool res = xmlNetlist->WriteNetlist( outPath, GNL_OPT_BOM, *m_reporter );
978
979 if( !res )
981
982 aJob->AddOutput( outPath );
983
984 m_reporter->Report( wxString::Format( _( "Wrote bill of materials to '%s'." ), outPath ),
986
987 return CLI::EXIT_CODES::OK;
988}
989
990
992 LIB_SYMBOL* symbol )
993{
994 wxCHECK( symbol, CLI::EXIT_CODES::ERR_UNKNOWN );
995
996 std::shared_ptr<LIB_SYMBOL> parent;
997 LIB_SYMBOL* symbolToPlot = symbol;
998
999 // if the symbol is an alias, then the draw items are stored in the root symbol
1000 if( symbol->IsDerived() )
1001 {
1002 parent = symbol->GetRootSymbol();
1003
1004 wxCHECK( parent, CLI::EXIT_CODES::ERR_UNKNOWN );
1005
1006 symbolToPlot = parent.get();
1007 }
1008
1009 // iterate from unit 1, unit 0 would be "all units" which we don't want
1010 for( int unit = 1; unit < symbol->GetUnitCount() + 1; unit++ )
1011 {
1012 for( int bodyStyle = 1; bodyStyle <= symbol->GetBodyStyleCount(); ++bodyStyle )
1013 {
1014 wxString filename;
1015 wxFileName fn;
1016
1017 fn.SetPath( aSvgJob->m_outputDirectory );
1018 fn.SetExt( FILEEXT::SVGFileExtension );
1019
1020 filename = symbol->GetName();
1021
1022 for( wxChar c : wxFileName::GetForbiddenChars( wxPATH_DOS ) )
1023 filename.Replace( c, ' ' );
1024
1025 // Even single units get a unit number in the filename. This simplifies the
1026 // handling of the files as they have a uniform pattern.
1027 // Also avoids aliasing 'sym', unit 2 and 'sym_unit2', unit 1 to the same file.
1028 filename += wxString::Format( "_unit%d", unit );
1029
1030 if( symbol->HasDeMorganBodyStyles() )
1031 {
1032 if( bodyStyle == 2 )
1033 filename += wxS( "_demorgan" );
1034 }
1035 else if( bodyStyle <= (int) symbol->GetBodyStyleNames().size() )
1036 {
1037 filename += wxS( "_" ) + symbol->GetBodyStyleNames()[bodyStyle-1].Lower();
1038 }
1039
1040 fn.SetName( filename );
1041 m_reporter->Report( wxString::Format( _( "Plotting symbol '%s' unit %d to '%s'\n" ),
1042 symbol->GetName(),
1043 unit,
1044 fn.GetFullPath() ),
1046
1047 // Get the symbol bounding box to fit the plot page to it
1048 BOX2I symbolBB = symbol->Flatten()->GetUnitBoundingBox( unit, bodyStyle,
1049 !aSvgJob->m_includeHiddenFields );
1050 PAGE_INFO pageInfo( PAGE_SIZE_TYPE::User );
1051 pageInfo.SetHeightMils( schIUScale.IUToMils( symbolBB.GetHeight() * 1.2 ) );
1052 pageInfo.SetWidthMils( schIUScale.IUToMils( symbolBB.GetWidth() * 1.2 ) );
1053
1054 SVG_PLOTTER* plotter = new SVG_PLOTTER();
1055 plotter->SetRenderSettings( aRenderSettings );
1056 plotter->SetPageSettings( pageInfo );
1057 plotter->SetColorMode( !aSvgJob->m_blackAndWhite );
1058
1059 VECTOR2I plot_offset = symbolBB.GetCenter();
1060 const double scale = 1.0;
1061
1062 // Currently, plot units are in decimal
1063 plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, scale, false );
1064
1065 plotter->SetCreator( wxT( "Eeschema-SVG" ) );
1066
1067 if( !plotter->OpenFile( fn.GetFullPath() ) )
1068 {
1069 m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ) + wxS( "\n" ),
1070 fn.GetFullPath() ),
1072
1073 delete plotter;
1075 }
1076
1077 LOCALE_IO toggle;
1078 SCH_PLOT_OPTS plotOpts;
1079
1080 plotter->StartPlot( wxT( "1" ) );
1081
1082 bool background = true;
1083 VECTOR2I offset( pageInfo.GetWidthIU( schIUScale.IU_PER_MILS ) / 2,
1084 pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) / 2 );
1085
1086 // note, we want the fields from the original symbol pointer (in case of non-alias)
1087 symbolToPlot->Plot( plotter, background, plotOpts, unit, bodyStyle, offset, false );
1088 symbol->PlotFields( plotter, background, plotOpts, unit, bodyStyle, offset, false );
1089
1090 symbolToPlot->Plot( plotter, !background, plotOpts, unit, bodyStyle, offset, false );
1091 symbol->PlotFields( plotter, !background, plotOpts, unit, bodyStyle, offset, false );
1092
1093 plotter->EndPlot();
1094 delete plotter;
1095 }
1096 }
1097
1098 if( m_reporter->HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
1100
1101 return CLI::EXIT_CODES::OK;
1102}
1103
1104
1106{
1107 JOB_SYM_EXPORT_SVG* svgJob = dynamic_cast<JOB_SYM_EXPORT_SVG*>( aJob );
1108
1109 wxCHECK( svgJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1110
1111 wxFileName fn( svgJob->m_libraryPath );
1112 fn.MakeAbsolute();
1113
1114 SCH_IO_KICAD_SEXPR_LIB_CACHE schLibrary( fn.GetFullPath() );
1115
1116 try
1117 {
1118 schLibrary.Load();
1119 }
1120 catch( ... )
1121 {
1122 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1124 }
1125
1126 if( m_progressReporter )
1127 m_progressReporter->KeepRefreshing();
1128
1129 LIB_SYMBOL* symbol = nullptr;
1130
1131 if( !svgJob->m_symbol.IsEmpty() )
1132 {
1133 // See if the selected symbol exists
1134 symbol = schLibrary.GetSymbol( svgJob->m_symbol );
1135
1136 if( !symbol )
1137 {
1138 m_reporter->Report( _( "There is no symbol selected to save." ) + wxS( "\n" ),
1141 }
1142 }
1143
1144 if( !svgJob->m_outputDirectory.IsEmpty() && !wxDir::Exists( svgJob->m_outputDirectory ) )
1145 {
1146 if( !wxFileName::Mkdir( svgJob->m_outputDirectory ) )
1147 {
1148 m_reporter->Report( wxString::Format( _( "Unable to create output directory '%s'." ) + wxS( "\n" ),
1149 svgJob->m_outputDirectory ),
1152 }
1153 }
1154
1155 SCH_RENDER_SETTINGS renderSettings;
1157 renderSettings.LoadColors( cs );
1158 renderSettings.SetDefaultPenWidth( DEFAULT_LINE_WIDTH_MILS * schIUScale.IU_PER_MILS );
1159 renderSettings.m_ShowHiddenPins = svgJob->m_includeHiddenPins;
1160 renderSettings.m_ShowHiddenFields = svgJob->m_includeHiddenFields;
1161
1162 int exitCode = CLI::EXIT_CODES::OK;
1163
1164 if( symbol )
1165 {
1166 exitCode = doSymExportSvg( svgJob, &renderSettings, symbol );
1167 }
1168 else
1169 {
1170 // Just plot all the symbols we can
1171 const LIB_SYMBOL_MAP& libSymMap = schLibrary.GetSymbolMap();
1172
1173 for( const auto& [name, libSymbol] : libSymMap )
1174 {
1175 if( m_progressReporter )
1176 {
1177 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), name ) );
1178 m_progressReporter->KeepRefreshing();
1179 }
1180
1181 exitCode = doSymExportSvg( svgJob, &renderSettings, libSymbol );
1182
1183 if( exitCode != CLI::EXIT_CODES::OK )
1184 break;
1185 }
1186 }
1187
1188 return exitCode;
1189}
1190
1191
1193{
1194 JOB_SYM_UPGRADE* upgradeJob = dynamic_cast<JOB_SYM_UPGRADE*>( aJob );
1195
1196 wxCHECK( upgradeJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1197
1198 wxFileName fn( upgradeJob->m_libraryPath );
1199 fn.MakeAbsolute();
1200
1201 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1202
1203 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1204 {
1205 if( wxFile::Exists( upgradeJob->m_outputLibraryPath ) )
1206 {
1207 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1209
1211 }
1212 }
1213 else if( fileType != SCH_IO_MGR::SCH_KICAD )
1214 {
1215 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
1217
1219 }
1220
1221 if( fileType == SCH_IO_MGR::SCH_KICAD )
1222 {
1223 SCH_IO_KICAD_SEXPR_LIB_CACHE schLibrary( fn.GetFullPath() );
1224
1225 try
1226 {
1227 schLibrary.Load();
1228 }
1229 catch( ... )
1230 {
1231 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1233 }
1234
1235 if( m_progressReporter )
1236 m_progressReporter->KeepRefreshing();
1237
1238 bool shouldSave =
1240
1241 if( shouldSave )
1242 {
1243 m_reporter->Report( _( "Saving symbol library in updated format\n" ), RPT_SEVERITY_ACTION );
1244
1245 try
1246 {
1247 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1248 schLibrary.SetFileName( upgradeJob->m_outputLibraryPath );
1249
1250 schLibrary.SetModified();
1251 schLibrary.Save();
1252 }
1253 catch( ... )
1254 {
1255 m_reporter->Report( ( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
1257 }
1258 }
1259 else
1260 {
1261 m_reporter->Report( _( "Symbol library was not updated\n" ), RPT_SEVERITY_ERROR );
1262 }
1263 }
1264 else
1265 {
1266 if( !SCH_IO_MGR::ConvertLibrary( nullptr, fn.GetAbsolutePath(), upgradeJob->m_outputLibraryPath ) )
1267 {
1268 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
1270 }
1271 }
1272
1273 return CLI::EXIT_CODES::OK;
1274}
1275
1276
1277
1279{
1280 JOB_SCH_ERC* ercJob = dynamic_cast<JOB_SCH_ERC*>( aJob );
1281
1282 wxCHECK( ercJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1283
1284 SCHEMATIC* sch = getSchematic( ercJob->m_filename );
1285
1286 if( !sch )
1288
1289 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
1290 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
1291
1292 if( ercJob->GetConfiguredOutputPath().IsEmpty() )
1293 {
1294 wxFileName fn = sch->GetFileName();
1295 fn.SetName( fn.GetName() + wxS( "-erc" ) );
1296
1298 fn.SetExt( FILEEXT::JsonFileExtension );
1299 else
1300 fn.SetExt( FILEEXT::ReportFileExtension );
1301
1302 // Use a transient working path so an empty configured output filename isn't persisted
1303 // back into the jobset file. Mirrors the PCB DRC handler.
1304 ercJob->SetWorkingOutputPath( fn.GetFullName() );
1305 }
1306
1307 wxString outPath = ercJob->GetFullOutputPath( &sch->Project() );
1308
1309 if( !PATHS::EnsurePathExists( outPath, true ) )
1310 {
1311 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1313 }
1314
1315 EDA_UNITS units;
1316
1317 switch( ercJob->m_units )
1318 {
1319 case JOB_SCH_ERC::UNITS::INCH: units = EDA_UNITS::INCH; break;
1320 case JOB_SCH_ERC::UNITS::MILS: units = EDA_UNITS::MILS; break;
1321 case JOB_SCH_ERC::UNITS::MM: units = EDA_UNITS::MM; break;
1322 default: units = EDA_UNITS::MM; break;
1323 }
1324
1325 std::shared_ptr<SHEETLIST_ERC_ITEMS_PROVIDER> markersProvider =
1326 std::make_shared<SHEETLIST_ERC_ITEMS_PROVIDER>( sch );
1327
1328 // Running ERC requires libraries be loaded, so make sure they have been
1330 adapter->AsyncLoad();
1331 adapter->BlockUntilLoaded();
1332
1333 ERC_TESTER ercTester( sch );
1334
1335 std::unique_ptr<DS_PROXY_VIEW_ITEM> drawingSheet( getDrawingSheetProxyView( sch ) );
1336 ercTester.RunTests( drawingSheet.get(), nullptr, m_kiway->KiFACE( KIWAY::FACE_CVPCB ),
1337 &sch->Project(), m_progressReporter );
1338
1339 markersProvider->SetSeverities( ercJob->m_severity );
1340
1341 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ), markersProvider->GetCount() ),
1343
1344 ERC_REPORT reportWriter( sch, units, markersProvider );
1345
1346 bool wroteReport = false;
1347
1349 wroteReport = reportWriter.WriteJsonReport( outPath );
1350 else
1351 wroteReport = reportWriter.WriteTextReport( outPath );
1352
1353 if( !wroteReport )
1354 {
1355 m_reporter->Report( wxString::Format( _( "Unable to save ERC report to %s\n" ), outPath ),
1358 }
1359
1360 m_reporter->Report( wxString::Format( _( "Saved ERC Report to %s\n" ), outPath ),
1362
1363 if( ercJob->m_exitCodeViolations )
1364 {
1365 if( markersProvider->GetCount() > 0 )
1367 }
1368
1370}
1371
1372
1374{
1375 JOB_SCH_UPGRADE* aUpgradeJob = dynamic_cast<JOB_SCH_UPGRADE*>( aJob );
1376
1377 if( aUpgradeJob == nullptr )
1379
1380 SCHEMATIC* sch = getSchematic( aUpgradeJob->m_filename );
1381
1382 if( !sch )
1384
1385 bool shouldSave = aUpgradeJob->m_force;
1386
1388 shouldSave = true;
1389
1390 if( !shouldSave )
1391 {
1392 m_reporter->Report( _( "Schematic file was not updated\n" ), RPT_SEVERITY_ERROR );
1394 }
1395
1396 // needs an absolute path
1397 wxFileName schPath( aUpgradeJob->m_filename );
1398 schPath.MakeAbsolute();
1399 const wxString schFullPath = schPath.GetFullPath();
1400
1401 try
1402 {
1403 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
1404 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( schFullPath, sch );
1405 pi->SaveSchematicFile( schFullPath, loadedSheet, sch );
1406 }
1407 catch( const IO_ERROR& ioe )
1408 {
1409 wxString msg =
1410 wxString::Format( _( "Error saving schematic file '%s'.\n%s" ), schFullPath, ioe.What().GetData() );
1411 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
1413 }
1414
1415 m_reporter->Report( _( "Successfully saved schematic file using the latest format\n" ), RPT_SEVERITY_INFO );
1416
1418}
1419
1420
1422{
1423 DS_PROXY_VIEW_ITEM* drawingSheet =
1425 &aSch->Project(), &aSch->RootScreen()->GetTitleBlock(),
1426 aSch->GetProperties() );
1427
1428 drawingSheet->SetPageNumber( TO_UTF8( aSch->RootScreen()->GetPageNumber() ) );
1429 drawingSheet->SetSheetCount( aSch->RootScreen()->GetPageCount() );
1430 drawingSheet->SetFileName( TO_UTF8( aSch->RootScreen()->GetFileName() ) );
1433 drawingSheet->SetIsFirstPage( aSch->RootScreen()->GetVirtualPageNumber() == 1 );
1434
1435 wxString currentVariant = aSch->GetCurrentVariant();
1436 wxString variantDesc = aSch->GetVariantDescription( currentVariant );
1437 drawingSheet->SetVariantName( TO_UTF8( currentVariant ) );
1438 drawingSheet->SetVariantDesc( TO_UTF8( variantDesc ) );
1439
1440 drawingSheet->SetSheetName( "" );
1441 drawingSheet->SetSheetPath( "" );
1442
1443 return drawingSheet;
1444}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:127
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
int GetPageCount() const
Definition base_screen.h:72
int GetVirtualPageNumber() const
Definition base_screen.h:75
const wxString & GetPageNumber() const
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr const Vec GetCenter() const
Definition box2.h:230
constexpr size_type GetHeight() const
Definition box2.h:215
Color settings are a bit different than most of the settings objects in that there can be more than o...
int ShowModal() override
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
void SetSheetPath(const std::string &aSheetPath)
Set the sheet path displayed in the title block.
void SetSheetCount(int aSheetCount)
Change the sheet-count number displayed in the title block.
void SetVariantName(const std::string &aVariant)
Set the current variant name and description to be shown on the drawing sheet.
void SetVariantDesc(const std::string &aVariantDesc)
void SetPageNumber(const std::string &aPageNumber)
Change the page number displayed in the title block.
void SetSheetName(const std::string &aSheetName)
Set the sheet name displayed in the title block.
void SetPageBorderColorLayer(int aLayerId)
Override the layer used to pick the color of the page border (normally LAYER_GRID)
void SetIsFirstPage(bool aIsFirstPage)
Change if this is first page.
void SetFileName(const std::string &aFileName)
Set the file name displayed in the title block.
void SetColorLayer(int aLayerId)
Can be used to override which layer ID is used for drawing sheet item colors.
static SCHEMATIC * LoadSchematic(const wxString &aFileName, bool aSetActive, bool aForceDefaultProject, PROJECT *aProject=nullptr, bool aCalculateConnectivity=true)
void InitRenderSettings(SCH_RENDER_SETTINGS *aRenderSettings, const wxString &aTheme, SCHEMATIC *aSch, const wxString &aDrawingSheetOverride=wxEmptyString)
Configure the SCH_RENDER_SETTINGS object with the correct data to be used with plotting.
SCHEMATIC * getSchematic(const wxString &aPath)
DS_PROXY_VIEW_ITEM * getDrawingSheetProxyView(SCHEMATIC *aSch)
void ClearCachedSchematic()
Clear the cached CLI schematic so the next job reloads from the current project.
int doSymExportSvg(JOB_SYM_EXPORT_SVG *aSvgJob, SCH_RENDER_SETTINGS *aRenderSettings, LIB_SYMBOL *symbol)
bool WriteJsonReport(const wxString &aFullFileName)
Writes a JSON formatted ERC Report to the given file path in the c-locale.
bool WriteTextReport(const wxString &aFullFileName)
Writes the text report also available via GetTextReport directly to a given file path.
void RunTests(DS_PROXY_VIEW_ITEM *aDrawingSheet, SCH_EDIT_FRAME *aEditFrame, KIFACE *aCvPcb, PROJECT *aProject, PROGRESS_REPORTER *aProgressReporter)
Definition erc.cpp:2084
int GetFieldNameCol(const wxString &aFieldName) const
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser, const wxString &aVariantName)
wxString Export(const BOM_FMT_PRESET &settings)
void ApplyBomPreset(const BOM_PRESET &preset, const wxString &aVariantName)
static const wxString ITEM_NUMBER_VARIABLE
void SetVariantNames(const std::vector< wxString > &aVariantNames)
static const wxString QUANTITY_VARIABLE
std::vector< BOM_FIELD > GetFieldsOrdered()
void SetCurrentVariant(const wxString &aVariantName)
Set the current variant name for highlighting purposes.
Provide an extensible class to resolve 3D model paths.
wxString ResolvePath(const wxString &aFileName, const wxString &aWorkingPath, std::vector< const EMBEDDED_FILES * > aEmbeddedFilesStack)
Determine the full path of the given file name.
void SetProgramBase(PGM_BASE *aBase)
Set a pointer to the application's PGM_BASE instance used to extract the local env vars.
bool SetProject(const PROJECT *aProject, bool *flgChanged=nullptr)
Set the current KiCad project directory as the first entry in the model path list.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
void Register(const std::string &aJobTypeName, std::function< int(JOB *job)> aHandler, std::function< bool(JOB *job, wxWindow *aParent)> aConfigHandler)
JOB_DISPATCHER(KIWAY *aKiway)
PROGRESS_REPORTER * m_progressReporter
REPORTER * m_reporter
std::vector< wxString > m_fieldsLabels
std::vector< wxString > m_fieldsOrdered
std::vector< wxString > m_fieldsGroupBy
std::vector< wxString > m_variantNames
std::vector< wxString > m_variantNames
JOB_PAGE_SIZE m_pageSizeSelect
SCH_PLOT_FORMAT m_plotFormat
std::vector< wxString > m_variantNames
std::vector< wxString > m_plotPages
bool m_exitCodeViolations
Definition job_rc.h:52
int m_severity
Definition job_rc.h:49
UNITS m_units
Definition job_rc.h:48
OUTPUT_FORMAT m_format
Definition job_rc.h:50
wxString m_filename
Definition job_rc.h:47
wxString m_outputLibraryPath
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:184
void SetConfiguredOutputPath(const wxString &aPath)
Sets the configured output path for the job, this path is always saved to file.
Definition job.cpp:157
void AddOutput(wxString aOutputPath)
Definition job.h:216
wxString GetFullOutputPath(PROJECT *aProject) const
Returns the full output path for the job, taking into account the configured output path,...
Definition job.cpp:150
bool GetOutputPathIsDirectory() const
Definition job.h:258
wxString GetConfiguredOutputPath() const
Returns the configured output path for the job.
Definition job.h:235
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition job.h:204
void SetWorkingOutputPath(const wxString &aPath)
Sets a transient output path for the job, it takes priority over the configured output path when GetF...
Definition job.h:241
const std::map< wxString, wxString > & GetVarOverrides() const
Definition job.h:197
void SetDefaultPenWidth(int aWidth)
void SetGapLengthRatio(double aRatio)
void SetDashLengthRatio(double aRatio)
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:315
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:402
@ FACE_CVPCB
Definition kiway.h:324
void AsyncLoad()
Loads all available libraries for this adapter type in the background.
Define a library symbol object.
Definition lib_symbol.h:83
const BOX2I GetUnitBoundingBox(int aUnit, int aBodyStyle, bool aIgnoreHiddenFields=true, bool aIgnoreLabelsOnInvisiblePins=true) const
Get the bounding box for the symbol.
bool IsDerived() const
Definition lib_symbol.h:200
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
void PlotFields(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed)
Plot symbol fields.
std::shared_ptr< LIB_SYMBOL > GetRootSymbol() const
Get the parent symbol that does not have another parent.
wxString GetName() const override
Definition lib_symbol.h:145
const std::vector< wxString > & GetBodyStyleNames() const
Definition lib_symbol.h:787
bool HasDeMorganBodyStyles() const override
Definition lib_symbol.h:784
int GetBodyStyleCount() const override
Definition lib_symbol.h:776
int GetUnitCount() const override
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:41
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
int GetHeightIU(double aIUScale) const
Gets the page height in IU.
Definition page_info.h:168
void SetHeightMils(double aHeightInMils)
int GetWidthIU(double aIUScale) const
Gets the page width in IU.
Definition page_info.h:159
void SetWidthMils(double aWidthInMils)
static bool EnsurePathExists(const wxString &aPath, bool aPathToFile=false)
Attempts to create a given path if it does not exist.
Definition paths.cpp:518
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:130
virtual bool OpenFile(const wxString &aFullFilename)
Open or create the plot file aFullFilename.
Definition plotter.cpp:77
virtual void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition plotter.h:169
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition plotter.h:166
virtual void SetCreator(const wxString &aCreator)
Definition plotter.h:188
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition plotter.h:163
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:66
virtual void ApplyTextVars(const std::map< wxString, wxString > &aVarsMap)
Applies the given var map, it will create or update existing vars.
Definition project.cpp:136
std::vector< BOM_PRESET > m_BomPresets
std::vector< BOM_FMT_PRESET > m_BomFmtPresets
Holds all the data relating to one schematic.
Definition schematic.h:89
void SetCurrentVariant(const wxString &aVariantName)
wxString GetVariantDescription(const wxString &aVariantName) const
Return the description for a variant.
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCHEMATIC_SETTINGS & Settings() const
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
PROJECT & Project() const
Return a reference to the project this schematic is part of.
Definition schematic.h:104
wxString GetCurrentVariant() const
Return the current variant being edited.
EMBEDDED_FILES * GetEmbeddedFiles() override
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
const std::map< wxString, wxString > * GetProperties()
Definition schematic.h:107
SCH_SHEET & Root() const
Definition schematic.h:133
Schematic editor (Eeschema) main window.
SCHEMATIC & Schematic() const
A cache assistant for the KiCad s-expression symbol libraries.
void Save(const std::optional< bool > &aOpt=std::nullopt) override
Save the entire library to file m_libFileName;.
virtual LIB_SYMBOL * GetSymbol(const wxString &aName)
void SetFileName(const wxString &aFileName)
const LIB_SYMBOL_MAP & GetSymbolMap() const
void SetModified(bool aModified=true)
static bool ConvertLibrary(std::map< std::string, UTF8 > *aOldFileProps, const wxString &aOldFilePath, const wxString &aNewFilepath)
Convert a schematic symbol library to the latest KiCad format.
static SCH_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
Return a plugin type given a symbol library using the file extension of aLibPath.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
int CheckAnnotation(ANNOTATION_ERROR_HANDLER aErrorHandler)
Check for annotations errors.
A helper to define a symbol's reference designator in a schematic.
void LoadColors(const COLOR_SETTINGS *aSettings) override
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:750
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
const PAGE_INFO & GetPageSettings() const
Definition sch_screen.h:141
const wxString & GetFileName() const
Definition sch_screen.h:154
int GetFileFormatVersionAtLoad() const
Definition sch_screen.h:139
TITLE_BLOCK & GetTitleBlock()
Definition sch_screen.h:165
void GetSymbols(SCH_REFERENCE_LIST &aReferences, SYMBOL_FILTER aSymbolFilter, bool aForceIncludeOrphanSymbols=false) const
Add a SCH_REFERENCE object to aReferences for each symbol in the list of sheets.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
Schematic symbol object.
Definition sch_symbol.h:76
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
virtual bool StartPlot(const wxString &aPageNumber) override
Create SVG file header.
virtual void SetViewport(const VECTOR2I &aOffset, double aIusPerDecimil, double aScale, bool aMirror) override
Set the plot offset and scaling for the current plot.
virtual bool EndPlot() override
An interface to the global shared library manager that is schematic-specific and linked to one projec...
const std::vector< TEMPLATE_FIELDNAME > & GetTemplateFieldNames()
Return a template field name list for read only access.
wxString GetGeneratedFieldDisplayName(const wxString &aSource)
Returns any variables unexpanded, e.g.
Definition common.cpp:448
bool IsGeneratedField(const wxString &aSource)
Returns true if the string is generated, e.g contains a single text var reference.
Definition common.cpp:460
The common library.
wxString GetDefaultPlotExtension(PLOT_FORMAT aFormat)
Return the default plot extension for a format.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:221
This file is part of the common library.
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
#define _(s)
EDA_UNITS
Definition eda_units.h:48
ERCE_T
ERC error codes.
@ FRAME_SCH
Definition frame_type.h:34
static const std::string CadstarNetlistFileExtension
static const std::string NetlistFileExtension
static const std::string ReportFileExtension
static const std::string JsonFileExtension
static const std::string XmlFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string OrCadPcb2NetlistFileExtension
static const std::string CsvFileExtension
static const std::string SpiceFileExtension
static const std::string SVGFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define KICAD_FONT_NAME
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition layer_ids.h:498
@ LAYER_SCHEMATIC_PAGE_LIMITS
Definition layer_ids.h:499
static const int ERR_ARGS
Definition exit_codes.h:31
static const int OK
Definition exit_codes.h:30
static const int ERR_RC_VIOLATIONS
Rules check violation count was greater than 0.
Definition exit_codes.h:37
static const int ERR_INVALID_INPUT_FILE
Definition exit_codes.h:33
static const int SUCCESS
Definition exit_codes.h:29
static const int ERR_INVALID_OUTPUT_CONFLICT
Definition exit_codes.h:34
static const int ERR_UNKNOWN
Definition exit_codes.h:32
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:100
@ GNL_OPT_BOM
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
PLOT_FORMAT
The set of supported output plot formats.
Definition plotter.h:64
Plotting engines similar to ps (PostScript, Gerber, svg)
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ RPT_SEVERITY_INFO
@ RPT_SEVERITY_ACTION
#define SEXPR_SYMBOL_LIB_FILE_VERSION
This file contains the file format version information for the s-expression schematic and symbol libr...
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
@ PAGE_SIZE_AUTO
Definition sch_plotter.h:48
@ PAGE_SIZE_A
Definition sch_plotter.h:50
@ PAGE_SIZE_A4
Definition sch_plotter.h:49
@ SYMBOL_FILTER_NON_POWER
@ SYMBOL_FILTER_ALL
COLOR_SETTINGS * GetColorSettings(const wxString &aName)
T * GetAppSettings(const char *aFilename)
const int scale
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
wxString label
wxString name
wxString fieldDelimiter
static std::vector< BOM_FMT_PRESET > BuiltInPresets()
wxString stringDelimiter
wxString refRangeDelimiter
wxString refDelimiter
wxString sortField
bool groupSymbols
std::vector< BOM_FIELD > fieldsOrdered
static std::vector< BOM_PRESET > BuiltInPresets()
bool excludeDNP
wxString filterString
std::vector< wxString > m_plotPages
Definition sch_plotter.h:58
wxString m_theme
Definition sch_plotter.h:67
DXF_UNITS m_DXF_File_Unit
Definition sch_plotter.h:74
bool m_PDFPropertyPopups
Definition sch_plotter.h:64
wxString m_outputDirectory
Definition sch_plotter.h:69
wxString m_outputFile
Definition sch_plotter.h:70
bool m_blackAndWhite
Definition sch_plotter.h:61
wxString m_variant
Definition sch_plotter.h:71
bool m_PDFHierarchicalLinks
Definition sch_plotter.h:65
bool m_useBackgroundColor
Definition sch_plotter.h:63
bool m_plotDrawingSheet
Definition sch_plotter.h:57
Hold a name of a symbol's field, field value, and default visibility.
std::map< wxString, LIB_SYMBOL *, LibSymbolMapSort > LIB_SYMBOL_MAP
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#define DO_TRANSLATE
#define MANDATORY_FIELDS
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
wxString GetCanonicalFieldName(FIELD_T aFieldType)
std::string path
VECTOR3I res
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687
Definition of file extensions used in Kicad.