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 return CLI::EXIT_CODES::OK;
404}
405
406
408{
409 JOB_EXPORT_SCH_NETLIST* aNetJob = dynamic_cast<JOB_EXPORT_SCH_NETLIST*>( aJob );
410
411 wxCHECK( aNetJob, CLI::EXIT_CODES::ERR_UNKNOWN );
412
413 SCHEMATIC* sch = getSchematic( aNetJob->m_filename );
414
415 if( !sch )
417
418 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
419 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
420
421 // Apply variant if specified
422 if( !aNetJob->m_variantNames.empty() )
423 {
424 // For netlist export, we use the first variant name from the set
425 wxString variantName = *aNetJob->m_variantNames.begin();
426
427 if( variantName != wxS( "all" ) )
428 sch->SetCurrentVariant( variantName );
429 }
430
431 // Annotation warning check
432 SCH_REFERENCE_LIST referenceList;
433 sch->Hierarchy().GetSymbols( referenceList );
434
435 if( referenceList.GetCount() > 0 )
436 {
437 if( referenceList.CheckAnnotation(
438 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
439 {
440 // We're only interested in the end result -- either errors or not
441 } )
442 > 0 )
443 {
444 m_reporter->Report( _( "Warning: schematic has annotation errors, please use the "
445 "schematic editor to fix them\n" ),
447 }
448 }
449
450 // Test duplicate sheet names:
451 ERC_TESTER erc( sch );
452
453 if( erc.TestDuplicateSheetNames( false ) > 0 )
454 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
455
456 std::unique_ptr<NETLIST_EXPORTER_BASE> helper;
457 unsigned netlistOption = 0;
458
459 wxString fileExt;
460
461 switch( aNetJob->format )
462 {
465 helper = std::make_unique<NETLIST_EXPORTER_KICAD>( sch );
466 break;
467
470 helper = std::make_unique<NETLIST_EXPORTER_ORCADPCB2>( sch );
471 break;
472
475 helper = std::make_unique<NETLIST_EXPORTER_CADSTAR>( sch );
476 break;
477
481 helper = std::make_unique<NETLIST_EXPORTER_SPICE>( sch );
482 break;
483
486 helper = std::make_unique<NETLIST_EXPORTER_SPICE_MODEL>( sch );
487 break;
488
490 fileExt = wxS( "xml" );
491 helper = std::make_unique<NETLIST_EXPORTER_XML>( sch );
492 break;
493
495 fileExt = wxS( "asc" );
496 helper = std::make_unique<NETLIST_EXPORTER_PADS>( sch );
497 break;
498
500 fileExt = wxS( "txt" );
501 helper = std::make_unique<NETLIST_EXPORTER_ALLEGRO>( sch );
502 break;
503
504 default:
505 m_reporter->Report( _( "Unknown netlist format.\n" ), RPT_SEVERITY_ERROR );
507 }
508
509 if( aNetJob->GetConfiguredOutputPath().IsEmpty() )
510 {
511 wxFileName fn = sch->GetFileName();
512 fn.SetName( fn.GetName() );
513 fn.SetExt( fileExt );
514
515 aNetJob->SetConfiguredOutputPath( fn.GetFullName() );
516 }
517
518 wxString outPath = aNetJob->GetFullOutputPath( &sch->Project() );
519
520 if( !PATHS::EnsurePathExists( outPath, true ) )
521 {
522 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
524 }
525
526 bool res = helper->WriteNetlist( outPath, netlistOption, *m_reporter );
527
528 if( !res )
530
531 return CLI::EXIT_CODES::OK;
532}
533
534
536{
537 JOB_EXPORT_SCH_BOM* aBomJob = dynamic_cast<JOB_EXPORT_SCH_BOM*>( aJob );
538
539 wxCHECK( aBomJob, CLI::EXIT_CODES::ERR_UNKNOWN );
540
541 SCHEMATIC* sch = getSchematic( aBomJob->m_filename );
542
543 if( !sch )
545
546 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
547 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
548
549 wxString currentVariant;
550
551 if( !aBomJob->m_variantNames.empty() )
552 {
553 currentVariant = aBomJob->m_variantNames.front();
554
555 if( currentVariant != wxS( "all" ) )
556 sch->SetCurrentVariant( currentVariant );
557 }
558
559 // Annotation warning check
560 SCH_REFERENCE_LIST referenceList;
561 sch->Hierarchy().GetSymbols( referenceList, false, false );
562
563 if( referenceList.GetCount() > 0 )
564 {
565 SCH_REFERENCE_LIST copy = referenceList;
566
567 // Check annotation splits references...
568 if( copy.CheckAnnotation(
569 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
570 {
571 // We're only interested in the end result -- either errors or not
572 } )
573 > 0 )
574 {
575 m_reporter->Report(
576 _( "Warning: schematic has annotation errors, please use the schematic "
577 "editor to fix them\n" ),
579 }
580 }
581
582 // Test duplicate sheet names:
583 ERC_TESTER erc( sch );
584
585 if( erc.TestDuplicateSheetNames( false ) > 0 )
586 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
587
588 // Build our data model
589 FIELDS_EDITOR_GRID_DATA_MODEL dataModel( referenceList, nullptr );
590
591 // Mandatory fields first
592 for( FIELD_T fieldId : MANDATORY_FIELDS )
593 {
594 dataModel.AddColumn( GetCanonicalFieldName( fieldId ),
595 GetDefaultFieldName( fieldId, DO_TRANSLATE ), false, currentVariant );
596 }
597
598 // Generated/virtual fields (e.g. ${QUANTITY}, ${ITEM_NUMBER}) present only in the fields table
601 false, currentVariant );
604 false, currentVariant );
605
606 // Attribute fields (boolean flags on symbols)
607 dataModel.AddColumn( wxS( "${DNP}" ), GetGeneratedFieldDisplayName( wxS( "${DNP}" ) ),
608 false, currentVariant );
609 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_BOM}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_BOM}" ) ),
610 false, currentVariant );
611 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_BOARD}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_BOARD}" ) ),
612 false, currentVariant );
613 dataModel.AddColumn( wxS( "${EXCLUDE_FROM_SIM}" ), GetGeneratedFieldDisplayName( wxS( "${EXCLUDE_FROM_SIM}" ) ),
614 false, currentVariant );
615
616 // User field names in symbols second
617 std::set<wxString> userFieldNames;
618
619 for( size_t i = 0; i < referenceList.GetCount(); ++i )
620 {
621 SCH_SYMBOL* symbol = referenceList[i].GetSymbol();
622
623 for( SCH_FIELD& field : symbol->GetFields() )
624 {
625 if( !field.IsMandatory() && !field.IsPrivate() )
626 userFieldNames.insert( field.GetName() );
627 }
628 }
629
630 for( const wxString& fieldName : userFieldNames )
631 dataModel.AddColumn( fieldName, GetGeneratedFieldDisplayName( fieldName ), true, currentVariant );
632
633 // Add any templateFieldNames which aren't already present in the userFieldNames
634 for( const TEMPLATE_FIELDNAME& templateFieldname :
636 {
637 if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
638 {
639 dataModel.AddColumn( templateFieldname.m_Name, GetGeneratedFieldDisplayName( templateFieldname.m_Name ),
640 false, currentVariant );
641 }
642 }
643
644 BOM_PRESET preset;
645
646 // Load a preset if one is specified
647 if( !aBomJob->m_bomPresetName.IsEmpty() )
648 {
649 // Find the preset
650 const BOM_PRESET* schPreset = nullptr;
651
652 for( const BOM_PRESET& p : BOM_PRESET::BuiltInPresets() )
653 {
654 if( p.name == aBomJob->m_bomPresetName )
655 {
656 schPreset = &p;
657 break;
658 }
659 }
660
661 for( const BOM_PRESET& p : sch->Settings().m_BomPresets )
662 {
663 if( p.name == aBomJob->m_bomPresetName )
664 {
665 schPreset = &p;
666 break;
667 }
668 }
669
670 if( !schPreset )
671 {
672 m_reporter->Report( wxString::Format( _( "BOM preset '%s' not found" ) + wxS( "\n" ),
673 aBomJob->m_bomPresetName ),
675
677 }
678
679 preset = *schPreset;
680 }
681 else
682 {
683 // Normalize field names so that bare generated-field tokens (e.g. "QUANTITY") are
684 // accepted alongside the canonical "${QUANTITY}" form. Shell expansion of ${VAR}
685 // inside double quotes silently produces an empty string, so this also guards against
686 // that common CLI pitfall.
687 auto normalizeFieldName = [&dataModel]( const wxString& aName ) -> wxString
688 {
689 if( aName.IsEmpty() )
690 return wxEmptyString;
691
692 if( IsGeneratedField( aName ) )
693 return aName;
694
695 wxString wrapped = wxS( "${" ) + aName + wxS( "}" );
696
697 if( IsGeneratedField( wrapped ) && dataModel.GetFieldNameCol( wrapped ) != -1 )
698 return wrapped;
699
700 return aName;
701 };
702
703 size_t i = 0;
704
705 for( const wxString& rawFieldName : aBomJob->m_fieldsOrdered )
706 {
707 wxString fieldName = normalizeFieldName( rawFieldName );
708
709 if( fieldName.IsEmpty() )
710 {
711 i++;
712 continue;
713 }
714
715 // Handle wildcard. We allow the wildcard anywhere in the list, but it needs to respect
716 // fields that come before and after the wildcard.
717 if( fieldName == wxS( "*" ) )
718 {
719 for( const BOM_FIELD& modelField : dataModel.GetFieldsOrdered() )
720 {
721 struct BOM_FIELD field;
722
723 field.name = modelField.name;
724 field.show = true;
725 field.groupBy = false;
726 field.label = field.name;
727
728 bool fieldAlreadyPresent = false;
729
730 for( BOM_FIELD& presetField : preset.fieldsOrdered )
731 {
732 if( presetField.name == field.name )
733 {
734 fieldAlreadyPresent = true;
735 break;
736 }
737 }
738
739 bool fieldLaterInList = false;
740
741 for( const wxString& fieldInList : aBomJob->m_fieldsOrdered )
742 {
743 if( normalizeFieldName( fieldInList ) == field.name )
744 {
745 fieldLaterInList = true;
746 break;
747 }
748 }
749
750 if( !fieldAlreadyPresent && !fieldLaterInList )
751 preset.fieldsOrdered.emplace_back( field );
752 }
753
754 continue;
755 }
756
757 struct BOM_FIELD field;
758
759 field.name = fieldName;
760 field.show = !fieldName.StartsWith( wxT( "__" ), &field.name );
761
762 field.groupBy = alg::contains( aBomJob->m_fieldsGroupBy, field.name )
763 || alg::contains( aBomJob->m_fieldsGroupBy, rawFieldName );
764
765 if( ( aBomJob->m_fieldsLabels.size() > i ) && !aBomJob->m_fieldsLabels[i].IsEmpty() )
766 field.label = aBomJob->m_fieldsLabels[i];
767 else if( IsGeneratedField( field.name ) )
768 field.label = GetGeneratedFieldDisplayName( field.name );
769 else
770 field.label = field.name;
771
772 preset.fieldsOrdered.emplace_back( field );
773 i++;
774 }
775
776 preset.sortAsc = aBomJob->m_sortAsc;
777 preset.sortField = normalizeFieldName( aBomJob->m_sortField );
778 preset.filterString = aBomJob->m_filterString;
779 preset.groupSymbols = aBomJob->m_groupSymbols;
780 preset.excludeDNP = aBomJob->m_excludeDNP;
781 }
782
783 BOM_FMT_PRESET fmt;
784
785 // Load a format preset if one is specified
786 if( !aBomJob->m_bomFmtPresetName.IsEmpty() )
787 {
788 std::optional<BOM_FMT_PRESET> schFmtPreset;
789
791 {
792 if( p.name == aBomJob->m_bomFmtPresetName )
793 {
794 schFmtPreset = p;
795 break;
796 }
797 }
798
799 for( const BOM_FMT_PRESET& p : sch->Settings().m_BomFmtPresets )
800 {
801 if( p.name == aBomJob->m_bomFmtPresetName )
802 {
803 schFmtPreset = p;
804 break;
805 }
806 }
807
808 if( !schFmtPreset )
809 {
810 m_reporter->Report( wxString::Format( _( "BOM format preset '%s' not found" ) + wxS( "\n" ),
811 aBomJob->m_bomFmtPresetName ),
813
815 }
816
817 fmt = *schFmtPreset;
818 }
819 else
820 {
821 fmt.fieldDelimiter = aBomJob->m_fieldDelimiter;
822 fmt.stringDelimiter = aBomJob->m_stringDelimiter;
823 fmt.refDelimiter = aBomJob->m_refDelimiter;
825 fmt.keepTabs = aBomJob->m_keepTabs;
826 fmt.keepLineBreaks = aBomJob->m_keepLineBreaks;
827 }
828
829 if( aBomJob->GetConfiguredOutputPath().IsEmpty() )
830 {
831 wxFileName fn = sch->GetFileName();
832 fn.SetName( fn.GetName() );
833 fn.SetExt( FILEEXT::CsvFileExtension );
834
835 aBomJob->SetConfiguredOutputPath( fn.GetFullName() );
836 }
837
838 wxString configuredPath = aBomJob->GetConfiguredOutputPath();
839 bool hasVariantPlaceholder = configuredPath.Contains( wxS( "${VARIANT}" ) );
840
841 // Determine which variants to process
842 std::vector<wxString> variantsToProcess;
843
844 if( aBomJob->m_variantNames.size() > 1 && hasVariantPlaceholder )
845 {
846 variantsToProcess = aBomJob->m_variantNames;
847 }
848 else
849 {
850 variantsToProcess.push_back( currentVariant );
851 }
852
853 for( const wxString& variantName : variantsToProcess )
854 {
855 std::vector<wxString> singleVariant = { variantName };
856 dataModel.SetVariantNames( singleVariant );
857 dataModel.SetCurrentVariant( variantName );
858 dataModel.ApplyBomPreset( preset, variantName );
859
860 wxString outPath;
861
862 if( hasVariantPlaceholder )
863 {
864 wxString variantPath = configuredPath;
865 variantPath.Replace( wxS( "${VARIANT}" ), variantName );
866 aBomJob->SetConfiguredOutputPath( variantPath );
867 outPath = aBomJob->GetFullOutputPath( &sch->Project() );
868 aBomJob->SetConfiguredOutputPath( configuredPath );
869 }
870 else
871 {
872 outPath = aBomJob->GetFullOutputPath( &sch->Project() );
873 }
874
875 if( !PATHS::EnsurePathExists( outPath, true ) )
876 {
877 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
879 }
880
881 wxFile f;
882
883 if( !f.Open( outPath, wxFile::write ) )
884 {
885 m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ), outPath ),
887
889 }
890
891 bool res = f.Write( dataModel.Export( fmt ) );
892
893 if( !res )
895
896 m_reporter->Report( wxString::Format( _( "Wrote bill of materials to '%s'." ), outPath ),
898 }
899
900 return CLI::EXIT_CODES::OK;
901}
902
903
905{
906 JOB_EXPORT_SCH_PYTHONBOM* aNetJob = dynamic_cast<JOB_EXPORT_SCH_PYTHONBOM*>( aJob );
907
908 wxCHECK( aNetJob, CLI::EXIT_CODES::ERR_UNKNOWN );
909
910 SCHEMATIC* sch = getSchematic( aNetJob->m_filename );
911
912 if( !sch )
914
915 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
916 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
917
918 // Annotation warning check
919 SCH_REFERENCE_LIST referenceList;
920 sch->Hierarchy().GetSymbols( referenceList );
921
922 if( referenceList.GetCount() > 0 )
923 {
924 if( referenceList.CheckAnnotation(
925 []( ERCE_T, const wxString&, SCH_REFERENCE*, SCH_REFERENCE* )
926 {
927 // We're only interested in the end result -- either errors or not
928 } )
929 > 0 )
930 {
931 m_reporter->Report( _( "Warning: schematic has annotation errors, please use the "
932 "schematic editor to fix them\n" ),
934 }
935 }
936
937 // Test duplicate sheet names:
938 ERC_TESTER erc( sch );
939
940 if( erc.TestDuplicateSheetNames( false ) > 0 )
941 m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING );
942
943 std::unique_ptr<NETLIST_EXPORTER_XML> xmlNetlist =
944 std::make_unique<NETLIST_EXPORTER_XML>( sch );
945
946 if( aNetJob->GetConfiguredOutputPath().IsEmpty() )
947 {
948 wxFileName fn = sch->GetFileName();
949 fn.SetName( fn.GetName() + "-bom" );
950 fn.SetExt( FILEEXT::XmlFileExtension );
951
952 aNetJob->SetConfiguredOutputPath( fn.GetFullName() );
953 }
954
955 wxString outPath = aNetJob->GetFullOutputPath( &sch->Project() );
956
957 if( !PATHS::EnsurePathExists( outPath, true ) )
958 {
959 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
961 }
962
963 bool res = xmlNetlist->WriteNetlist( outPath, GNL_OPT_BOM, *m_reporter );
964
965 if( !res )
967
968 m_reporter->Report( wxString::Format( _( "Wrote bill of materials to '%s'." ), outPath ),
970
971 return CLI::EXIT_CODES::OK;
972}
973
974
976 LIB_SYMBOL* symbol )
977{
978 wxCHECK( symbol, CLI::EXIT_CODES::ERR_UNKNOWN );
979
980 std::shared_ptr<LIB_SYMBOL> parent;
981 LIB_SYMBOL* symbolToPlot = symbol;
982
983 // if the symbol is an alias, then the draw items are stored in the root symbol
984 if( symbol->IsDerived() )
985 {
986 parent = symbol->GetRootSymbol();
987
988 wxCHECK( parent, CLI::EXIT_CODES::ERR_UNKNOWN );
989
990 symbolToPlot = parent.get();
991 }
992
993 // iterate from unit 1, unit 0 would be "all units" which we don't want
994 for( int unit = 1; unit < symbol->GetUnitCount() + 1; unit++ )
995 {
996 for( int bodyStyle = 1; bodyStyle <= symbol->GetBodyStyleCount(); ++bodyStyle )
997 {
998 wxString filename;
999 wxFileName fn;
1000
1001 fn.SetPath( aSvgJob->m_outputDirectory );
1002 fn.SetExt( FILEEXT::SVGFileExtension );
1003
1004 filename = symbol->GetName();
1005
1006 for( wxChar c : wxFileName::GetForbiddenChars( wxPATH_DOS ) )
1007 filename.Replace( c, ' ' );
1008
1009 // Even single units get a unit number in the filename. This simplifies the
1010 // handling of the files as they have a uniform pattern.
1011 // Also avoids aliasing 'sym', unit 2 and 'sym_unit2', unit 1 to the same file.
1012 filename += wxString::Format( "_unit%d", unit );
1013
1014 if( symbol->HasDeMorganBodyStyles() )
1015 {
1016 if( bodyStyle == 2 )
1017 filename += wxS( "_demorgan" );
1018 }
1019 else if( bodyStyle <= (int) symbol->GetBodyStyleNames().size() )
1020 {
1021 filename += wxS( "_" ) + symbol->GetBodyStyleNames()[bodyStyle-1].Lower();
1022 }
1023
1024 fn.SetName( filename );
1025 m_reporter->Report( wxString::Format( _( "Plotting symbol '%s' unit %d to '%s'\n" ),
1026 symbol->GetName(),
1027 unit,
1028 fn.GetFullPath() ),
1030
1031 // Get the symbol bounding box to fit the plot page to it
1032 BOX2I symbolBB = symbol->Flatten()->GetUnitBoundingBox( unit, bodyStyle,
1033 !aSvgJob->m_includeHiddenFields );
1034 PAGE_INFO pageInfo( PAGE_SIZE_TYPE::User );
1035 pageInfo.SetHeightMils( schIUScale.IUToMils( symbolBB.GetHeight() * 1.2 ) );
1036 pageInfo.SetWidthMils( schIUScale.IUToMils( symbolBB.GetWidth() * 1.2 ) );
1037
1038 SVG_PLOTTER* plotter = new SVG_PLOTTER();
1039 plotter->SetRenderSettings( aRenderSettings );
1040 plotter->SetPageSettings( pageInfo );
1041 plotter->SetColorMode( !aSvgJob->m_blackAndWhite );
1042
1043 VECTOR2I plot_offset = symbolBB.GetCenter();
1044 const double scale = 1.0;
1045
1046 // Currently, plot units are in decimal
1047 plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, scale, false );
1048
1049 plotter->SetCreator( wxT( "Eeschema-SVG" ) );
1050
1051 if( !plotter->OpenFile( fn.GetFullPath() ) )
1052 {
1053 m_reporter->Report( wxString::Format( _( "Unable to open destination '%s'" ) + wxS( "\n" ),
1054 fn.GetFullPath() ),
1056
1057 delete plotter;
1059 }
1060
1061 LOCALE_IO toggle;
1062 SCH_PLOT_OPTS plotOpts;
1063
1064 plotter->StartPlot( wxT( "1" ) );
1065
1066 bool background = true;
1067 VECTOR2I offset( pageInfo.GetWidthIU( schIUScale.IU_PER_MILS ) / 2,
1068 pageInfo.GetHeightIU( schIUScale.IU_PER_MILS ) / 2 );
1069
1070 // note, we want the fields from the original symbol pointer (in case of non-alias)
1071 symbolToPlot->Plot( plotter, background, plotOpts, unit, bodyStyle, offset, false );
1072 symbol->PlotFields( plotter, background, plotOpts, unit, bodyStyle, offset, false );
1073
1074 symbolToPlot->Plot( plotter, !background, plotOpts, unit, bodyStyle, offset, false );
1075 symbol->PlotFields( plotter, !background, plotOpts, unit, bodyStyle, offset, false );
1076
1077 plotter->EndPlot();
1078 delete plotter;
1079 }
1080 }
1081
1082 if( m_reporter->HasMessageOfSeverity( RPT_SEVERITY_ERROR ) )
1084
1085 return CLI::EXIT_CODES::OK;
1086}
1087
1088
1090{
1091 JOB_SYM_EXPORT_SVG* svgJob = dynamic_cast<JOB_SYM_EXPORT_SVG*>( aJob );
1092
1093 wxCHECK( svgJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1094
1095 wxFileName fn( svgJob->m_libraryPath );
1096 fn.MakeAbsolute();
1097
1098 SCH_IO_KICAD_SEXPR_LIB_CACHE schLibrary( fn.GetFullPath() );
1099
1100 try
1101 {
1102 schLibrary.Load();
1103 }
1104 catch( ... )
1105 {
1106 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1108 }
1109
1110 if( m_progressReporter )
1111 m_progressReporter->KeepRefreshing();
1112
1113 LIB_SYMBOL* symbol = nullptr;
1114
1115 if( !svgJob->m_symbol.IsEmpty() )
1116 {
1117 // See if the selected symbol exists
1118 symbol = schLibrary.GetSymbol( svgJob->m_symbol );
1119
1120 if( !symbol )
1121 {
1122 m_reporter->Report( _( "There is no symbol selected to save." ) + wxS( "\n" ),
1125 }
1126 }
1127
1128 if( !svgJob->m_outputDirectory.IsEmpty() && !wxDir::Exists( svgJob->m_outputDirectory ) )
1129 {
1130 if( !wxFileName::Mkdir( svgJob->m_outputDirectory ) )
1131 {
1132 m_reporter->Report( wxString::Format( _( "Unable to create output directory '%s'." ) + wxS( "\n" ),
1133 svgJob->m_outputDirectory ),
1136 }
1137 }
1138
1139 SCH_RENDER_SETTINGS renderSettings;
1141 renderSettings.LoadColors( cs );
1142 renderSettings.SetDefaultPenWidth( DEFAULT_LINE_WIDTH_MILS * schIUScale.IU_PER_MILS );
1143 renderSettings.m_ShowHiddenPins = svgJob->m_includeHiddenPins;
1144 renderSettings.m_ShowHiddenFields = svgJob->m_includeHiddenFields;
1145
1146 int exitCode = CLI::EXIT_CODES::OK;
1147
1148 if( symbol )
1149 {
1150 exitCode = doSymExportSvg( svgJob, &renderSettings, symbol );
1151 }
1152 else
1153 {
1154 // Just plot all the symbols we can
1155 const LIB_SYMBOL_MAP& libSymMap = schLibrary.GetSymbolMap();
1156
1157 for( const auto& [name, libSymbol] : libSymMap )
1158 {
1159 if( m_progressReporter )
1160 {
1161 m_progressReporter->AdvancePhase( wxString::Format( _( "Exporting %s" ), name ) );
1162 m_progressReporter->KeepRefreshing();
1163 }
1164
1165 exitCode = doSymExportSvg( svgJob, &renderSettings, libSymbol );
1166
1167 if( exitCode != CLI::EXIT_CODES::OK )
1168 break;
1169 }
1170 }
1171
1172 return exitCode;
1173}
1174
1175
1177{
1178 JOB_SYM_UPGRADE* upgradeJob = dynamic_cast<JOB_SYM_UPGRADE*>( aJob );
1179
1180 wxCHECK( upgradeJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1181
1182 wxFileName fn( upgradeJob->m_libraryPath );
1183 fn.MakeAbsolute();
1184
1185 SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() );
1186
1187 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1188 {
1189 if( wxFile::Exists( upgradeJob->m_outputLibraryPath ) )
1190 {
1191 m_reporter->Report( _( "Output path must not conflict with existing path\n" ),
1193
1195 }
1196 }
1197 else if( fileType != SCH_IO_MGR::SCH_KICAD )
1198 {
1199 m_reporter->Report( _( "Output path must be specified to convert legacy and non-KiCad libraries\n" ),
1201
1203 }
1204
1205 if( fileType == SCH_IO_MGR::SCH_KICAD )
1206 {
1207 SCH_IO_KICAD_SEXPR_LIB_CACHE schLibrary( fn.GetFullPath() );
1208
1209 try
1210 {
1211 schLibrary.Load();
1212 }
1213 catch( ... )
1214 {
1215 m_reporter->Report( _( "Unable to load library\n" ), RPT_SEVERITY_ERROR );
1217 }
1218
1219 if( m_progressReporter )
1220 m_progressReporter->KeepRefreshing();
1221
1222 bool shouldSave =
1224
1225 if( shouldSave )
1226 {
1227 m_reporter->Report( _( "Saving symbol library in updated format\n" ), RPT_SEVERITY_ACTION );
1228
1229 try
1230 {
1231 if( !upgradeJob->m_outputLibraryPath.IsEmpty() )
1232 schLibrary.SetFileName( upgradeJob->m_outputLibraryPath );
1233
1234 schLibrary.SetModified();
1235 schLibrary.Save();
1236 }
1237 catch( ... )
1238 {
1239 m_reporter->Report( ( "Unable to save library\n" ), RPT_SEVERITY_ERROR );
1241 }
1242 }
1243 else
1244 {
1245 m_reporter->Report( _( "Symbol library was not updated\n" ), RPT_SEVERITY_ERROR );
1246 }
1247 }
1248 else
1249 {
1250 if( !SCH_IO_MGR::ConvertLibrary( nullptr, fn.GetAbsolutePath(), upgradeJob->m_outputLibraryPath ) )
1251 {
1252 m_reporter->Report( ( "Unable to convert library\n" ), RPT_SEVERITY_ERROR );
1254 }
1255 }
1256
1257 return CLI::EXIT_CODES::OK;
1258}
1259
1260
1261
1263{
1264 JOB_SCH_ERC* ercJob = dynamic_cast<JOB_SCH_ERC*>( aJob );
1265
1266 wxCHECK( ercJob, CLI::EXIT_CODES::ERR_UNKNOWN );
1267
1268 SCHEMATIC* sch = getSchematic( ercJob->m_filename );
1269
1270 if( !sch )
1272
1273 aJob->SetTitleBlock( sch->RootScreen()->GetTitleBlock() );
1274 sch->Project().ApplyTextVars( aJob->GetVarOverrides() );
1275
1276 if( ercJob->GetConfiguredOutputPath().IsEmpty() )
1277 {
1278 wxFileName fn = sch->GetFileName();
1279 fn.SetName( fn.GetName() + wxS( "-erc" ) );
1280
1282 fn.SetExt( FILEEXT::JsonFileExtension );
1283 else
1284 fn.SetExt( FILEEXT::ReportFileExtension );
1285
1286 ercJob->SetConfiguredOutputPath( fn.GetFullName() );
1287 }
1288
1289 wxString outPath = ercJob->GetFullOutputPath( &sch->Project() );
1290
1291 if( !PATHS::EnsurePathExists( outPath, true ) )
1292 {
1293 m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR );
1295 }
1296
1297 EDA_UNITS units;
1298
1299 switch( ercJob->m_units )
1300 {
1301 case JOB_SCH_ERC::UNITS::INCH: units = EDA_UNITS::INCH; break;
1302 case JOB_SCH_ERC::UNITS::MILS: units = EDA_UNITS::MILS; break;
1303 case JOB_SCH_ERC::UNITS::MM: units = EDA_UNITS::MM; break;
1304 default: units = EDA_UNITS::MM; break;
1305 }
1306
1307 std::shared_ptr<SHEETLIST_ERC_ITEMS_PROVIDER> markersProvider =
1308 std::make_shared<SHEETLIST_ERC_ITEMS_PROVIDER>( sch );
1309
1310 // Running ERC requires libraries be loaded, so make sure they have been
1312 adapter->AsyncLoad();
1313 adapter->BlockUntilLoaded();
1314
1315 ERC_TESTER ercTester( sch );
1316
1317 std::unique_ptr<DS_PROXY_VIEW_ITEM> drawingSheet( getDrawingSheetProxyView( sch ) );
1318 ercTester.RunTests( drawingSheet.get(), nullptr, m_kiway->KiFACE( KIWAY::FACE_CVPCB ),
1319 &sch->Project(), m_progressReporter );
1320
1321 markersProvider->SetSeverities( ercJob->m_severity );
1322
1323 m_reporter->Report( wxString::Format( _( "Found %d violations\n" ), markersProvider->GetCount() ),
1325
1326 ERC_REPORT reportWriter( sch, units, markersProvider );
1327
1328 bool wroteReport = false;
1329
1331 wroteReport = reportWriter.WriteJsonReport( outPath );
1332 else
1333 wroteReport = reportWriter.WriteTextReport( outPath );
1334
1335 if( !wroteReport )
1336 {
1337 m_reporter->Report( wxString::Format( _( "Unable to save ERC report to %s\n" ), outPath ),
1340 }
1341
1342 m_reporter->Report( wxString::Format( _( "Saved ERC Report to %s\n" ), outPath ),
1344
1345 if( ercJob->m_exitCodeViolations )
1346 {
1347 if( markersProvider->GetCount() > 0 )
1349 }
1350
1352}
1353
1354
1356{
1357 JOB_SCH_UPGRADE* aUpgradeJob = dynamic_cast<JOB_SCH_UPGRADE*>( aJob );
1358
1359 if( aUpgradeJob == nullptr )
1361
1362 SCHEMATIC* sch = getSchematic( aUpgradeJob->m_filename );
1363
1364 if( !sch )
1366
1367 bool shouldSave = aUpgradeJob->m_force;
1368
1370 shouldSave = true;
1371
1372 if( !shouldSave )
1373 {
1374 m_reporter->Report( _( "Schematic file was not updated\n" ), RPT_SEVERITY_ERROR );
1376 }
1377
1378 // needs an absolute path
1379 wxFileName schPath( aUpgradeJob->m_filename );
1380 schPath.MakeAbsolute();
1381 const wxString schFullPath = schPath.GetFullPath();
1382
1383 try
1384 {
1385 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
1386 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( schFullPath, sch );
1387 pi->SaveSchematicFile( schFullPath, loadedSheet, sch );
1388 }
1389 catch( const IO_ERROR& ioe )
1390 {
1391 wxString msg =
1392 wxString::Format( _( "Error saving schematic file '%s'.\n%s" ), schFullPath, ioe.What().GetData() );
1393 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
1395 }
1396
1397 m_reporter->Report( _( "Successfully saved schematic file using the latest format\n" ), RPT_SEVERITY_INFO );
1398
1400}
1401
1402
1404{
1405 DS_PROXY_VIEW_ITEM* drawingSheet =
1407 &aSch->Project(), &aSch->RootScreen()->GetTitleBlock(),
1408 aSch->GetProperties() );
1409
1410 drawingSheet->SetPageNumber( TO_UTF8( aSch->RootScreen()->GetPageNumber() ) );
1411 drawingSheet->SetSheetCount( aSch->RootScreen()->GetPageCount() );
1412 drawingSheet->SetFileName( TO_UTF8( aSch->RootScreen()->GetFileName() ) );
1415 drawingSheet->SetIsFirstPage( aSch->RootScreen()->GetVirtualPageNumber() == 1 );
1416
1417 drawingSheet->SetSheetName( "" );
1418 drawingSheet->SetSheetPath( "" );
1419
1420 return drawingSheet;
1421}
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 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:2054
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
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:295
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:407
@ FACE_CVPCB
Definition kiway.h:304
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:515
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:131
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:65
virtual void ApplyTextVars(const std::map< wxString, wxString > &aVarsMap)
Applies the given var map, it will create or update existing vars.
Definition project.cpp:126
std::vector< BOM_PRESET > m_BomPresets
std::vector< BOM_FMT_PRESET > m_BomFmtPresets
Holds all the data relating to one schematic.
Definition schematic.h:88
void SetCurrentVariant(const wxString &aVariantName)
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:103
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:106
SCH_SHEET & Root() const
Definition schematic.h:132
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:496
@ LAYER_SCHEMATIC_PAGE_LIMITS
Definition layer_ids.h:497
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
SETTINGS_MANAGER * GetSettingsManager()
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:695
Definition of file extensions used in Kicad.