KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eeschema.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) 2004 Jean-Pierre Charras, [email protected]
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <algorithm>
23
24#include <api/api_handler_sch.h>
27#include <api/api_server.h>
28#include <api/api_utils.h>
33#include <pgm_base.h>
34#include <kiface_base.h>
37#include <confirm.h>
38#include <gestfich.h>
40#include "eeschema_helpers.h"
42#include <reporter.h>
43#include "git/kigit_sch_merge.h"
46#include <eeschema_settings.h>
47#include <footprint_filter.h>
48#include <sch_edit_frame.h>
50#include <symbol_edit_frame.h>
51#include <symbol_viewer_frame.h>
58#include <kiway.h>
59#include <project_sch.h>
60#include <richio.h>
63#include <sexpr/sexpr.h>
64#include <sexpr/sexpr_parser.h>
65#include <string_utils.h>
66#include <trace_helpers.h>
67#include <thread_pool.h>
68#include <kiface_ids.h>
70#include <widgets/kistatusbar.h>
72#include <wx/ffile.h>
73#include <wx/tokenzr.h>
75
76#include <schematic.h>
77#include <connection_graph.h>
88#include <sim/simulator_frame.h>
89
91#include <toolbars_sch_editor.h>
93
94#include <sch_io/sch_io.h>
95#include <sch_io/sch_io_mgr.h>
96
97#include <wx/crt.h>
98
99// The main sheet of the project
101
102
103namespace SCH {
104
105// Non-job kiface exports for diff/merge (returned by IfaceOrAddress). Defined
106// after the kiface instance so they can route into its jobs handler.
107static int eeschemaMergeExport( int aKind, const wxString& aAncestor, const wxString& aOurs,
108 const wxString& aTheirs, const wxString& aOutput, bool aInteractive,
109 bool aSingleFile, REPORTER* aReporter );
110static int eeschemaOpenDiffDialogExport( int aKind, const wxString& aFileA, const wxString& aFileB,
111 const wxString& aLabelA, const wxString& aLabelB,
112 wxWindow* aParent, REPORTER* aReporter );
114eeschemaAttachDiffCanvasesExport( int aKind, const wxString& aFileA, const wxString& aFileB,
115 WIDGET_DIFF_CANVAS* aBefore, WIDGET_DIFF_CANVAS* aAfter,
116 KICAD_DIFF::DOCUMENT_DIFF* aDiff, REPORTER* aReporter );
117
118
119// TODO: This should move out of this file
120static std::unique_ptr<SCHEMATIC> readSchematicFromFile( const std::string& aFilename )
121{
122 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
123 std::unique_ptr<SCHEMATIC> schematic = std::make_unique<SCHEMATIC>( nullptr );
124
126
127 wxFileName pro( aFilename );
128 pro.SetExt( FILEEXT::ProjectFileExtension );
129 pro.MakeAbsolute();
130 wxString projectPath = pro.GetFullPath();
131
132 PROJECT* project = manager.GetProject( projectPath );
133
134 if( !project )
135 {
136 manager.LoadProject( projectPath, true );
137 project = manager.GetProject( projectPath );
138 }
139
140 schematic->Reset();
141 schematic->SetProject( project );
142 SCH_SHEET* rootSheet = pi->LoadSchematicFile( aFilename, schematic.get() );
143
144 if( !rootSheet )
145 return nullptr;
146
147 std::vector<SCH_SHEET*> topLevelSheets = schematic->GetTopLevelSheets();
148 bool rootIsTopLevel = std::find( topLevelSheets.begin(), topLevelSheets.end(), rootSheet )
149 != topLevelSheets.end();
150 bool rootIsVirtualRoot = rootSheet == &schematic->Root() || rootSheet->IsVirtualRootSheet();
151
152 if( !rootIsTopLevel && !rootIsVirtualRoot )
153 schematic->SetTopLevelSheets( { rootSheet } );
154
155 SCH_SCREENS screens( schematic->Root() );
156
157 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
158 screen->UpdateLocalLibSymbolLinks();
159
160 SCH_SHEET_LIST sheets = schematic->Hierarchy();
161
162 // Restore all of the loaded symbol instances from the root sheet screen.
163 sheets.UpdateSymbolInstanceData( schematic->RootScreen()->GetSymbolInstances() );
164
165 if( schematic->RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
166 {
167 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
168 screen->FixLegacyPowerSymbolMismatches();
169 }
170
171 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
172 screen->MigrateSimModels();
173
174 // NOTE: This is required for multi-unit symbols to be correct
175 for( SCH_SHEET_PATH& sheet : sheets )
176 sheet.UpdateAllScreenReferences();
177
178 // TODO: this must handle SchematicCleanup somehow. The original version didn't because
179 // it knew that QA test cases were saved in a clean state.
180
181 // TODO: does this need to handle PruneOrphanedSymbolInstances() and
182 // PruneOrphanedSheetInstances()?
183
184 schematic->ConnectionGraph()->Recalculate( sheets, true );
185
186 return schematic;
187}
188
189
190// TODO: This should move out of this file
191bool generateSchematicNetlist( const wxString& aFilename, std::string& aNetlist, KIWAY* aKiway )
192{
193 std::unique_ptr<SCHEMATIC> schematic = readSchematicFromFile( aFilename.ToStdString() );
194
195 if( !schematic )
196 return false;
197
198 NETLIST_EXPORTER_KICAD exporter( schematic.get(), aKiway );
199 STRING_FORMATTER formatter;
200
201 exporter.Format( &formatter, GNL_ALL | GNL_OPT_KICAD );
202 aNetlist = formatter.GetString();
203
204 return true;
205}
206
207
212{
213 PROJECT* project = nullptr;
214
215 if( wxTheApp )
216 {
217 wxWindow* focus = wxWindow::FindFocus();
218 wxWindow* top = focus ? wxGetTopLevelParent( focus ) : wxTheApp->GetTopWindow();
219
220 if( top )
221 {
222 if( KIWAY_HOLDER* holder = dynamic_cast<KIWAY_HOLDER*>( top ) )
223 project = &holder->Prj();
224 }
225 }
226
227 if( !project )
229
230 return project;
231}
232
244static bool footprintReferenceMatches( const LIB_ID& aReference, const LIB_ID& aFootprint )
245{
246 if( !aReference.GetUniStringLibItemName().IsSameAs( aFootprint.GetUniStringLibItemName(), false ) )
247 return false;
248
249 if( !aReference.GetLibNickname().empty() && !aFootprint.GetLibNickname().empty()
250 && !aReference.GetUniStringLibNickname().IsSameAs( aFootprint.GetUniStringLibNickname(), false ) )
251 {
252 return false;
253 }
254
255 return true;
256}
257
258
260
264static bool symbolFilterMatchesFootprint( const LIB_SYMBOL& aSymbol, const LIB_ID& aFootprint,
265 FOOTPRINT_USER_MATCH& aMatch )
266{
267 for( const wxString& filter : aSymbol.GetFPFilters() )
268 {
269 if( filter.IsEmpty() )
270 continue;
271
273 matcher.SetPattern( filter.Lower() );
275 if( FootprintFilterMatchesName( matcher, aFootprint.GetUniStringLibNickname(),
276 aFootprint.GetUniStringLibItemName() ) )
277 {
279 return true;
280 }
281 }
283 return false;
284}
286
293static wxString effectiveFootprintText( const LIB_SYMBOL& aSymbol )
294{
295 if( const SCH_FIELD* field = aSymbol.GetField( FIELD_T::FOOTPRINT ) )
296 {
297 if( !field->GetText().IsEmpty() )
298 return field->GetText();
301 if( std::shared_ptr<LIB_SYMBOL> parent = aSymbol.GetParent().lock() )
302 return effectiveFootprintText( *parent );
304 return wxEmptyString;
305}
317static bool symbolPinMapsBindFootprint( const LIB_SYMBOL& aSymbol, const LIB_ID& aFootprint,
318 FOOTPRINT_USER_MATCH& aMatch )
319{
320 for( const ASSOCIATED_FOOTPRINT& associated : aSymbol.GetEffectiveAssociatedFootprints() )
321 {
322 // A symbol can bind several maps, to the same footprint or to different ones.
323 if( footprintReferenceMatches( associated.m_FootprintLibId, aFootprint ) )
324 aMatch.m_MatchedPinMaps.push_back( associated.m_MapName );
325 }
326
327 return !aMatch.m_MatchedPinMaps.empty();
328}
329
330
335static bool symbolFootprintFieldNamesFootprint( const LIB_SYMBOL& aSymbol, const LIB_ID& aFootprint,
336 FOOTPRINT_USER_MATCH& aMatch )
337{
338 LIB_ID fieldId;
339
340 if( fieldId.Parse( effectiveFootprintText( aSymbol ) ) == -1
341 && footprintReferenceMatches( fieldId, aFootprint ) )
342 {
343 aMatch.m_MatchesFootprintField = true;
344 return true;
345 }
346
347 return false;
348}
349
350
359static std::optional<FOOTPRINT_USER_MATCH> symbolUsesFootprint( const LIB_SYMBOL& aSymbol,
360 const LIB_ID& aFootprint )
361{
363 match.m_Symbol = aSymbol.GetLibId();
364
365 // Every predicate is evaluated: the match feeds the filter and the two flags alike.
366 const bool byFilter = symbolFilterMatchesFootprint( aSymbol, aFootprint, match );
367 const bool byField = symbolFootprintFieldNamesFootprint( aSymbol, aFootprint, match );
368 const bool byPinMap = symbolPinMapsBindFootprint( aSymbol, aFootprint, match );
369
370 if( !byFilter && !byField && !byPinMap )
371 return std::nullopt;
372
373 match.m_PinCount = aSymbol.GetPinCount();
374 match.m_IsDerived = aSymbol.IsDerived();
375
376 return match;
377}
378
379
394static wxString filterFootprintUsers( const wxString& aQueryJson )
395{
397 result.m_Success = false;
398
399 try
400 {
402
403 // A footprint with no item name cannot be referred to by a filter, field or
404 // association, so the query is a successful, empty one.
405 if( query.m_Footprint.GetLibItemName().empty() )
406 {
407 result.m_Success = true;
408 return result.ToJsonStr();
409 }
410
411 // No enabled way of using the footprint can match anything, so the query is a
412 // successful, empty one.
413 if( !query.m_MatchFilters && !query.m_MatchFootprintField && !query.m_MatchPinMaps )
414 {
415 result.m_Success = true;
416 return result.ToJsonStr();
417 }
418
420
421 if( !adapter )
422 return result.ToJsonStr();
423
424 adapter->AsyncLoad();
425 adapter->BlockUntilLoaded();
426
427 for( const wxString& nickname : adapter->GetLibraryNames() )
428 {
429 for( LIB_SYMBOL* symbol : adapter->GetSymbols( nickname ) )
430 {
431 if( !symbol )
432 continue;
433
434 std::optional<FOOTPRINT_USER_MATCH> match = symbolUsesFootprint( *symbol, query.m_Footprint );
435
436 if( !match )
437 continue;
438
439 const bool byFilter = query.m_MatchFilters && !match->m_MatchedFilter.IsEmpty();
440 const bool byField = query.m_MatchFootprintField && match->m_MatchesFootprintField;
441 const bool byPinMap = query.m_MatchPinMaps && !match->m_MatchedPinMaps.empty();
442
443 if( !byFilter && !byField && !byPinMap )
444 continue;
445
446 if( query.m_MaxResults > 0 && static_cast<int>( result.m_Matches.size() ) >= query.m_MaxResults )
447 {
448 result.m_IsLimited = true;
449 break;
450 }
451
452 result.m_Matches.push_back( std::move( *match ) );
453 }
454
455 if( result.m_IsLimited )
456 break;
457 }
458
459 result.m_Success = true;
460
461 return result.ToJsonStr();
462 }
463 catch( const std::exception& )
464 {
465 // A failure carries no matches, even if the scan had already collected some.
466 result.m_Matches.clear();
467 result.m_Success = false;
468 return result.ToJsonStr();
469 }
470}
471
472
477{
479
480 if( adapter )
481 {
482 adapter->AsyncLoad();
483 return true;
484 }
485
486 return false;
487}
488
489
497{
499
500 if( !adapter )
501 return 1.0f;
502
503 // Nothing to report means there is nothing to wait for.
504 if( std::optional<float> progress = adapter->AsyncLoadProgress() )
505 return *progress;
506
507 return 1.0f;
508}
509
510
511static struct IFACE : public KIFACE_BASE, public UNITS_PROVIDER
512{
513 // Of course all are virtual overloads, implementations of the KIFACE.
514
515 IFACE( const char* aName, KIWAY::FACE_T aType ) :
516 KIFACE_BASE( aName, aType ),
519 {}
520
521 bool OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway ) override;
522
523 void Reset() override;
524
525 void OnKifaceEnd() override;
526
527 wxWindow* CreateKiWindow( wxWindow* aParent, int aClassId, KIWAY* aKiway, int aCtlBits = 0 ) override
528 {
529 switch( aClassId )
530 {
531 case FRAME_SCH:
532 {
533 SCH_EDIT_FRAME* frame = new SCH_EDIT_FRAME( aKiway, aParent );
534
536
537 if( Kiface().IsSingle() )
538 {
539 // only run this under single_top, not under a project manager.
542 }
543
544 return frame;
545 }
546
548 return new SYMBOL_EDIT_FRAME( aKiway, aParent );
549
550 case FRAME_SIMULATOR:
551 {
552 try
553 {
554 SIMULATOR_FRAME* frame = new SIMULATOR_FRAME( aKiway, aParent );
555 return frame;
556 }
557 catch( const SIMULATOR_INIT_ERR& )
558 {
559 // catch the init err exception as we don't want it to bubble up
560 // its going to be some ngspice install issue but we don't want to log that
561 return nullptr;
562 }
563 }
564
565 case FRAME_SCH_VIEWER:
566 return new SYMBOL_VIEWER_FRAME( aKiway, aParent );
567
569 {
570 bool cancelled = false;
571 SYMBOL_CHOOSER_FRAME* chooser = new SYMBOL_CHOOSER_FRAME( aKiway, aParent, cancelled );
572
573 if( cancelled )
574 {
575 chooser->Destroy();
576 return nullptr;
577 }
578
579 return chooser;
580 }
581
583 InvokeSchEditSymbolLibTable( aKiway, aParent );
584 // Dialog has completed; nothing to return.
585 return nullptr;
586
588 InvokeEditDesignBlockLibTable( aKiway, aParent );
589 // Dialog has completed; nothing to return.
590 return nullptr;
591
593 return new PANEL_SYM_DISPLAY_OPTIONS( aParent, GetAppSettings<SYMBOL_EDITOR_SETTINGS>( "symbol_editor" ) );
594
596 {
598 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
599
600 if( !frame )
601 frame = aKiway->Player( FRAME_SCH_VIEWER, false );
602
603 if( !frame )
604 frame = aKiway->Player( FRAME_SCH, false );
605
606 if( frame )
607 SetUserUnits( frame->GetUserUnits() );
608
609 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_SCH_SYMBOL_EDITOR );
610 }
611
613 return CreateSnappingPanel( aParent, GetAppSettings<SYMBOL_EDITOR_SETTINGS>( "symbol_editor" ),
615
617 {
618 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
619
620 if( !frame )
621 frame = aKiway->Player( FRAME_SCH_VIEWER, false );
622
623 if( !frame )
624 frame = aKiway->Player( FRAME_SCH, false );
625
626 if( frame )
627 SetUserUnits( frame->GetUserUnits() );
628
629 return new PANEL_SYM_EDITING_OPTIONS( aParent, this, frame );
630 }
631
633 {
636
637 std::vector<TOOL_ACTION*> actions;
638 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
639
641 actions.push_back( action );
642
644 controls.push_back( control );
645
646 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, FRAME_SCH_SYMBOL_EDITOR, actions, controls );
647 }
648
649 case PANEL_SYM_COLORS:
650 return new PANEL_SYM_COLOR_SETTINGS( aParent );
651
653 return new PANEL_EESCHEMA_DISPLAY_OPTIONS( aParent, GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" ) );
654
655 case PANEL_SCH_GRIDS:
656 {
658 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_SCH, false );
659
660 if( !frame )
661 frame = aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
662
663 if( !frame )
664 frame = aKiway->Player( FRAME_SCH_VIEWER, false );
665
666 if( frame )
667 SetUserUnits( frame->GetUserUnits() );
668
669 return new PANEL_GRID_SETTINGS( aParent, this, frame, cfg, FRAME_SCH );
670 }
671
675
677 {
678 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_SCH, false );
679
680 if( !frame )
681 frame = aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
682
683 if( !frame )
684 frame = aKiway->Player( FRAME_SCH_VIEWER, false );
685
686 if( frame )
687 SetUserUnits( frame->GetUserUnits() );
688
689 return new PANEL_EESCHEMA_EDITING_OPTIONS( aParent, this, frame );
690 }
691
693 {
696
697 std::vector<TOOL_ACTION*> actions;
698 std::vector<ACTION_TOOLBAR_CONTROL*> controls;
699
701 actions.push_back( action );
702
704 controls.push_back( control );
705
706 return new PANEL_TOOLBAR_CUSTOMIZATION( aParent, cfg, tb, FRAME_SCH, actions, controls );
707 }
708
709 case PANEL_SCH_COLORS:
710 return new PANEL_EESCHEMA_COLOR_SETTINGS( aParent );
711
713 return new PANEL_TEMPLATE_FIELDNAMES( aParent, nullptr );
714
716 {
717 EDA_BASE_FRAME* frame = aKiway->Player( FRAME_SCH, false );
718
719 if( !frame )
720 frame = aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
721
722 if( !frame )
723 frame = aKiway->Player( FRAME_SCH_VIEWER, false );
724
725 return new class PANEL_SCH_DATA_SOURCES( aParent, frame );
726 }
727
729 return new PANEL_SIMULATOR_PREFERENCES( aParent );
730
731 default:
732 return nullptr;
733 }
734 }
735
746 void* IfaceOrAddress( int aDataId ) override
747 {
748 switch( aDataId )
749 {
751 return (void*) generateSchematicNetlist;
752
754 return reinterpret_cast<void*>( &filterFootprintUsers );
755
757 return reinterpret_cast<void*>( &startSymbolLibraryLoad );
758
760 return reinterpret_cast<void*>( &symbolLibraryLoadProgress );
761
763 return reinterpret_cast<void*>( &eeschemaMergeExport );
764
766 return reinterpret_cast<void*>( &eeschemaOpenDiffDialogExport );
767
768 case KIFACE_ATTACH_DIFF_CANVASES: return reinterpret_cast<void*>( &eeschemaAttachDiffCanvasesExport );
769 }
770
771 return nullptr;
772 }
773
776
782 void SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
783 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
784 const wxString& aSrcFilePath, wxString& aErrors ) override;
785
786
787 int HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter ) override;
788
789 bool HandleJobConfig( JOB* aJob, wxWindow* aParent ) override;
790
791 bool HandleApiOpenDocument( const DOCUMENT_SPEC& aSpec,
792 KICAD_API_SERVER* aServer,
793 wxString* aError ) override;
794
795 bool handleCreateSchematic( const wxString& aPath, KICAD_API_SERVER* aServer, wxString* aError );
796 bool handleOpenSymbol( const wxString& aProjectPath, const wxString& aLibIdStr, KICAD_API_SERVER* aServer,
797 wxString* aError );
798 bool HandleApiCloseDocument( const DOCUMENT_SPEC& aSpec,
799 KICAD_API_SERVER* aServer,
800 wxString* aError ) override;
801
802 void PreloadLibraries( KIWAY* aKiway ) override;
803 void CancelPreload( bool aBlock = true ) override;
804 void ProjectChanged() override;
805 void RegisterLibraryHandlers( KICAD_API_SERVER* aServer ) override;
806 bool LoadAllLibraries() override;
807
808
809private:
810 std::unique_ptr<EESCHEMA_JOBS_HANDLER> m_jobHandler;
811 std::shared_ptr<BACKGROUND_JOB> m_libraryPreloadBackgroundJob;
812 std::future<void> m_libraryPreloadReturn;
814 std::atomic_bool m_libraryPreloadAbort;
815
816 void closeSchematic( KICAD_API_SERVER* aServer );
817 void closeSymbol( KICAD_API_SERVER* aServer );
818
819 KIWAY* m_kiway = nullptr;
821 std::shared_ptr<HEADLESS_SCH_CONTEXT> m_openContext;
822 std::shared_ptr<HEADLESS_SYMBOL_EDITOR_CONTEXT> m_openSymbolContext;
823 std::unique_ptr<API_HANDLER_SYMBOL> m_openSymbolHandler;
824 std::unique_ptr<API_HANDLER_SCH> m_openHandler;
825 std::unique_ptr<API_HANDLER_SCH_LIBRARIES> m_apiHandlerSchLibs;
826
827} kiface( "eeschema", KIWAY::FACE_SCH );
828
829
830int eeschemaMergeExport( int aKind, const wxString& aAncestor, const wxString& aOurs,
831 const wxString& aTheirs, const wxString& aOutput, bool aInteractive,
832 bool aSingleFile, REPORTER* aReporter )
833{
834 return kiface.JobHandler()->RunMerge( static_cast<KICAD_DIFF::DOC_KIND>( aKind ), aAncestor,
835 aOurs, aTheirs, aOutput, aInteractive, aSingleFile,
836 aReporter );
837}
838
839
840int eeschemaOpenDiffDialogExport( int aKind, const wxString& aFileA, const wxString& aFileB,
841 const wxString& aLabelA, const wxString& aLabelB,
842 wxWindow* aParent, REPORTER* aReporter )
843{
844 return kiface.JobHandler()->OpenDiffDialog( static_cast<KICAD_DIFF::DOC_KIND>( aKind ), aFileA,
845 aFileB, aLabelA, aLabelB, aParent, aReporter );
846}
847
848
850 const wxString& aFileB, WIDGET_DIFF_CANVAS* aBefore,
851 WIDGET_DIFF_CANVAS* aAfter,
853 REPORTER* aReporter )
854{
855 return kiface.JobHandler()->AttachDiffCanvases( static_cast<KICAD_DIFF::DOC_KIND>( aKind ), aFileA, aFileB, aBefore,
856 aAfter, *aDiff, aReporter );
857}
858
859} // namespace
860
861using namespace SCH;
862
863
865
866
867// KIFACE_GETTER's actual spelling is a substitution macro found in kiway.h.
868// KIFACE_GETTER will not have name mangling due to declaration in kiway.h.
869KIFACE_API KIFACE* KIFACE_GETTER( int* aKIFACEversion, int aKiwayVersion, PGM_BASE* aProgram )
870{
871 return &kiface;
872}
873
874
875bool IFACE::OnKifaceStart( PGM_BASE* aProgram, int aCtlBits, KIWAY* aKiway )
876{
877 // This is process-level-initialization, not project-level-initialization of the DSO.
878 // Do nothing in here pertinent to a project!
880
881 // Register the symbol editor settings as well because they share a KiFACE and need to be
882 // loaded prior to use to avoid threading deadlocks
884 aProgram->GetSettingsManager().RegisterSettings( symSettings ); // manager takes ownership
885
886 // We intentionally register KifaceSettings after SYMBOL_EDITOR_SETTINGS
887 // In legacy configs, many settings were in a single editor config nd the migration routine
888 // for the main editor file will try and call into the now separate settings stores
889 // to move the settings into them
891
892 start_common( aCtlBits );
893
894 m_kiway = aKiway;
895
896 m_jobHandler = std::make_unique<EESCHEMA_JOBS_HANDLER>( aKiway );
897
899 {
900 m_jobHandler->SetReporter( &CLI_REPORTER::GetInstance() );
901 m_jobHandler->SetProgressReporter( &CLI_PROGRESS_REPORTER::GetInstance() );
902 }
903
904 if( Pgm().ApiServerOrNull() )
905 {
906 m_apiHandlerSchLibs = std::make_unique<API_HANDLER_SCH_LIBRARIES>();
908 }
909
910 // Register the schematic and symbol-library merge drivers with libgit2 so
911 // `.gitattributes` entries `merge=kicad-sch` and `merge=kicad-sym-lib`
912 // route through KiCad-aware merge logic.
915
916 return true;
917}
918
919
921{
922 if( m_jobHandler )
923 m_jobHandler->ClearCachedSchematic();
924
925 closeSchematic( nullptr );
926 closeSymbol( nullptr );
927}
928
929
931{
932 constexpr static int interval = 150;
933 constexpr static int timeLimit = 120000;
934
935 wxCHECK( aKiway, /* void */ );
936
937 // Use compare_exchange to atomically check and set the flag to prevent race conditions
938 // when PreloadLibraries is called multiple times concurrently (e.g., from project manager
939 // and schematic editor both scheduling via CallAfter)
940 bool expected = false;
941
942 if( !m_libraryPreloadInProgress.compare_exchange_strong( expected, true ) )
943 return;
944
946
948 Pgm().GetBackgroundJobMonitor().Create( _( "Loading Symbol Libraries" ) );
949
950 auto preload =
951 [this, aKiway]() -> void
952 {
953 std::shared_ptr<BACKGROUND_JOB_REPORTER> reporter =
955
957
958 int elapsed = 0;
959 bool aborted = false;
960
961 reporter->Report( _( "Loading Symbol Libraries" ) );
962 adapter->AsyncLoad();
963
964 while( true )
965 {
966 if( m_libraryPreloadAbort.load() )
967 {
968 m_libraryPreloadAbort.store( false );
969 aborted = true;
970 break;
971 }
972
973 std::this_thread::sleep_for( std::chrono::milliseconds( interval ) );
974
975 if( std::optional<float> loadStatus = adapter->AsyncLoadProgress() )
976 {
977 float progress = *loadStatus;
978 reporter->SetCurrentProgress( progress );
979
980 if( progress >= 1 )
981 break;
982 }
983 else
984 {
985 reporter->SetCurrentProgress( 1 );
986 break;
987 }
988
989 elapsed += interval;
990
991 if( elapsed > timeLimit )
992 break;
993 }
994
995 // AbortAsyncLoad() sets the adapter's worker abort flag and then blocks,
996 // so workers exit at their next checkpoint. BlockUntilLoaded() alone just
997 // waits for each future to complete naturally, which can hang indefinitely
998 // if a worker is stuck on a stalled network or filesystem operation.
999 if( aborted )
1000 adapter->AbortAsyncLoad();
1001 else
1002 adapter->BlockUntilLoaded();
1003
1004 // If aborted, skip operations that use the adapter since the project may have changed
1005 // and the adapter's project reference could be stale. This prevents use-after-free
1006 // crashes when switching projects during library preload.
1007 if( !aborted )
1008 {
1009 // Collect library load errors for async reporting
1011 }
1012 else
1013 {
1014 wxLogTrace( traceLibraries, "eeschema PreloadLibraries: aborted, skipping symbol processing" );
1015 }
1016
1019
1020 // Only send reload notifications if we weren't aborted
1021 if( !aborted )
1022 {
1023 std::string payload = "";
1024 aKiway->ExpressMail( FRAME_SCH, MAIL_RELOAD_LIB, payload, nullptr, true );
1025 aKiway->ExpressMail( FRAME_SCH_SYMBOL_EDITOR, MAIL_RELOAD_LIB, payload, nullptr, true );
1026 aKiway->ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload, nullptr, true );
1027 }
1028
1029 m_libraryPreloadInProgress.store( false );
1030 };
1031
1032 std::future<void> preloadFuture = std::async( std::launch::async, preload );
1033 m_libraryPreloadReturn = std::move( preloadFuture );
1034}
1035
1036
1037void IFACE::CancelPreload( bool aBlock )
1038{
1039 if( m_libraryPreloadInProgress.load() )
1040 {
1041 m_libraryPreloadAbort.store( true );
1042
1043 if( aBlock )
1045 }
1046}
1047
1048
1050{
1051 if( m_libraryPreloadInProgress.load() )
1052 m_libraryPreloadAbort.store( true );
1053}
1054
1055
1057{
1058 CancelPreload( true );
1059
1061 {
1062 if( Pgm().ApiServerOrNull() )
1064
1065 m_apiHandlerSchLibs.reset();
1066 }
1067
1068 // Release the CLI-cached schematic while the static ERC_ITEM tables it serializes against are
1069 // still alive; deferring to static teardown crashes reading dangling severity keys
1070 if( m_jobHandler )
1071 m_jobHandler->ClearCachedSchematic();
1072
1073 end_common();
1074}
1075
1076
1077void IFACE::SaveFileAs( const wxString& aProjectBasePath, const wxString& aProjectName,
1078 const wxString& aNewProjectBasePath, const wxString& aNewProjectName,
1079 const wxString& aSrcFilePath, wxString& aErrors )
1080{
1081 wxFileName destFile( aSrcFilePath );
1082 wxString destPath = destFile.GetPathWithSep();
1083 wxUniChar pathSep = wxFileName::GetPathSeparator();
1084 wxString ext = destFile.GetExt();
1085
1086 if( destPath.StartsWith( aProjectBasePath + pathSep ) )
1087 destPath.Replace( aProjectBasePath, aNewProjectBasePath, false );
1088
1089 destFile.SetPath( destPath );
1090
1095 {
1096 if( destFile.GetName() == aProjectName )
1097 {
1098 destFile.SetName( aNewProjectName );
1099 }
1100 else if( destFile.GetName() == aNewProjectName )
1101 {
1102 wxString msg;
1103
1104 if( !aErrors.empty() )
1105 aErrors += wxS( "\n" );
1106
1107 msg.Printf( _( "Cannot copy file '%s' as it will be overwritten by the new root "
1108 "sheet file." ), destFile.GetFullPath() );
1109 aErrors += msg;
1110 return;
1111 }
1112
1113 CopySexprFile( aSrcFilePath, destFile.GetFullPath(),
1114 [&]( const std::string& token, wxString& value ) -> bool
1115 {
1116 if( token == "project" && value == aProjectName )
1117 {
1118 value = aNewProjectName;
1119 return true;
1120 }
1121
1122 return false;
1123 },
1124 aErrors );
1125 }
1127 {
1128 // Symbols are not project-specific. Keep their source names.
1129 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
1130 }
1134 {
1135 if( destFile.GetName() == aProjectName + wxS( "-cache" ) )
1136 destFile.SetName( aNewProjectName + wxS( "-cache" ) );
1137
1138 if( destFile.GetName() == aProjectName + wxS( "-rescue" ) )
1139 destFile.SetName( aNewProjectName + wxS( "-rescue" ) );
1140
1141 KiCopyFile( aSrcFilePath, destFile.GetFullPath(), aErrors );
1142 }
1143 else if( ext == FILEEXT::NetlistFileExtension )
1144 {
1145 if( destFile.GetName() == aProjectName )
1146 destFile.SetName( aNewProjectName );
1147
1148 CopySexprFile( aSrcFilePath, destFile.GetFullPath(),
1149 [&]( const std::string& token, wxString& value ) -> bool
1150 {
1151 if( token == "source" )
1152 {
1153 for( const wxString& extension : { wxString( wxT( ".sch" ) ), wxString( wxT( ".kicad_sch" ) ) } )
1154 {
1155 if( value == aProjectName + extension )
1156 {
1157 value = aNewProjectName + extension;
1158 return true;
1159 }
1160 else if( value == aProjectBasePath + "/" + aProjectName + extension )
1161 {
1162 value = aNewProjectBasePath + "/" + aNewProjectName + extension;
1163 return true;
1164 }
1165 else if( value.StartsWith( aProjectBasePath ) )
1166 {
1167 value.Replace( aProjectBasePath, aNewProjectBasePath, false );
1168 return true;
1169 }
1170 }
1171 }
1172
1173 return false;
1174 },
1175 aErrors );
1176 }
1177 else if( destFile.GetName() == FILEEXT::SymbolLibraryTableFileName )
1178 {
1179 wxFileName libTableFn( aSrcFilePath );
1180 LIBRARY_TABLE libTable( libTableFn, LIBRARY_TABLE_SCOPE::PROJECT );
1181 libTable.SetPath( destFile.GetFullPath() );
1182 libTable.SetType( LIBRARY_TABLE_TYPE::SYMBOL );
1183
1184 for( LIBRARY_TABLE_ROW& row : libTable.Rows() )
1185 {
1186 wxString uri = row.URI();
1187
1188 uri.Replace( wxS( "/" ) + aProjectName + wxS( "-cache.lib" ),
1189 wxS( "/" ) + aNewProjectName + wxS( "-cache.lib" ) );
1190 uri.Replace( wxS( "/" ) + aProjectName + wxS( "-rescue.lib" ),
1191 wxS( "/" ) + aNewProjectName + wxS( "-rescue.lib" ) );
1192 uri.Replace( wxS( "/" ) + aProjectName + wxS( ".lib" ),
1193 wxS( "/" ) + aNewProjectName + wxS( ".lib" ) );
1194
1195 row.SetURI( uri );
1196 }
1197
1198 libTable.Save().map_error(
1199 [&]( const LIBRARY_ERROR& aError )
1200 {
1201 wxString msg;
1202
1203 if( !aErrors.empty() )
1204 aErrors += wxT( "\n" );
1205
1206 msg.Printf( _( "Cannot copy file '%s'." ), destFile.GetFullPath() );
1207 aErrors += msg;
1208 } );
1209 }
1210 else
1211 {
1212 wxFAIL_MSG( wxS( "Unexpected filetype for Eeschema::SaveFileAs()" ) );
1213 }
1214}
1215
1216
1217int IFACE::HandleJob( JOB* aJob, REPORTER* aReporter, PROGRESS_REPORTER* aProgressReporter )
1218{
1219 return m_jobHandler->RunJob( aJob, aReporter, aProgressReporter );
1220}
1221
1222
1223bool IFACE::HandleJobConfig( JOB* aJob, wxWindow* aParent )
1224{
1225 return m_jobHandler->HandleJobConfig( aJob, aParent );
1226}
1227
1228
1229// TODO(JE) some of the below methods can probably be factored out and shared between sch/pcb
1231{
1232 if( m_openHandler )
1233 {
1234 if( aServer )
1235 aServer->DeregisterHandler( m_openHandler.get() );
1236
1237 m_openHandler.reset();
1238 }
1239
1240 m_openContext.reset();
1241
1242 delete m_openSchematic;
1243 m_openSchematic = nullptr;
1244
1245 // The jobs handler caches the last-loaded schematic. Clear it so the next job
1246 // uses the schematic from the newly opened document rather than a stale copy.
1247 if( m_jobHandler )
1248 m_jobHandler->ClearCachedSchematic();
1249}
1250
1251
1253{
1255 {
1256 if( aServer )
1257 aServer->DeregisterHandler( m_openSymbolHandler.get() );
1258
1259 m_openSymbolHandler.reset();
1260 }
1261
1262 m_openSymbolContext.reset();
1263}
1264
1265
1267 KICAD_API_SERVER* aServer, wxString* aError )
1268{
1269 wxCHECK( aServer, false );
1270
1271 if( aSpec.kind == DOCUMENT_SPEC::KIND::CREATE_KIND )
1272 return handleCreateSchematic( aSpec.path, aServer, aError );
1273
1274 if( aSpec.kind == DOCUMENT_SPEC::KIND::LIBID_KIND )
1275 return handleOpenSymbol( aSpec.path, aSpec.libId.GetUniStringLibId(), aServer, aError );
1276
1277 if( aSpec.path.IsEmpty() )
1278 {
1279 if( aError )
1280 *aError = wxS( "No path specified to open" );
1281
1282 return false;
1283 }
1284
1285 wxFileName projectPath( aSpec.path );
1286
1287 if( projectPath.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1288 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1289 else if( projectPath.GetExt() != FILEEXT::ProjectFileExtension )
1290 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1291
1292 projectPath.MakeAbsolute();
1293
1294 // We currently only support one document per type (and each needs to come from
1295 // the same project). This will need evolution once we support MDI and multi-project.
1296 closeSchematic( aServer );
1297
1298 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
1299
1300 // Reuse an already-loaded project if one exists for this path.
1301 PROJECT* project = settingsManager.GetProject( projectPath.GetFullPath() );
1302
1303 if( !project )
1304 {
1305 if( !settingsManager.LoadProject( projectPath.GetFullPath(), true ) )
1306 wxLogTrace( traceApi, "Warning: no project file found for %s", aSpec.path );
1307
1308 project = settingsManager.GetProject( projectPath.GetFullPath() );
1309 }
1310
1311 if( !project )
1312 {
1313 if( aError )
1314 *aError = wxString::Format( wxS( "Error loading project for %s" ), aSpec.path );
1315
1316 return false;
1317 }
1318
1319 wxFileName schPath( projectPath );
1320 schPath.SetExt( FILEEXT::KiCadSchematicFileExtension );
1321
1322 if( !schPath.FileExists() )
1323 {
1324 if( aError )
1325 *aError = wxString::Format( wxS( "File not found: %s" ), schPath.GetFullPath() );
1326
1327 return false;
1328 }
1329
1330 SCHEMATIC* schematic = nullptr;
1331
1332 try
1333 {
1334 schematic = EESCHEMA_HELPERS::LoadSchematic( schPath.GetFullPath(), false, false, project );
1335
1336 if( !schematic )
1337 {
1338 if( aError )
1339 *aError = wxS( "Failed to load schematic" );
1340
1341 return false;
1342 }
1343 }
1344 catch( ... )
1345 {
1346 if( aError )
1347 *aError = wxS( "Failed to load schematic" );
1348
1349 return false;
1350 }
1351
1353
1354 m_openContext = std::make_shared<HEADLESS_SCH_CONTEXT>( &m_openSchematic, project, m_kiway );
1355
1356 if( !m_apiHandlerSchLibs )
1357 {
1358 m_apiHandlerSchLibs = std::make_unique<API_HANDLER_SCH_LIBRARIES>();
1359 aServer->RegisterHandler( m_apiHandlerSchLibs.get() );
1360 }
1361
1362 m_openHandler = std::make_unique<API_HANDLER_SCH>( m_openContext );
1363 aServer->RegisterHandler( m_openHandler.get() );
1364
1365 return true;
1366}
1367
1368
1369bool IFACE::handleCreateSchematic( const wxString& aPath, KICAD_API_SERVER* aServer, wxString* aError )
1370{
1371 wxFileName schPath( aPath );
1372 schPath.MakeAbsolute();
1373
1374 wxFileName projectPath( schPath );
1375 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1376
1377 if( m_openSchematic && m_openSchematic->HasHierarchy() )
1378 {
1379 if( m_openSchematic->Hierarchy().IsModified() )
1380 {
1381 if( aError )
1382 *aError = wxS( "The current schematic has unsaved changes; save or revert it first" );
1383
1384 return false;
1385 }
1386 }
1387
1388 closeSchematic( aServer );
1389
1390 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
1391
1392 PROJECT* project = settingsManager.GetProject( projectPath.GetFullPath() );
1393
1394 if( !project )
1395 {
1396 // Create the project settings in memory (LoadProject falls back to defaults when the
1397 // file does not exist on disk) without writing any files.
1398 settingsManager.LoadProject( projectPath.GetFullPath(), true );
1399 project = settingsManager.GetProject( projectPath.GetFullPath() );
1400 }
1401
1402 if( !project )
1403 {
1404 if( aError )
1405 *aError = wxString::Format( wxS( "Error creating project for %s" ), aPath );
1406
1407 return false;
1408 }
1409
1410 std::unique_ptr<SCHEMATIC> schematic = std::make_unique<SCHEMATIC>( project );
1411 schematic->CreateDefaultScreens();
1412
1413 SCH_SCREENS screens( schematic->Root() );
1414 schematic->RootScreen()->SetFileName( schPath.GetFullPath() );
1415
1416 m_openSchematic = schematic.release();
1417
1418 m_openContext = std::make_shared<HEADLESS_SCH_CONTEXT>( &m_openSchematic, project, m_kiway );
1419
1420 if( !m_apiHandlerSchLibs )
1421 {
1422 m_apiHandlerSchLibs = std::make_unique<API_HANDLER_SCH_LIBRARIES>();
1423 aServer->RegisterHandler( m_apiHandlerSchLibs.get() );
1424 }
1425
1426 m_openHandler = std::make_unique<API_HANDLER_SCH>( m_openContext );
1427 aServer->RegisterHandler( m_openHandler.get() );
1428
1429 return true;
1430}
1431
1432
1433bool IFACE::handleOpenSymbol( const wxString& aProjectPath, const wxString& aLibIdStr, KICAD_API_SERVER* aServer,
1434 wxString* aError )
1435{
1436 LIB_ID libId;
1437
1438 if( libId.Parse( aLibIdStr ) >= 0 )
1439 {
1440 if( aError )
1441 *aError = wxString::Format( wxS( "Invalid symbol LIB_ID: %s" ), aLibIdStr );
1442
1443 return false;
1444 }
1445
1446 wxFileName projectPath( aProjectPath );
1447 projectPath.MakeAbsolute();
1448
1449 SETTINGS_MANAGER& settingsManager = Pgm().GetSettingsManager();
1450
1451 if( !settingsManager.LoadProject( projectPath.GetFullPath(), true ) )
1452 {
1453 wxLogTrace( traceApi, "Warning: no project file found for %s", aProjectPath );
1454 }
1455
1456 PROJECT* project = settingsManager.GetProject( projectPath.GetFullPath() );
1457
1458 if( !project )
1459 {
1460 if( aError )
1461 *aError = wxString::Format( wxS( "Error loading project for %s" ), aProjectPath );
1462
1463 return false;
1464 }
1465
1467 adapter->AsyncLoad();
1468 adapter->BlockUntilLoaded();
1469
1470 std::unique_ptr<LIB_SYMBOL> symbol;
1471
1472 try
1473 {
1474 LIB_SYMBOL* loaded = adapter->LoadSymbol( libId );
1475
1476 if( !loaded )
1477 {
1478 if( aError )
1479 *aError = wxString::Format( wxS( "Symbol not found: %s" ), aLibIdStr );
1480
1481 return false;
1482 }
1483
1484 symbol = std::make_unique<LIB_SYMBOL>( *loaded );
1485 }
1486 catch( const IO_ERROR& err )
1487 {
1488 if( aError )
1489 *aError = wxString::Format( wxS( "Failed to load symbol: %s" ), err.What() );
1490
1491 return false;
1492 }
1493 catch( ... )
1494 {
1495 if( aError )
1496 *aError = wxS( "Failed to load symbol" );
1497
1498 return false;
1499 }
1500
1501 closeSymbol( aServer );
1502
1503 if( !m_apiHandlerSchLibs )
1504 {
1505 m_apiHandlerSchLibs = std::make_unique<API_HANDLER_SCH_LIBRARIES>();
1506 aServer->RegisterHandler( m_apiHandlerSchLibs.get() );
1507 }
1508
1509 m_openSymbolContext = std::make_shared<HEADLESS_SYMBOL_EDITOR_CONTEXT>(
1510 std::move( symbol ), libId, project, GetAppSettings<SYMBOL_EDITOR_SETTINGS>( "symbol_editor" ), m_kiway );
1511
1512 m_openSymbolHandler = std::make_unique<API_HANDLER_SYMBOL>( m_openSymbolContext, nullptr );
1513 aServer->RegisterHandler( m_openSymbolHandler.get() );
1514
1515 return true;
1516}
1517
1518
1519bool IFACE::HandleApiCloseDocument( const DOCUMENT_SPEC& aSpec, KICAD_API_SERVER* aServer, wxString* aError )
1520{
1521 wxCHECK( aServer, false );
1522
1523 if( aSpec.kind == DOCUMENT_SPEC::KIND::LIBID_KIND )
1524 {
1525 if( !m_openSymbolContext )
1526 {
1527 if( aError )
1528 *aError = wxS( "No symbol is currently open" );
1529
1530 return false;
1531 }
1532
1533 if( aSpec.libId.IsValid() && m_openSymbolContext->GetLoadedLibId() != aSpec.libId )
1534 {
1535 if( aError )
1536 *aError = wxS( "Requested document does not match the open document" );
1537
1538 return false;
1539 }
1540
1541 closeSymbol( aServer );
1542 return true;
1543 }
1544
1545 if( !m_openContext )
1546 {
1547 if( aError )
1548 *aError = wxS( "No schematic is currently open" );
1549
1550 return false;
1551 }
1552
1553 if( !aSpec.path.IsEmpty() )
1554 {
1555 wxFileName currentSch( m_openContext->GetCurrentFileName() );
1556
1557 if( currentSch.GetFullName() != wxFileName( aSpec.path ).GetFullName() )
1558 {
1559 if( aError )
1560 *aError = wxS( "Requested document does not match the open document" );
1561
1562 return false;
1563 }
1564 }
1565
1566 closeSchematic( aServer );
1567 return true;
1568}
1569
1570
1572{
1573 wxCHECK_RET( aServer, "no API server provided" );
1574
1575 if( !m_apiHandlerSchLibs )
1576 {
1577 m_apiHandlerSchLibs = std::make_unique<API_HANDLER_SCH_LIBRARIES>();
1578 aServer->RegisterHandler( m_apiHandlerSchLibs.get() );
1579 }
1580}
1581
1582
1584{
1586
1587 if( !adapter )
1588 return false;
1589
1590 adapter->AsyncLoad();
1591 return true;
1592}
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
static std::list< TOOL_ACTION * > & GetActionList()
Return list of TOOL_ACTIONs.
Class to hold basic information about controls that can be added to the toolbars.
static std::list< ACTION_TOOLBAR_CONTROL * > GetCustomControlList(FRAME_T aContext)
Get the list of custom controls that could be used on a particular frame type.
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
std::shared_ptr< BACKGROUND_JOB > Create(const wxString &aName)
Creates a background job with the given name.
void Remove(std::shared_ptr< BACKGROUND_JOB > job)
Removes the given background job from any lists and frees it.
static CLI_PROGRESS_REPORTER & GetInstance()
static CLI_REPORTER & GetInstance()
Definition reporter.cpp:261
static bool IsOnStandardSocketPath()
static void AnnounceToPrimary(FRAME_T aFrameType)
The base frame for deriving all KiCad main window classes.
virtual bool SetPattern(const wxString &aPattern) override
Set the pattern against which candidates will be matched.
static void SetSchEditFrame(SCH_EDIT_FRAME *aSchEditFrame)
static SCHEMATIC * LoadSchematic(const wxString &aFileName, bool aSetActive, bool aForceDefaultProject, PROJECT *aProject=nullptr, bool aCalculateConnectivity=true, REPORTER *aRootReporter=nullptr)
Handle Eeschema job dispatches.
SNAP_INFERENCE_SETTINGS m_SnapInference
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()
An simple container class that lets us dispatch output jobs to kifaces.
Definition job.h:184
void RegisterHandler(API_HANDLER *aHandler)
Adds a new request handler to the server.
void DeregisterHandler(API_HANDLER *aHandler)
Keeps the documents drawn on a pair of diff canvases alive.
A KIFACE implementation.
Definition kiface_base.h:35
KIFACE_BASE(const char *aKifaceName, KIWAY::FACE_T aId)
Definition kiface_base.h:64
void InitSettings(APP_SETTINGS_BASE *aSettings)
Definition kiface_base.h:94
void end_common()
Common things to do for a top program module, during OnKifaceEnd();.
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:92
bool start_common(int aCtlBits)
Common things to do for a top program module, during OnKifaceStart().
int m_start_flags
flags provided in OnKifaceStart()
bool IsSingle() const
Is this KIFACE running under single_top?
static int Apply(const git_merge_driver_source *aSrc, const char **aPathOut, unsigned int *aModeOut, git_buf *aMergedOut)
A mix in class which holds the location of a wxWindow's KIWAY.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:348
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:401
virtual void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=nullptr, bool aFromOtherThread=false)
Send aPayload to aDestination from aSource.
Definition kiway.cpp:499
FACE_T
Known KIFACE implementations.
Definition kiway.h:354
@ FACE_SCH
eeschema DSO
Definition kiway.h:355
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition kiway.cpp:208
std::optional< float > AsyncLoadProgress() const
Returns the fraction of the libraries queued by AsyncLoad() that have been processed,...
std::vector< KI_ERROR > GetLibraryLoadErrors() const
Returns all library load errors as newline-separated strings for display.
void AbortAsyncLoad()
Aborts any async load in progress; blocks until fully done aborting.
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
void AsyncLoad()
Loads all available libraries for this adapter type in the background.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:65
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
wxString GetUniStringLibId() const
Definition lib_id.h:144
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition lib_id.h:108
const wxString GetUniStringLibNickname() const
Definition lib_id.h:84
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
std::weak_ptr< LIB_SYMBOL > & GetParent()
Definition lib_symbol.h:152
int GetPinCount() const override
const std::vector< ASSOCIATED_FOOTPRINT > & GetEffectiveAssociatedFootprints() const
Definition lib_symbol.h:300
bool IsDerived() const
Definition lib_symbol.h:241
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
wxArrayString GetFPFilters() const
Definition lib_symbol.h:252
Generate the KiCad netlist format supported by Pcbnew.
void Format(OUTPUTFORMATTER *aOutputFormatter, int aCtl)
Output this s-expression netlist into aOutputFormatter.
Container for data for KiCad programs.
Definition pgm_base.h:101
virtual BACKGROUND_JOBS_MONITOR & GetBackgroundJobMonitor() const
Definition pgm_base.h:129
void AddLibraryLoadMessages(const std::vector< KI_ERROR > &aMessages)
Add library load messages to all registered status bars.
void ClearLibraryLoadMessages()
Clear library load messages from all registered status bars.
KICAD_API_SERVER & GetApiServer()
Definition pgm_base.h:141
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:123
A progress reporter interface for use in multi-threaded environments.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
Container for project specific data.
Definition project.h:63
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
Holds all the data relating to one schematic.
Definition schematic.h:149
Schematic editor (Eeschema) main window.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:826
SCH_SCREEN * GetNext()
SCH_SCREEN * GetFirst()
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
bool IsVirtualRootSheet() const
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Take ownership of the pointer passed in.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
PROJECT * GetProject(const wxString &aFullPath) const
Retrieve a loaded project by name.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
The SIMULATOR_FRAME holds the main user-interface for running simulations.
Simple error container for failure to init the simulation engine and ultimately abort the frame const...
Implement an OUTPUTFORMATTER to a memory buffer.
Definition richio.h:430
const std::string & GetString()
Definition richio.h:453
Symbol library viewer main window.
SNAP_INFERENCE_SETTINGS m_SnapInference
The symbol library editor main window.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
std::vector< LIB_SYMBOL * > GetSymbols(const wxString &aNickname, SYMBOL_TYPE aType=SYMBOL_TYPE::ALL_SYMBOLS)
Symbol library viewer main window.
Represent a single user action.
UNITS_PROVIDER(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits)
EDA_UNITS GetUserUnits() const
void SetUserUnits(EDA_UNITS aUnits)
bool empty() const
Definition utf8.h:105
GAL-backed canvas for visualizing a KICAD_DIFF::DIFF_SCENE.
This file is part of the common library.
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition cvpcb.cpp:165
#define _(s)
EDA_UNITS
Definition eda_units.h:44
SCH_SHEET * g_RootSheet
Definition eeschema.cpp:100
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition eeschema.cpp:864
bool FootprintFilterMatchesName(const EDA_PATTERN_MATCH &aFilter, const wxString &aLibNickname, const wxString &aFootprintName)
Whether a given footprint matches a specified filter.
@ PANEL_SYM_EDIT_GRIDS
Definition frame_type.h:72
@ FRAME_SCH_SYMBOL_EDITOR
Definition frame_type.h:31
@ PANEL_SCH_FIELD_NAME_TEMPLATES
Definition frame_type.h:84
@ PANEL_SCH_TOOLBARS
Definition frame_type.h:83
@ PANEL_SYM_SNAPPING
Definition frame_type.h:73
@ FRAME_SCH_VIEWER
Definition frame_type.h:32
@ PANEL_SCH_DISP_OPTIONS
Definition frame_type.h:78
@ PANEL_SCH_SIMULATOR
Definition frame_type.h:85
@ FRAME_SCH
Definition frame_type.h:30
@ PANEL_SYM_TOOLBARS
Definition frame_type.h:76
@ FRAME_SIMULATOR
Definition frame_type.h:34
@ PANEL_SYM_EDIT_OPTIONS
Definition frame_type.h:74
@ PANEL_SCH_EDIT_OPTIONS
Definition frame_type.h:81
@ PANEL_SYM_DISP_OPTIONS
Definition frame_type.h:71
@ DIALOG_SCH_LIBRARY_TABLE
Definition frame_type.h:130
@ PANEL_SYM_COLORS
Definition frame_type.h:75
@ PANEL_SCH_SNAPPING
Definition frame_type.h:80
@ PANEL_SCH_GRIDS
Definition frame_type.h:79
@ PANEL_SCH_COLORS
Definition frame_type.h:82
@ DIALOG_DESIGN_BLOCK_LIBRARY_TABLE
Definition frame_type.h:129
@ FRAME_SYMBOL_CHOOSER
Definition frame_type.h:33
void CopySexprFile(const wxString &aSrcPath, const wxString &aDestPath, std::function< bool(const std::string &token, wxString &value)> aCallback, wxString &aErrors)
Definition gestfich.cpp:388
void KiCopyFile(const wxString &aSrcPath, const wxString &aDestPath, wxString &aErrors)
Definition gestfich.cpp:361
static const std::string LegacySchematicFileExtension
static const std::string NetlistFileExtension
static const std::string SymbolLibraryTableFileName
static const std::string ProjectFileExtension
static const std::string SchematicSymbolFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string LegacySymbolLibFileExtension
static const std::string KiCadSymbolLibFileExtension
static const std::string BackupFileSuffix
static const std::string LegacySymbolDocumentFileExtension
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
const wxChar *const traceApi
Flag to enable debug output related to the IPC API and its plugin system.
Definition api_utils.cpp:33
#define KIFACE_API
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
@ KIFACE_FILTER_FOOTPRINT_USERS
Function pointer type: wxString (*)(const wxString& aQueryJson) Input JSON: the object written by FOO...
Definition kiface_ids.h:50
@ KIFACE_MERGE_DOCUMENT
int (*)( int aKind, const wxString& aAncestor, const wxString& aOurs, const wxString& aTheirs,...
Definition kiface_ids.h:70
@ KIFACE_NETLIST_SCHEMATIC
Definition kiface_ids.h:63
@ KIFACE_TRIGGER_SYMBOLS_LOAD
Function pointer type: bool (*)() Starts loading the symbol libraries in the background.
Definition kiface_ids.h:55
@ KIFACE_ATTACH_DIFF_CANVASES
KICAD_DIFF::DIFF_CANVAS_CONTEXT* (*)( int aKind, const wxString& aFileA, const wxString& aFileB,...
Definition kiface_ids.h:85
@ KIFACE_OPEN_DIFF_DIALOG
int (*)( int aKind, const wxString& aFileA, const wxString& aFileB, const wxString& aLabelA,...
Definition kiface_ids.h:77
@ KIFACE_SYMBOLS_LOAD_PROGRESS
Function pointer type: float (*)() Returns how far the library loader has gotten as a fraction of the...
Definition kiface_ids.h:60
#define KFCTL_CLI
Running as CLI app.
Definition kiway.h:176
#define KIFACE_GETTER
Definition kiway.h:110
@ MAIL_RELOAD_LIB
Definition mail_type.h:55
DOC_KIND
Document type a diff/merge entry point should route to, derived from a file path's extension.
bool RegisterMergeDriver(const char *aName, MERGE_APPLY_FN aApply)
Register a KiCad merge driver with libgit2.
static int eeschemaMergeExport(int aKind, const wxString &aAncestor, const wxString &aOurs, const wxString &aTheirs, const wxString &aOutput, bool aInteractive, bool aSingleFile, REPORTER *aReporter)
Definition eeschema.cpp:830
static float symbolLibraryLoadProgress()
Return how far a background load has got.
Definition eeschema.cpp:496
bool generateSchematicNetlist(const wxString &aFilename, std::string &aNetlist, KIWAY *aKiway)
Definition eeschema.cpp:191
static wxString filterFootprintUsers(const wxString &aQueryJson)
Find the symbols that select a given footprint somehow (but FP field, filters or pin maps)
Definition eeschema.cpp:394
static bool footprintReferenceMatches(const LIB_ID &aReference, const LIB_ID &aFootprint)
Whether a footprint reference names aFootprint.
Definition eeschema.cpp:244
static KICAD_DIFF::DIFF_CANVAS_CONTEXT * eeschemaAttachDiffCanvasesExport(int aKind, const wxString &aFileA, const wxString &aFileB, WIDGET_DIFF_CANVAS *aBefore, WIDGET_DIFF_CANVAS *aAfter, KICAD_DIFF::DOCUMENT_DIFF *aDiff, REPORTER *aReporter)
Definition eeschema.cpp:849
static bool symbolPinMapsBindFootprint(const LIB_SYMBOL &aSymbol, const LIB_ID &aFootprint, FOOTPRINT_USER_MATCH &aMatch)
Whether one of the pin maps of aSymbol is bound to aFootprint; collects the names of the bound maps i...
Definition eeschema.cpp:317
static bool symbolFootprintFieldNamesFootprint(const LIB_SYMBOL &aSymbol, const LIB_ID &aFootprint, FOOTPRINT_USER_MATCH &aMatch)
Whether the footprint field of aSymbol names aFootprint; sets the footprint field flag in aMatch.
Definition eeschema.cpp:335
static std::optional< FOOTPRINT_USER_MATCH > symbolUsesFootprint(const LIB_SYMBOL &aSymbol, const LIB_ID &aFootprint)
Return how aSymbol uses aFootprint, or nothing when it doesn't.
Definition eeschema.cpp:359
static std::unique_ptr< SCHEMATIC > readSchematicFromFile(const std::string &aFilename)
Definition eeschema.cpp:120
static PROJECT * symbolLibraryProject()
Return the project whose symbol libraries the kiface-level symbol services work with.
Definition eeschema.cpp:211
static wxString effectiveFootprintText(const LIB_SYMBOL &aSymbol)
Return the footprint field text in effect for a symbol.
Definition eeschema.cpp:293
static bool symbolFilterMatchesFootprint(const LIB_SYMBOL &aSymbol, const LIB_ID &aFootprint, FOOTPRINT_USER_MATCH &aMatch)
Whether any footprint filter of a symbol selects a given footprint.
Definition eeschema.cpp:264
static bool startSymbolLibraryLoad()
Start loading the symbol libraries in the background.
Definition eeschema.cpp:476
SCH::IFACE KIFACE_BASE, UNITS_PROVIDER kiface("eeschema", KIWAY::FACE_SCH)
static int eeschemaOpenDiffDialogExport(int aKind, const wxString &aFileA, const wxString &aFileB, const wxString &aLabelA, const wxString &aLabelB, wxWindow *aParent, REPORTER *aReporter)
Definition eeschema.cpp:840
#define GNL_ALL
@ GNL_OPT_KICAD
void InvokeEditDesignBlockLibTable(KIWAY *aKiway, wxWindow *aParent)
PANEL_SNAPPING * CreateSnappingPanel(wxWindow *aParent, SETTINGS_T *aCfg, FRAME_T aFrameType, SNAP_INFERENCE_SETTINGS SETTINGS_T::*aInference=nullptr, MAGNETIC_SETTINGS SETTINGS_T::*aMagnetics=nullptr)
Build the snapping page for an editor.
void InvokeSchEditSymbolLibTable(KIWAY *aKiway, wxWindow *aParent)
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
T * GetToolbarSettings(const wxString &aFilename)
T * GetAppSettings(const char *aFilename)
A first-class footprint choice on a LIB_SYMBOL, tied to a named pin map.
Definition pin_map.h:159
All the information needed to query the symbol libraries for the symbols using a footprint.
static FOOTPRINT_USERS_QUERY FromJsonStr(const wxString &aJson)
Parse the JSON object written by ToJsonStr().
bool m_MatchPinMaps
When true, symbols whose pin maps are bound to the footprint are returned.
int m_MaxResults
Limits the number of returned symbols; zero means no limit.
bool m_MatchFilters
When true, symbols whose footprint filters select the footprint are returned.
bool m_MatchFootprintField
When true, symbols whose footprint field names the footprint are returned.
LIB_ID m_Footprint
The footprint to find the users of.
The outcome of a footprint users query, and the JSON encoding used to move it across the Eeschema kif...
One symbol that uses a footprint, and the reason it matched.
wxString m_MatchedFilter
The footprint filter that selected the footprint, empty when the match did not come from a filter.
int m_PinCount
The number of pins of the matching symbol.
bool m_MatchesFootprintField
True when the symbol's footprint field names the footprint.
LIB_ID m_Symbol
The "library:symbol" name of the matching symbol.
bool m_IsDerived
True when the symbol is derived from another symbol rather than being a root symbol.
std::vector< wxString > m_MatchedPinMaps
The names of the symbol's pin maps that are bound to the footprint, in the order they were found; emp...
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
The full set of changes between two parsed documents of one type.
wxString path
File path (KIND::FILE_KIND) or project path (KIND::LIBID_KIND).
Definition kiway.h:164
LIB_ID libId
Library identifier; valid when kind == KIND::LIBID_KIND.
Definition kiway.h:165
Implement a participant in the KIWAY alchemy.
Definition kiway.h:153
std::future< void > m_libraryPreloadReturn
Definition eeschema.cpp:812
bool OnKifaceStart(PGM_BASE *aProgram, int aCtlBits, KIWAY *aKiway) override
Typically start_common() is called from here.
Definition eeschema.cpp:875
std::shared_ptr< BACKGROUND_JOB > m_libraryPreloadBackgroundJob
Definition eeschema.cpp:811
std::unique_ptr< API_HANDLER_SCH > m_openHandler
Definition eeschema.cpp:824
void PreloadLibraries(KIWAY *aKiway) override
Definition eeschema.cpp:930
void closeSymbol(KICAD_API_SERVER *aServer)
void SaveFileAs(const wxString &aProjectBasePath, const wxString &aProjectName, const wxString &aNewProjectBasePath, const wxString &aNewProjectName, const wxString &aSrcFilePath, wxString &aErrors) override
Saving a file under a different name is delegated to the various KIFACEs because the project doesn't ...
void ProjectChanged() override
std::unique_ptr< API_HANDLER_SYMBOL > m_openSymbolHandler
Definition eeschema.cpp:823
void CancelPreload(bool aBlock=true) override
wxWindow * CreateKiWindow(wxWindow *aParent, int aClassId, KIWAY *aKiway, int aCtlBits=0) override
Create a wxWindow for the current project.
Definition eeschema.cpp:527
EESCHEMA_JOBS_HANDLER * JobHandler() const
Accessor for the non-job diff/merge exports (eeschemaMergeExport etc.).
Definition eeschema.cpp:775
std::atomic_bool m_libraryPreloadAbort
Definition eeschema.cpp:814
KIWAY * m_kiway
Definition eeschema.cpp:819
IFACE(const char *aName, KIWAY::FACE_T aType)
Definition eeschema.cpp:515
void RegisterLibraryHandlers(KICAD_API_SERVER *aServer) override
Register this face's library API handlers on the given server.
void Reset() override
Reloads global state.
Definition eeschema.cpp:920
void * IfaceOrAddress(int aDataId) override
Return a pointer to the requested object.
Definition eeschema.cpp:746
int HandleJob(JOB *aJob, REPORTER *aReporter, PROGRESS_REPORTER *aProgressReporter) override
std::unique_ptr< EESCHEMA_JOBS_HANDLER > m_jobHandler
Definition eeschema.cpp:810
std::unique_ptr< API_HANDLER_SCH_LIBRARIES > m_apiHandlerSchLibs
Definition eeschema.cpp:825
bool LoadAllLibraries() override
Starts a background load of all libraries of the type owned by this face.
std::atomic_bool m_libraryPreloadInProgress
Definition eeschema.cpp:813
bool HandleApiCloseDocument(const DOCUMENT_SPEC &aSpec, KICAD_API_SERVER *aServer, wxString *aError) override
Close the document identified by aSpec.
bool HandleApiOpenDocument(const DOCUMENT_SPEC &aSpec, KICAD_API_SERVER *aServer, wxString *aError) override
void closeSchematic(KICAD_API_SERVER *aServer)
std::shared_ptr< HEADLESS_SYMBOL_EDITOR_CONTEXT > m_openSymbolContext
Definition eeschema.cpp:822
bool handleOpenSymbol(const wxString &aProjectPath, const wxString &aLibIdStr, KICAD_API_SERVER *aServer, wxString *aError)
bool HandleJobConfig(JOB *aJob, wxWindow *aParent) override
std::shared_ptr< HEADLESS_SCH_CONTEXT > m_openContext
Definition eeschema.cpp:821
bool handleCreateSchematic(const wxString &aPath, KICAD_API_SERVER *aServer, wxString *aError)
SCHEMATIC * m_openSchematic
Definition eeschema.cpp:820
void OnKifaceEnd() override
Called just once just before the DSO is to be unloaded.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
IbisParser parser & reporter
KIBIS top(path, &reporter)
VECTOR3I expected(15, 30, 45)
static const long long MM
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.