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
103 if( dlg.WasAborted() )
104 return false;
105
106 return dlg.ShowModal() == wxID_OK;
107 } );
108 Register( "pythonbom",
109 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportPythonBom, this, std::placeholders::_1 ),
110 []( JOB* job, wxWindow* aParent ) -> bool
111 {
112 return true;
113 } );
114 Register( "netlist",
115 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportNetlist, this, std::placeholders::_1 ),
116 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
117 {
118 JOB_EXPORT_SCH_NETLIST* netJob = dynamic_cast<JOB_EXPORT_SCH_NETLIST*>( job );
119
120 SCH_EDIT_FRAME* editFrame =
121 static_cast<SCH_EDIT_FRAME*>( aKiway->Player( FRAME_SCH, false ) );
122
123 wxCHECK( netJob && editFrame, false );
124
125 DIALOG_EXPORT_NETLIST dlg( editFrame, aParent, netJob );
126 return dlg.ShowModal() == wxID_OK;
127 } );
128 Register( "plot",
129 std::bind( &EESCHEMA_JOBS_HANDLER::JobExportPlot, this, std::placeholders::_1 ),
130 [aKiway]( JOB* job, wxWindow* aParent ) -> bool
131 {
132 JOB_EXPORT_SCH_PLOT* plotJob = dynamic_cast<JOB_EXPORT_SCH_PLOT*>( job );
133
134 SCH_EDIT_FRAME* editFrame =
135 static_cast<SCH_EDIT_FRAME*>( aKiway->Player( FRAME_SCH, false ) );
136
137 wxCHECK( plotJob && editFrame, false );
138
139 if( plotJob->m_plotFormat == SCH_PLOT_FORMAT::HPGL )
140 {
141 DisplayErrorMessage( editFrame,
142 _( "Plotting to HPGL is no longer supported as of KiCad 10.0." ) );
143 return false;
144 }
145
146 DIALOG_PLOT_SCHEMATIC dlg( editFrame, aParent, plotJob );
147 return dlg.ShowModal() == wxID_OK;
148 } );
149 Register( "symupgrade",
150 std::bind( &EESCHEMA_JOBS_HANDLER::JobSymUpgrade, this, std::placeholders::_1 ),
151 []( JOB* job, wxWindow* aParent ) -> bool
152 {
153 return true;
154 } );
155 Register( "symsvg",
156 std::bind( &EESCHEMA_JOBS_HANDLER::JobSymExportSvg, this, std::placeholders::_1 ),
157 []( JOB* job, wxWindow* aParent ) -> bool
158 {
159 return true;
160 } );
161 Register( "erc", std::bind( &EESCHEMA_JOBS_HANDLER::JobSchErc, this, std::placeholders::_1 ),
162 []( JOB* job, wxWindow* aParent ) -> bool
163 {
164 JOB_SCH_ERC* ercJob = dynamic_cast<JOB_SCH_ERC*>( job );
165
166 wxCHECK( ercJob, false );
167
168 DIALOG_ERC_JOB_CONFIG dlg( aParent, ercJob );
169 return dlg.ShowModal() == wxID_OK;
170 } );
171 Register( "upgrade", std::bind( &EESCHEMA_JOBS_HANDLER::JobUpgrade, this, std::placeholders::_1 ),
172 []( JOB* job, wxWindow* aParent ) -> bool
173 {
174 return true;
175 } );
176}
177
178
184
185
187{
188 SCHEMATIC* sch = nullptr;
189
190 if( !Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpenNotDummy() )
191 {
193 wxString schPath = aPath;
194
195 if( schPath.IsEmpty() )
196 {
197 wxFileName path = project.GetProjectFullName();
199 path.MakeAbsolute();
200 schPath = path.GetFullPath();
201 }
202
203 if( !m_cliSchematic )
204 m_cliSchematic = EESCHEMA_HELPERS::LoadSchematic( schPath, true, false, &project );
205
206 sch = m_cliSchematic;
207 }
208 else if( Pgm().IsGUI() && Pgm().GetSettingsManager().IsProjectOpen() )
209 {
210 SCH_EDIT_FRAME* editFrame = static_cast<SCH_EDIT_FRAME*>( m_kiway->Player( FRAME_SCH, false ) );
211
212 if( editFrame )
213 sch = &editFrame->Schematic();
214 }
215 else if( !aPath.IsEmpty() )
216 {
217 sch = EESCHEMA_HELPERS::LoadSchematic( aPath, true, false );
218 }
219
220 if( !sch )
221 m_reporter->Report( _( "Failed to load schematic\n" ), RPT_SEVERITY_ERROR );
222
223 return sch;
224}
225
227 const wxString& aTheme, SCHEMATIC* aSch,
228 const wxString& aDrawingSheetOverride )
229{
230 COLOR_SETTINGS* cs = ::GetColorSettings( aTheme );
231 aRenderSettings->LoadColors( cs );
232 aRenderSettings->m_ShowHiddenPins = false;
233 aRenderSettings->m_ShowHiddenFields = false;
234 aRenderSettings->m_ShowPinAltIcons = false;
235
236 aRenderSettings->SetDefaultPenWidth( aSch->Settings().m_DefaultLineWidth );
237 aRenderSettings->m_LabelSizeRatio = aSch->Settings().m_LabelSizeRatio;
238 aRenderSettings->m_TextOffsetRatio = aSch->Settings().m_TextOffsetRatio;
239 aRenderSettings->m_PinSymbolSize = aSch->Settings().m_PinSymbolSize;
240
241 aRenderSettings->SetDashLengthRatio( aSch->Settings().m_DashedLineDashRatio );
242 aRenderSettings->SetGapLengthRatio( aSch->Settings().m_DashedLineGapRatio );
243
244 // Load the drawing sheet from the filename stored in BASE_SCREEN::m_DrawingSheetFileName.
245 // If empty, or not existing, the default drawing sheet is loaded.
246
247 auto loadSheet =
248 [&]( const wxString& path ) -> bool
249 {
250 wxString msg;
251 FILENAME_RESOLVER resolve;
252 resolve.SetProject( &aSch->Project() );
253 resolve.SetProgramBase( &Pgm() );
254
255 wxString absolutePath = resolve.ResolvePath( path, wxGetCwd(),
256 { aSch->GetEmbeddedFiles() } );
257
258 if( !DS_DATA_MODEL::GetTheInstance().LoadDrawingSheet( absolutePath, &msg ) )
259 {
260 m_reporter->Report( wxString::Format( _( "Error loading drawing sheet '%s'." ), path )
261 + wxS( "\n" ) + msg + wxS( "\n" ),
263 return false;
264 }
265
266 return true;
267 };
268
269 // try to load the override first
270 if( !aDrawingSheetOverride.IsEmpty() && loadSheet( aDrawingSheetOverride ) )
271 return;
272
273 // no override or failed override continues here
274 loadSheet( aSch->Settings().m_SchDrawingSheetFileName );
275}
276
277
279{
280 JOB_EXPORT_SCH_PLOT* aPlotJob = dynamic_cast<JOB_EXPORT_SCH_PLOT*>( aJob );
281
282 wxCHECK( aPlotJob, CLI::EXIT_CODES::ERR_UNKNOWN );
283
284 if( aPlotJob->m_plotFormat == SCH_PLOT_FORMAT::HPGL )
285 {
286 m_reporter->Report( _( "Plotting to HPGL is no longer supported as of KiCad 10.0.\n" ),
289 }
290
291 SCHEMATIC* sch = getSchematic( aPlotJob->m_filename );
292
293 if( !sch )
295
296 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
297 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
298
299 // Determine the variant to use. The dialog edit path writes m_variant (the scalar),
300 // while the CLI path populates m_variantNames directly. Prefer the scalar so a
301 // dialog-edited selection always wins over a stale list left over from CLI input.
302 wxString variantName;
303
304 if( !aPlotJob->m_variant.IsEmpty() )
305 variantName = aPlotJob->m_variant;
306 else if( !aPlotJob->m_variantNames.empty() )
307 variantName = aPlotJob->m_variantNames.front();
308
309 if( !variantName.IsEmpty() && variantName != wxS( "all" ) )
310 sch->SetCurrentVariant( variantName );
311
312 std::unique_ptr<SCH_RENDER_SETTINGS> renderSettings = std::make_unique<SCH_RENDER_SETTINGS>();
313 InitRenderSettings( renderSettings.get(), aPlotJob->m_theme, sch, aPlotJob->m_drawingSheet );
314
315 wxString font = aPlotJob->m_defaultFont;
316
317 if( font.IsEmpty() )
318 {
320 font = cfg ? cfg->m_Appearance.default_font : wxString( KICAD_FONT_NAME );
321 }
322
323 renderSettings->SetDefaultFont( font );
324 renderSettings->SetMinPenWidth( aPlotJob->m_minPenWidth );
325
326 // Clear cached bounding boxes for all text items so they're recomputed with the correct
327 // default font. This is necessary because text bounding boxes may have been cached during
328 // schematic loading before the render settings (and thus default font) were configured.
329 SCH_SCREENS screens( sch->Root() );
330
331 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
332 {
333 for( SCH_ITEM* item : screen->Items() )
334 item->ClearCaches();
335
336 for( const auto& [libItemName, libSymbol] : screen->GetLibSymbols() )
337 libSymbol->ClearCaches();
338 }
339
340 std::unique_ptr<SCH_PLOTTER> schPlotter = std::make_unique<SCH_PLOTTER>( sch );
341
343
344 switch( aPlotJob->m_plotFormat )
345 {
346 case SCH_PLOT_FORMAT::DXF: format = PLOT_FORMAT::DXF; break;
347 case SCH_PLOT_FORMAT::PDF: format = PLOT_FORMAT::PDF; break;
348 case SCH_PLOT_FORMAT::SVG: format = PLOT_FORMAT::SVG; break;
349 case SCH_PLOT_FORMAT::POST: format = PLOT_FORMAT::POST; break;
350 case SCH_PLOT_FORMAT::PNG: format = PLOT_FORMAT::PNG; break;
351 case SCH_PLOT_FORMAT::HPGL: /* no longer supported */ break;
352 }
353
354 int pageSizeSelect = PageFormatReq::PAGE_SIZE_AUTO;
355
356 switch( aPlotJob->m_pageSizeSelect )
357 {
358 case JOB_PAGE_SIZE::PAGE_SIZE_A: pageSizeSelect = PageFormatReq::PAGE_SIZE_A; break;
359 case JOB_PAGE_SIZE::PAGE_SIZE_A4: pageSizeSelect = PageFormatReq::PAGE_SIZE_A4; break;
361 }
362
363 if( !aPlotJob->GetOutputPathIsDirectory() && aPlotJob->GetConfiguredOutputPath().IsEmpty() )
364 {
365 wxFileName fn = sch->GetFileName();
366 fn.SetName( fn.GetName() );
367 fn.SetExt( GetDefaultPlotExtension( format ) );
368
369 aPlotJob->SetConfiguredOutputPath( fn.GetFullName() );
370 }
371
372 wxString outPath = aPlotJob->GetFullOutputPath( &sch->Project() );
373
374 if( !PATHS::EnsurePathExists( outPath, !aPlotJob->GetOutputPathIsDirectory() ) )
375 {
376 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
378 }
379
380 SCH_PLOT_OPTS plotOpts;
381 plotOpts.m_blackAndWhite = aPlotJob->m_blackAndWhite;
382 plotOpts.m_PDFPropertyPopups = aPlotJob->m_PDFPropertyPopups;
384 plotOpts.m_PDFMetadata = aPlotJob->m_PDFMetadata;
385
386 if( aPlotJob->GetOutputPathIsDirectory() )
387 {
388 plotOpts.m_outputDirectory = outPath;
389 plotOpts.m_outputFile = wxEmptyString;
390 }
391 else
392 {
393 plotOpts.m_outputDirectory = wxEmptyString;
394 plotOpts.m_outputFile = outPath;
395 }
396
397 plotOpts.m_pageSizeSelect = pageSizeSelect;
398 plotOpts.m_plotAll = aPlotJob->m_plotAll;
399 plotOpts.m_plotDrawingSheet = aPlotJob->m_plotDrawingSheet;
400 plotOpts.m_plotPages = aPlotJob->m_plotPages;
401 plotOpts.m_theme = aPlotJob->m_theme;
402 plotOpts.m_useBackgroundColor = aPlotJob->m_useBackgroundColor;
403 plotOpts.m_plotHopOver = aPlotJob->m_show_hop_over;
404
405 if( !variantName.IsEmpty() )
406 plotOpts.m_variant = variantName;
407
408 // Always export dxf in mm by kicad-cli (similar to Pcbnew)
410
411 if( aPlotJob->m_plotFormat == SCH_PLOT_FORMAT::PNG )
412 {
413 JOB_EXPORT_SCH_PLOT_PNG* pngJob = static_cast<JOB_EXPORT_SCH_PLOT_PNG*>( aPlotJob );
414 plotOpts.m_pngDPI = pngJob->m_dpi;
415 plotOpts.m_pngAntialias = pngJob->m_antialias;
416 }
417
418 schPlotter->Plot( format, plotOpts, renderSettings.get(), m_reporter );
419
420 if( m_reporter->HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
422
423 for( const wxString& outputPath : schPlotter->GetOutputFilePaths() )
424 aJob->AddOutput( outputPath );
425
426 return CLI::EXIT_CODES::OK;
427}
428
429
431{
432 JOB_EXPORT_SCH_NETLIST* aNetJob = dynamic_cast<JOB_EXPORT_SCH_NETLIST*>( aJob );
433
434 wxCHECK( aNetJob, CLI::EXIT_CODES::ERR_UNKNOWN );
435
436 SCHEMATIC* sch = getSchematic( aNetJob->m_filename );
437
438 if( !sch )
440
441 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
442 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
443
444 // Apply variant if specified
445 if( !aNetJob->m_variantNames.empty() )
446 {
447 // For netlist export, we use the first variant name from the set
448 wxString variantName = *aNetJob->m_variantNames.begin();
449
450 if( variantName != wxS( "all" ) )
451 sch->SetCurrentVariant( variantName );
452 }
453
454 // Annotation warning check
455 SCH_REFERENCE_LIST referenceList;
456 sch->Hierarchy().GetSymbols( referenceList, SYMBOL_FILTER_ALL );
457
458 if( referenceList.GetCount() > 0 )
459 {
460 if( referenceList.CheckAnnotation(
461 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
462 {
463 // We're only interested in the end result -- either errors or not
464 } )
465 > 0 )
466 {
467 m_reporter->Report( _( "Warning: schematic has annotation errors, please use the "
468 "schematic editor to fix them\n" ),
470 }
471 }
472
473 // Test duplicate sheet names:
474 ERC_TESTER erc( sch );
475
476 if( erc.TestDuplicateSheetNames( false ) > 0 )
477 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
478
479 std::unique_ptr<NETLIST_EXPORTER_BASE> helper;
480 unsigned netlistOption = 0;
481
482 wxString fileExt;
483
484 switch( aNetJob->format )
485 {
488 helper = std::make_unique<NETLIST_EXPORTER_KICAD>( sch );
489 break;
490
493 helper = std::make_unique<NETLIST_EXPORTER_ORCADPCB2>( sch );
494 break;
495
498 helper = std::make_unique<NETLIST_EXPORTER_CADSTAR>( sch );
499 break;
500
504 helper = std::make_unique<NETLIST_EXPORTER_SPICE>( sch );
505 break;
506
509 helper = std::make_unique<NETLIST_EXPORTER_SPICE_MODEL>( sch );
510 break;
511
513 fileExt = wxS( "xml" );
514 helper = std::make_unique<NETLIST_EXPORTER_XML>( sch );
515 break;
516
518 fileExt = wxS( "asc" );
519 helper = std::make_unique<NETLIST_EXPORTER_PADS>( sch );
520 break;
521
523 fileExt = wxS( "txt" );
524 helper = std::make_unique<NETLIST_EXPORTER_ALLEGRO>( sch );
525 break;
526
527 default:
528 m_reporter->Report( _( "Unknown netlist format.\n" ), RPT_SEVERITY_ERROR );
530 }
531
532 if( aNetJob->GetConfiguredOutputPath().IsEmpty() )
533 {
534 wxFileName fn = sch->GetFileName();
535 fn.SetName( fn.GetName() );
536 fn.SetExt( fileExt );
537
538 aNetJob->SetConfiguredOutputPath( fn.GetFullName() );
539 }
540
541 wxString outPath = aNetJob->GetFullOutputPath( &sch->Project() );
542
543 if( !PATHS::EnsurePathExists( outPath, true ) )
544 {
545 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
547 }
548
549 bool res = helper->WriteNetlist( outPath, netlistOption, *m_reporter );
550
551 if( !res )
553
554 aJob->AddOutput( outPath );
555
556 return CLI::EXIT_CODES::OK;
557}
558
559
561{
562 JOB_EXPORT_SCH_BOM* aBomJob = dynamic_cast<JOB_EXPORT_SCH_BOM*>( aJob );
563
564 wxCHECK( aBomJob, CLI::EXIT_CODES::ERR_UNKNOWN );
565
566 SCHEMATIC* sch = getSchematic( aBomJob->m_filename );
567
568 if( !sch )
570
571 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
572 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
573
574 wxString currentVariant;
575
576 if( !aBomJob->m_variantNames.empty() )
577 {
578 currentVariant = aBomJob->m_variantNames.front();
579
580 if( currentVariant != wxS( "all" ) )
581 sch->SetCurrentVariant( currentVariant );
582 }
583
584 // Annotation warning check
585 SCH_REFERENCE_LIST referenceList;
586 sch->Hierarchy().GetSymbols( referenceList, SYMBOL_FILTER_NON_POWER, false );
587
588 if( referenceList.GetCount() > 0 )
589 {
590 SCH_REFERENCE_LIST copy = referenceList;
591
592 // Check annotation splits references...
593 if( copy.CheckAnnotation(
594 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
595 {
596 // We're only interested in the end result -- either errors or not
597 } )
598 > 0 )
599 {
600 m_reporter->Report(
601 _( "Warning: schematic has annotation errors, please use the schematic "
602 "editor to fix them\n" ),
604 }
605 }
606
607 // Test duplicate sheet names:
608 ERC_TESTER erc( sch );
609
610 if( erc.TestDuplicateSheetNames( false ) > 0 )
611 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
612
613 // Build our data model
614 FIELDS_EDITOR_GRID_DATA_MODEL dataModel( referenceList, nullptr );
615
616 // Mandatory fields first
617 for( FIELD_T fieldId : MANDATORY_FIELDS )
618 {
619 dataModel.AddColumn( GetCanonicalFieldName( fieldId ),
620 GetDefaultFieldName( fieldId, DO_TRANSLATE ), false, currentVariant );
621 }
622
623 // Generated/virtual fields (e.g. ${QUANTITY}, ${ITEM_NUMBER}) present only in the fields table
626 false, currentVariant );
629 false, currentVariant );
630
631 // Attribute fields (boolean flags on symbols)
632 dataModel.AddColumn( wxS( "${DNP}" ), GetGeneratedFieldDisplayName( wxS( "${DNP}" ) ),
633 false, currentVariant );
634 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_BOM}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_BOM}" ) ),
635 false, currentVariant );
636 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_BOARD}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_BOARD}" ) ),
637 false, currentVariant );
638 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_SIM}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_SIM}" ) ),
639 false, currentVariant );
640
641 // User field names in symbols second
642 std::set<wxString> userFieldNames;
643
644 for( size_t i = 0; i < referenceList.GetCount(); ++i )
645 {
646 SCH_SYMBOL* symbol = referenceList[i].GetSymbol();
647
648 for( SCH_FIELD& field : symbol->GetFields() )
649 {
650 if( !field.IsMandatory() && !field.IsPrivate() )
651 userFieldNames.insert( field.GetName() );
652 }
653 }
654
655 for( const wxString& fieldName : userFieldNames )
656 dataModel.AddColumn( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, currentVariant );
657
658 // Add any templateFieldNames which aren't already present in the userFieldNames
659 for( const TEMPLATE_FIELDNAME& templateFieldname :
661 {
662 if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
663 {
664 dataModel.AddColumn( templateFieldname.m_Name, GetGeneratedFieldDisplayName( templateFieldname.m_Name ),
665 false, currentVariant );
666 }
667 }
668
669 BOM_PRESET preset;
670
671 // Load a preset if one is specified
672 if( !aBomJob->m_bomPresetName.IsEmpty() )
673 {
674 // Find the preset
675 const BOM_PRESET* schPreset = nullptr;
676
677 for( const BOM_PRESET& p : BOM_PRESET::BuiltInPresets() )
678 {
679 if( p.name == aBomJob->m_bomPresetName )
680 {
681 schPreset = &p;
682 break;
683 }
684 }
685
686 for( const BOM_PRESET& p : sch->Settings().m_BomPresets )
687 {
688 if( p.name == aBomJob->m_bomPresetName )
689 {
690 schPreset = &p;
691 break;
692 }
693 }
694
695 if( !schPreset )
696 {
697 m_reporter->Report( wxString::Format( _( "BOM preset '%s' not found" ) + wxS( "\n" ),
698 aBomJob->m_bomPresetName ),
700
702 }
703
704 preset = *schPreset;
705 }
706 else
707 {
708 // Normalize field names so that bare generated-field tokens (e.g. "QUANTITY") are
709 // accepted alongside the canonical "${QUANTITY}" form. Shell expansion of ${VAR}
710 // inside double quotes silently produces an empty string, so this also guards against
711 // that common CLI pitfall.
712 auto normalizeFieldName = [&dataModel]( const wxString& aName ) -> wxString
713 {
714 if( aName.IsEmpty() )
715 return wxEmptyString;
716
717 if( IsGeneratedField( aName ) )
718 return aName;
719
720 wxString wrapped = wxS( "${" ) + aName + wxS( "}" );
721
722 if( IsGeneratedField( wrapped ) && dataModel.GetFieldNameCol( wrapped ) != -1 )
723 return wrapped;
724
725 return aName;
726 };
727
728 size_t i = 0;
729
730 for( const wxString& rawFieldName : aBomJob->m_fieldsOrdered )
731 {
732 wxString fieldName = normalizeFieldName( rawFieldName );
733
734 if( fieldName.IsEmpty() )
735 {
736 i++;
737 continue;
738 }
739
740 // Handle wildcard. We allow the wildcard anywhere in the list, but it needs to respect
741 // fields that come before and after the wildcard.
742 if( fieldName == wxS( "*" ) )
743 {
744 for( const BOM_FIELD& modelField : dataModel.GetFieldsOrdered() )
745 {
746 struct BOM_FIELD field;
747
748 field.name = modelField.name;
749 field.show = true;
750 field.groupBy = false;
751 field.label = field.name;
752
753 bool fieldAlreadyPresent = false;
754
755 for( BOM_FIELD& presetField : preset.fieldsOrdered )
756 {
757 if( presetField.name == field.name )
758 {
759 fieldAlreadyPresent = true;
760 break;
761 }
762 }
763
764 bool fieldLaterInList = false;
765
766 for( const wxString& fieldInList : aBomJob->m_fieldsOrdered )
767 {
768 if( normalizeFieldName( fieldInList ) == field.name )
769 {
770 fieldLaterInList = true;
771 break;
772 }
773 }
774
775 if( !fieldAlreadyPresent && !fieldLaterInList )
776 preset.fieldsOrdered.emplace_back( field );
777 }
778
779 continue;
780 }
781
782 struct BOM_FIELD field;
783
784 field.name = fieldName;
785 field.show = !fieldName.StartsWith( wxT( "__" ), &field.name );
786
787 field.groupBy = alg::contains( aBomJob->m_fieldsGroupBy, field.name )
788 || alg::contains( aBomJob->m_fieldsGroupBy, rawFieldName );
789
790 if( ( aBomJob->m_fieldsLabels.size() > i ) && !aBomJob->m_fieldsLabels[i].IsEmpty() )
791 field.label = aBomJob->m_fieldsLabels[i];
792 else if( IsGeneratedField( field.name ) )
793 field.label = GetGeneratedFieldDisplayName( field.name );
794 else
795 field.label = field.name;
796
797 preset.fieldsOrdered.emplace_back( field );
798 i++;
799 }
800
801 preset.sortAsc = aBomJob->m_sortAsc;
802 preset.sortField = normalizeFieldName( aBomJob->m_sortField );
803 preset.filterString = aBomJob->m_filterString;
804 preset.groupSymbols = aBomJob->m_groupSymbols;
805 preset.excludeDNP = aBomJob->m_excludeDNP;
806 }
807
808 BOM_FMT_PRESET fmt;
809
810 // Load a format preset if one is specified
811 if( !aBomJob->m_bomFmtPresetName.IsEmpty() )
812 {
813 std::optional<BOM_FMT_PRESET> schFmtPreset;
814
816 {
817 if( p.name == aBomJob->m_bomFmtPresetName )
818 {
819 schFmtPreset = p;
820 break;
821 }
822 }
823
824 for( const BOM_FMT_PRESET& p : sch->Settings().m_BomFmtPresets )
825 {
826 if( p.name == aBomJob->m_bomFmtPresetName )
827 {
828 schFmtPreset = p;
829 break;
830 }
831 }
832
833 if( !schFmtPreset )
834 {
835 m_reporter->Report( wxString::Format( _( "BOM format preset '%s' not found" ) + wxS( "\n" ),
836 aBomJob->m_bomFmtPresetName ),
838
840 }
841
842 fmt = *schFmtPreset;
843 }
844 else
845 {
846 fmt.fieldDelimiter = aBomJob->m_fieldDelimiter;
847 fmt.stringDelimiter = aBomJob->m_stringDelimiter;
848 fmt.refDelimiter = aBomJob->m_refDelimiter;
850 fmt.keepTabs = aBomJob->m_keepTabs;
851 fmt.keepLineBreaks = aBomJob->m_keepLineBreaks;
852 }
853
854 if( aBomJob->GetConfiguredOutputPath().IsEmpty() )
855 {
856 wxFileName fn = sch->GetFileName();
857 fn.SetName( fn.GetName() );
858 fn.SetExt( FILEEXT::CsvFileExtension );
859
860 aBomJob->SetConfiguredOutputPath( fn.GetFullName() );
861 }
862
863 wxString configuredPath = aBomJob->GetConfiguredOutputPath();
864 bool hasVariantPlaceholder = configuredPath.Contains( wxS( "${VARIANT}" ) );
865
866 // Determine which variants to process
867 std::vector<wxString> variantsToProcess;
868
869 if( aBomJob->m_variantNames.size() > 1 && hasVariantPlaceholder )
870 {
871 variantsToProcess = aBomJob->m_variantNames;
872 }
873 else
874 {
875 variantsToProcess.push_back( currentVariant );
876 }
877
878 for( const wxString& variantName : variantsToProcess )
879 {
880 std::vector<wxString> singleVariant = { variantName };
881 dataModel.SetVariantNames( singleVariant );
882 dataModel.SetCurrentVariant( variantName );
883 dataModel.ApplyBomPreset( preset, variantName );
884
885 wxString outPath;
886
887 if( hasVariantPlaceholder )
888 {
889 wxString variantPath = configuredPath;
890 variantPath.Replace( wxS( "${VARIANT}" ), variantName );
891 aBomJob->SetConfiguredOutputPath( variantPath );
892 outPath = aBomJob->GetFullOutputPath( &sch->Project() );
893 aBomJob->SetConfiguredOutputPath( configuredPath );
894 }
895 else
896 {
897 outPath = aBomJob->GetFullOutputPath( &sch->Project() );
898 }
899
900 if( !PATHS::EnsurePathExists( outPath, true ) )
901 {
902 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
904 }
905
906 wxFile f;
907
908 if( !f.Open( outPath, wxFile::write ) )
909 {
910 m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ), outPath ),
912
914 }
915
916 bool res = f.Write( dataModel.Export( fmt ) );
917
918 if( !res )
920
921 aJob->AddOutput( outPath );
922
923 m_reporter->Report( wxString::Format( _( "Wrote bill of materials to '%s'." ), outPath ),
925 }
926
927 return CLI::EXIT_CODES::OK;
928}
929
930
932{
933 JOB_EXPORT_SCH_PYTHONBOM* aNetJob = dynamic_cast<JOB_EXPORT_SCH_PYTHONBOM*>( aJob );
934
935 wxCHECK( aNetJob, CLI::EXIT_CODES::ERR_UNKNOWN );
936
937 SCHEMATIC* sch = getSchematic( aNetJob->m_filename );
938
939 if( !sch )
941
942 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
943 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
944
945 // Annotation warning check
946 SCH_REFERENCE_LIST referenceList;
947 sch->Hierarchy().GetSymbols( referenceList, SYMBOL_FILTER_ALL );
948
949 if( referenceList.GetCount() > 0 )
950 {
951 if( referenceList.CheckAnnotation(
952 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
953 {
954 // We're only interested in the end result -- either errors or not
955 } )
956 > 0 )
957 {
958 m_reporter->Report( _( "Warning: schematic has annotation errors, please use the "
959 "schematic editor to fix them\n" ),
961 }
962 }
963
964 // Test duplicate sheet names:
965 ERC_TESTER erc( sch );
966
967 if( erc.TestDuplicateSheetNames( false ) > 0 )
968 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
969
970 std::unique_ptr<NETLIST_EXPORTER_XML> xmlNetlist =
971 std::make_unique<NETLIST_EXPORTER_XML>( sch );
972
973 if( aNetJob->GetConfiguredOutputPath().IsEmpty() )
974 {
975 wxFileName fn = sch->GetFileName();
976 fn.SetName( fn.GetName() + "-bom" );
977 fn.SetExt( FILEEXT::XmlFileExtension );
978
979 aNetJob->SetConfiguredOutputPath( fn.GetFullName() );
980 }
981
982 wxString outPath = aNetJob->GetFullOutputPath( &sch->Project() );
983
984 if( !PATHS::EnsurePathExists( outPath, true ) )
985 {
986 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
988 }
989
990 bool res = xmlNetlist->WriteNetlist( outPath, GNL_OPT_BOM, *m_reporter );
991
992 if( !res )
994
995 aJob->AddOutput( outPath );
996
997 m_reporter->Report( wxString::Format( _( "Wrote bill of materials to '%s'." ), outPath ),
999
1000 return CLI::EXIT_CODES::OK;
1001}
1002
1003
1005 LIB_SYMBOL* symbol )
1006{
1007 wxCHECK( symbol, CLI::EXIT_CODES::ERR_UNKNOWN );
1008
1009 std::shared_ptr<LIB_SYMBOL> parent;
1010 LIB_SYMBOL* symbolToPlot = symbol;
1011
1012 // if the symbol is an alias, then the draw items are stored in the root symbol
1013 if( symbol->IsDerived() )
1014 {
1015 parent = symbol->GetRootSymbol();
1016
1017 wxCHECK( parent, CLI::EXIT_CODES::ERR_UNKNOWN );
1018
1019 symbolToPlot = parent.get();
1020 }
1021
1022 // iterate from unit 1, unit 0 would be "all units" which we don't want
1023 for( int unit = 1; unit < symbol->GetUnitCount() + 1; unit++ )
1024 {
1025 for( int bodyStyle = 1; bodyStyle <= symbol->GetBodyStyleCount(); ++bodyStyle )
1026 {
1027 wxString filename;
1028 wxFileName fn;
1029
1030 fn.SetPath( aSvgJob->m_outputDirectory );
1031 fn.SetExt( FILEEXT::SVGFileExtension );
1032
1033 filename = symbol->GetName();
1034
1035 for( wxChar c : wxFileName::GetForbiddenChars( wxPATH_DOS ) )
1036 filename.Replace( c, ' ' );
1037
1038 // Even single units get a unit number in the filename. This simplifies the
1039 // handling of the files as they have a uniform pattern.
1040 // Also avoids aliasing 'sym', unit 2 and 'sym_unit2', unit 1 to the same file.
1041 filename += wxString::Format( "_unit%d", unit );
1042
1043 if( symbol->HasDeMorganBodyStyles() )
1044 {
1045 if( bodyStyle == 2 )
1046 filename += wxS( "_demorgan" );
1047 }
1048 else if( bodyStyle <= (int) symbol->GetBodyStyleNames().size() )
1049 {
1050 filename += wxS( "_" ) + symbol->GetBodyStyleNames()[bodyStyle-1].Lower();
1051 }
1052
1053 fn.SetName( filename );
1054 m_reporter->Report( wxString::Format( _( "Plotting symbol '%s' unit %d to '%s'\n" ),
1055 symbol->GetName(),
1056 unit,
1057 fn.GetFullPath() ),
1059
1060 // Get the symbol bounding box to fit the plot page to it
1061 BOX2I symbolBB = symbol->Flatten()->GetUnitBoundingBox( unit, bodyStyle,
1062 !aSvgJob->m_includeHiddenFields );
1063 PAGE_INFO pageInfo( PAGE_SIZE_TYPE::User );
1064 pageInfo.SetHeightMils( schIUScale.IUToMils( symbolBB.GetHeight() * 1.2 ) );
1065 pageInfo.SetWidthMils( schIUScale.IUToMils( symbolBB.GetWidth() * 1.2 ) );
1066
1067 SVG_PLOTTER* plotter = new SVG_PLOTTER();
1068 plotter->SetRenderSettings( aRenderSettings );
1069 plotter->SetPageSettings( pageInfo );
1070 plotter->SetColorMode( !aSvgJob->m_blackAndWhite );
1071
1072 VECTOR2I plot_offset = symbolBB.GetCenter();
1073 const double scale = 1.0;
1074
1075 // Currently, plot units are in decimal
1076 plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, scale, false );
1077
1078 plotter->SetCreator( wxT( "Eeschema-SVG" ) );
1079
1080 if( !plotter->OpenFile( fn.GetFullPath() ) )
1081 {
1082 m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ) + wxS( "\n" ),
1083 fn.GetFullPath() ),
1085
1086 delete plotter;
1088 }
1089
1090 LOCALE_IO toggle;
1091 SCH_PLOT_OPTS plotOpts;
1092
1093 plotter->StartPlot( wxT( "1" ) );
1094
1095 bool background = true;
1096 VECTOR2I offset( pageInfo.GetWidthIU( schIUScale.IU_PER_MILS ) / 2,
1097 pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) / 2 );
1098
1099 // note, we want the fields from the original symbol pointer (in case of non-alias)
1100 symbolToPlot->Plot( plotter, background, plotOpts, unit, bodyStyle, offset, false );
1101 symbol->PlotFields( plotter, background, plotOpts, unit, bodyStyle, offset, false );
1102
1103 symbolToPlot->Plot( plotter, !background, plotOpts, unit, bodyStyle, offset, false );
1104 symbol->PlotFields( plotter, !background, plotOpts, unit, bodyStyle, offset, false );
1105
1106 plotter->EndPlot();
1107 delete plotter;
1108 }
1109 }
1110
1111 if( m_reporter->HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
1113
1114 return CLI::EXIT_CODES::OK;
1115}
1116
1117
1119{
1120 JOB_SYM_EXPORT_SVG* svgJob = dynamic_cast<JOB_SYM_EXPORT_SVG*>( aJob );
1121
1122 wxCHECK( svgJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1123
1124 wxFileName fn( svgJob->m_libraryPath );
1125 fn.MakeAbsolute();
1126
1127 SCH_IO_KICAD_SEXPR_LIB_CACHE schLibrary( fn.GetFullPath() );
1128
1129 try
1130 {
1131 schLibrary.Load();
1132 }
1133 catch( ... )
1134 {
1135 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1137 }
1138
1139 if( m_progressReporter )
1140 m_progressReporter->KeepRefreshing();
1141
1142 LIB_SYMBOL* symbol = nullptr;
1143
1144 if( !svgJob->m_symbol.IsEmpty() )
1145 {
1146 // See if the selected symbol exists
1147 symbol = schLibrary.GetSymbol( svgJob->m_symbol );
1148
1149 if( !symbol )
1150 {
1151 m_reporter->Report( _( "There is no symbol selected to save." ) + wxS( "\n" ),
1154 }
1155 }
1156
1157 if( !svgJob->m_outputDirectory.IsEmpty() && !wxDir::Exists( svgJob->m_outputDirectory ) )
1158 {
1159 if( !wxFileName::Mkdir( svgJob->m_outputDirectory ) )
1160 {
1161 m_reporter->Report( wxString::Format( _( "Unable to create output directory '%s'." ) + wxS( "\n" ),
1162 svgJob->m_outputDirectory ),
1165 }
1166 }
1167
1168 SCH_RENDER_SETTINGS renderSettings;
1170 renderSettings.LoadColors( cs );
1171 renderSettings.SetDefaultPenWidth( DEFAULT_LINE_WIDTH_MILS * schIUScale.IU_PER_MILS );
1172 renderSettings.m_ShowHiddenPins = svgJob->m_includeHiddenPins;
1173 renderSettings.m_ShowHiddenFields = svgJob->m_includeHiddenFields;
1174
1175 int exitCode = CLI::EXIT_CODES::OK;
1176
1177 if( symbol )
1178 {
1179 exitCode = doSymExportSvg( svgJob, &renderSettings, symbol );
1180 }
1181 else
1182 {
1183 // Just plot all the symbols we can
1184 const LIB_SYMBOL_MAP& libSymMap = schLibrary.GetSymbolMap();
1185
1186 for( const auto& [name, libSymbol] : libSymMap )
1187 {
1188 if( m_progressReporter )
1189 {
1190 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), name ) );
1191 m_progressReporter->KeepRefreshing();
1192 }
1193
1194 exitCode = doSymExportSvg( svgJob, &renderSettings, libSymbol );
1195
1196 if( exitCode != CLI::EXIT_CODES::OK )
1197 break;
1198 }
1199 }
1200
1201 return exitCode;
1202}
1203
1204
1206{
1207 JOB_SYM_UPGRADE* upgradeJob = dynamic_cast<JOB_SYM_UPGRADE*>( aJob );
1208
1209 wxCHECK( upgradeJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1210
1211 wxFileName fn( upgradeJob->m_libraryPath );
1212 fn.MakeAbsolute();
1213
1214 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1215
1216 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1217 {
1218 if( wxFile::Exists( upgradeJob->m_outputLibraryPath ) )
1219 {
1220 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1222
1224 }
1225 }
1226 else if( fileType != SCH_IO_MGR::SCH_KICAD )
1227 {
1228 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
1230
1232 }
1233
1234 if( fileType == SCH_IO_MGR::SCH_KICAD )
1235 {
1236 SCH_IO_KICAD_SEXPR_LIB_CACHE schLibrary( fn.GetFullPath() );
1237
1238 try
1239 {
1240 schLibrary.Load();
1241 }
1242 catch( ... )
1243 {
1244 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1246 }
1247
1248 if( m_progressReporter )
1249 m_progressReporter->KeepRefreshing();
1250
1251 bool shouldSave =
1253
1254 if( shouldSave )
1255 {
1256 m_reporter->Report( _( "Saving symbol library in updated format\n" ), RPT_SEVERITY_ACTION );
1257
1258 try
1259 {
1260 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1261 schLibrary.SetFileName( upgradeJob->m_outputLibraryPath );
1262
1263 schLibrary.SetModified();
1264 schLibrary.Save();
1265 }
1266 catch( ... )
1267 {
1268 m_reporter->Report( ( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
1270 }
1271 }
1272 else
1273 {
1274 m_reporter->Report( _( "Symbol library was not updated\n" ), RPT_SEVERITY_ERROR );
1275 }
1276 }
1277 else
1278 {
1279 if( !SCH_IO_MGR::ConvertLibrary( nullptr, fn.GetAbsolutePath(), upgradeJob->m_outputLibraryPath ) )
1280 {
1281 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
1283 }
1284 }
1285
1286 return CLI::EXIT_CODES::OK;
1287}
1288
1289
1290
1292{
1293 JOB_SCH_ERC* ercJob = dynamic_cast<JOB_SCH_ERC*>( aJob );
1294
1295 wxCHECK( ercJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1296
1297 SCHEMATIC* sch = getSchematic( ercJob->m_filename );
1298
1299 if( !sch )
1301
1302 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
1303 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
1304
1305 if( ercJob->GetConfiguredOutputPath().IsEmpty() )
1306 {
1307 wxFileName fn = sch->GetFileName();
1308 fn.SetName( fn.GetName() + wxS( "-erc" ) );
1309
1311 fn.SetExt( FILEEXT::JsonFileExtension );
1312 else
1313 fn.SetExt( FILEEXT::ReportFileExtension );
1314
1315 // Use a transient working path so an empty configured output filename isn't persisted
1316 // back into the jobset file. Mirrors the PCB DRC handler.
1317 ercJob->SetWorkingOutputPath( fn.GetFullName() );
1318 }
1319
1320 wxString outPath = ercJob->GetFullOutputPath( &sch->Project() );
1321
1322 if( !PATHS::EnsurePathExists( outPath, true ) )
1323 {
1324 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1326 }
1327
1328 EDA_UNITS units;
1329
1330 switch( ercJob->m_units )
1331 {
1332 case JOB_SCH_ERC::UNITS::INCH: units = EDA_UNITS::INCH; break;
1333 case JOB_SCH_ERC::UNITS::MILS: units = EDA_UNITS::MILS; break;
1334 case JOB_SCH_ERC::UNITS::MM: units = EDA_UNITS::MM; break;
1335 default: units = EDA_UNITS::MM; break;
1336 }
1337
1338 std::shared_ptr<SHEETLIST_ERC_ITEMS_PROVIDER> markersProvider =
1339 std::make_shared<SHEETLIST_ERC_ITEMS_PROVIDER>( sch );
1340
1341 // Running ERC requires libraries be loaded, so make sure they have been
1343 adapter->AsyncLoad();
1344 adapter->BlockUntilLoaded();
1345
1346 ERC_TESTER ercTester( sch );
1347
1348 std::unique_ptr<DS_PROXY_VIEW_ITEM> drawingSheet( getDrawingSheetProxyView( sch ) );
1349 ercTester.RunTests( drawingSheet.get(), nullptr, m_kiway->KiFACE( KIWAY::FACE_CVPCB ),
1350 &sch->Project(), m_progressReporter );
1351
1352 markersProvider->SetSeverities( ercJob->m_severity );
1353
1354 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ), markersProvider->GetCount() ),
1356
1357 ERC_REPORT reportWriter( sch, units, markersProvider );
1358
1359 bool wroteReport = false;
1360
1362 wroteReport = reportWriter.WriteJsonReport( outPath );
1363 else
1364 wroteReport = reportWriter.WriteTextReport( outPath );
1365
1366 if( !wroteReport )
1367 {
1368 m_reporter->Report( wxString::Format( _( "Unable to save ERC report to %s\n" ), outPath ),
1371 }
1372
1373 m_reporter->Report( wxString::Format( _( "Saved ERC Report to %s\n" ), outPath ),
1375
1376 if( ercJob->m_exitCodeViolations )
1377 {
1378 if( markersProvider->GetCount() > 0 )
1380 }
1381
1383}
1384
1385
1387{
1388 JOB_SCH_UPGRADE* aUpgradeJob = dynamic_cast<JOB_SCH_UPGRADE*>( aJob );
1389
1390 if( aUpgradeJob == nullptr )
1392
1393 SCHEMATIC* sch = getSchematic( aUpgradeJob->m_filename );
1394
1395 if( !sch )
1397
1398 bool shouldSave = aUpgradeJob->m_force;
1399
1401 shouldSave = true;
1402
1403 if( !shouldSave )
1404 {
1405 m_reporter->Report( _( "Schematic file was not updated\n" ), RPT_SEVERITY_ERROR );
1407 }
1408
1409 // needs an absolute path
1410 wxFileName schPath( aUpgradeJob->m_filename );
1411 schPath.MakeAbsolute();
1412 const wxString schFullPath = schPath.GetFullPath();
1413
1414 try
1415 {
1416 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
1417 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( schFullPath, sch );
1418 pi->SaveSchematicFile( schFullPath, loadedSheet, sch );
1419 }
1420 catch( const IO_ERROR& ioe )
1421 {
1422 wxString msg =
1423 wxString::Format( _( "Error saving schematic file '%s'.\n%s" ), schFullPath, ioe.What().GetData() );
1424 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
1426 }
1427
1428 m_reporter->Report( _( "Successfully saved schematic file using the latest format\n" ), RPT_SEVERITY_INFO );
1429
1431}
1432
1433
1435{
1436 DS_PROXY_VIEW_ITEM* drawingSheet =
1438 &aSch->Project(), &aSch->RootScreen()->GetTitleBlock(),
1439 aSch->GetProperties() );
1440
1441 drawingSheet->SetPageNumber( TO_UTF8( aSch->RootScreen()->GetPageNumber() ) );
1442 drawingSheet->SetSheetCount( aSch->RootScreen()->GetPageCount() );
1443 drawingSheet->SetFileName( TO_UTF8( aSch->RootScreen()->GetFileName() ) );
1446 drawingSheet->SetIsFirstPage( aSch->RootScreen()->GetVirtualPageNumber() == 1 );
1447
1448 wxString currentVariant = aSch->GetCurrentVariant();
1449 wxString variantDesc = aSch->GetVariantDescription( currentVariant );
1450 drawingSheet->SetVariantName( TO_UTF8( currentVariant ) );
1451 drawingSheet->SetVariantDesc( TO_UTF8( variantDesc ) );
1452
1453 drawingSheet->SetSheetName( "" );
1454 drawingSheet->SetSheetPath( "" );
1455
1456 return drawingSheet;
1457}
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:2260
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:788
bool HasDeMorganBodyStyles() const override
Definition lib_symbol.h:785
int GetBodyStyleCount() const override
Definition lib_symbol.h:777
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:170
void SetRenderSettings(RENDER_SETTINGS *aSettings)
Definition plotter.h:167
virtual void SetCreator(const wxString &aCreator)
Definition plotter.h:189
virtual void SetColorMode(bool aColorMode)
Plot in B/W or color.
Definition plotter.h:164
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:49
@ PAGE_SIZE_A
Definition sch_plotter.h:51
@ PAGE_SIZE_A4
Definition sch_plotter.h:50
@ 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:59
wxString m_theme
Definition sch_plotter.h:68
DXF_UNITS m_DXF_File_Unit
Definition sch_plotter.h:75
bool m_PDFPropertyPopups
Definition sch_plotter.h:65
wxString m_outputDirectory
Definition sch_plotter.h:70
bool m_pngAntialias
Definition sch_plotter.h:78
wxString m_outputFile
Definition sch_plotter.h:71
bool m_blackAndWhite
Definition sch_plotter.h:62
wxString m_variant
Definition sch_plotter.h:72
bool m_PDFHierarchicalLinks
Definition sch_plotter.h:66
bool m_useBackgroundColor
Definition sch_plotter.h:64
bool m_plotDrawingSheet
Definition sch_plotter.h:58
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.