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