KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eeschema_helpers.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 The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "eeschema_helpers.h"
21
22#include <algorithm>
23
24#include <connection_graph.h>
25#include <locale_io.h>
27#include <schematic.h>
28#include <sch_commit.h>
29#include <sch_edit_frame.h>
30#include <sch_file_versions.h>
31#include <sch_label.h>
32#include <sch_io/sch_io.h>
33#include <sch_io/sch_io_mgr.h>
36#include <tool/tool_manager.h>
37#include <kiface_base.h>
38
39#include <wx/app.h>
40
41
43
44
46{
47 s_SchEditFrame = aSchEditFrame;
48}
49
50
51SCHEMATIC* EESCHEMA_HELPERS::LoadSchematic( const wxString& aFileName, bool aSetActive,
52 bool aForceDefaultProject, PROJECT* aProject, bool aCalculateConnectivity )
53{
54 if( aFileName.EndsWith( FILEEXT::KiCadSchematicFileExtension ) )
55 return LoadSchematic( aFileName, SCH_IO_MGR::SCH_KICAD, aSetActive, aForceDefaultProject,
56 aProject, aCalculateConnectivity );
57 else if( aFileName.EndsWith( FILEEXT::LegacySchematicFileExtension ) )
58 return LoadSchematic( aFileName, SCH_IO_MGR::SCH_LEGACY, aSetActive, aForceDefaultProject,
59 aProject, aCalculateConnectivity );
60
61 // as fall back for any other kind use the legacy format
62 return LoadSchematic( aFileName, SCH_IO_MGR::SCH_LEGACY, aSetActive, aForceDefaultProject, aProject,
63 aCalculateConnectivity );
64}
65
66
67SCHEMATIC* EESCHEMA_HELPERS::LoadSchematic( const wxString& aFileName,
68 SCH_IO_MGR::SCH_FILE_T aFormat,
69 bool aSetActive,
70 bool aForceDefaultProject,
71 PROJECT* aProject,
72 bool aCalculateConnectivity )
73{
74 wxFileName pro = aFileName;
76 pro.MakeAbsolute();
77 wxString projectPath = pro.GetFullPath();
78
79 // Ensure the "C" locale is temporary set, before reading any file
80 // It also avoid wxWidget alerts about locale issues, later, when using Python 3
82
83 PROJECT* project = aProject;
85
86 if( !project )
87 {
88 project = mgr.GetProject( projectPath );
89 }
90
91 if( !aForceDefaultProject )
92 {
93 if( !project )
94 {
95 if( wxFileExists( projectPath ) )
96 {
97 mgr.LoadProject( projectPath, aSetActive );
98 project = mgr.GetProject( projectPath );
99 }
100 }
101 else if( s_SchEditFrame && project == &mgr.Prj() )
102 {
103 // Project is already loaded? Then so is the board
104 return &s_SchEditFrame->Schematic();
105 }
106 }
107
108 // Board cannot be loaded without a project, so create the default project
109 if( !project || aForceDefaultProject )
110 project = &mgr.Prj();
111
112 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( aFormat ) );
113
114 std::unique_ptr<SCHEMATIC> schematic = std::make_unique<SCHEMATIC>( project );
115 schematic->CreateDefaultScreens();
116
117 wxFileName schFile = aFileName;
118 schFile.MakeAbsolute();
119
120 try
121 {
122 SCH_SHEET* rootSheet = pi->LoadSchematicFile( schFile.GetFullPath(), schematic.get() );
123
124 if( !rootSheet )
125 {
126 schematic->SetProject( nullptr );
127 return nullptr;
128 }
129
130 std::vector<SCH_SHEET*> topLevelSheets = schematic->GetTopLevelSheets();
131 bool rootIsTopLevel = std::find( topLevelSheets.begin(), topLevelSheets.end(), rootSheet )
132 != topLevelSheets.end();
133 bool rootIsVirtualRoot = rootSheet == &schematic->Root() || rootSheet->IsVirtualRootSheet();
134
135 if( !rootIsTopLevel && !rootIsVirtualRoot )
136 schematic->SetTopLevelSheets( { rootSheet } );
137
138 // Make ${SHEETNAME} work on the root sheet until we properly support naming the root
139 // sheet. Prefer the display name from the matching schematic.top_level_sheets entry in
140 // the project file so CLI/API exports show the same name the GUI does.
141 if( rootSheet->GetName().IsEmpty() )
142 {
143 wxString rootName = _( "Root" );
144
145 for( const TOP_LEVEL_SHEET_INFO& info : project->GetProjectFile().GetTopLevelSheets() )
146 {
147 wxFileName candidate( project->GetProjectPath(), info.filename );
148
149 if( candidate.SameAs( schFile ) && !info.name.IsEmpty() )
150 {
151 rootName = info.name;
152 break;
153 }
154 }
155
156 rootSheet->SetName( rootName );
157 }
158 }
159 catch( ... )
160 {
161 schematic->SetProject( nullptr );
162 return nullptr;
163 }
164
165 SCH_SHEET_LIST sheetList = schematic->BuildSheetListSortedByPageNumbers();
166 SCH_SCREENS screens( schematic->Root() );
167
168 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
169 screen->UpdateLocalLibSymbolLinks();
170
171 if( schematic->RootScreen()->GetFileFormatVersionAtLoad() < 20221002 )
172 sheetList.UpdateSymbolInstanceData( schematic->RootScreen()->GetSymbolInstances());
173
174 sheetList.UpdateSheetInstanceData( schematic->RootScreen()->GetSheetInstances());
175
176 if( schematic->RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
178
179 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
180 screen->MigrateSimModels();
181
182 schematic->LoadVariants();
183
184 wxString projectName = project->GetProjectName();
185
186 if( projectName.IsEmpty() )
187 projectName = schFile.GetName();
188
189 // Check must run before pruning so variant data on a stale instance path is migrated
190 // onto the new instance before the orphan is removed.
191 sheetList.CheckForMissingSymbolInstances( projectName );
192 screens.PruneOrphanedSymbolInstances( projectName, sheetList );
193 screens.PruneOrphanedSheetInstances( projectName, sheetList );
194
195 sheetList.AnnotatePowerSymbols();
196
197 if( sheetList.AllSheetPageNumbersEmpty() )
198 sheetList.SetInitialPageNumbers();
199 else
200 sheetList.RepairPageNumbers();
201
202 // A schematic written by an older version can lose the junctions that Eeschema implies from
203 // merged colinear wires, which shows up as connectivity errors. The GUI editor repairs this on
204 // load; the headless/CLI loader must do the same before connectivity is calculated. It is
205 // limited to pre-current files (the current version writes those junctions on save, so running
206 // it on a current file could silently connect an intentional crossing) and to callers that
207 // actually want connectivity.
208 if( aCalculateConnectivity
209 && schematic->RootScreen()->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
210 schematic->FixupJunctionsAfterImport();
211
212 schematic->ConnectionGraph()->Reset();
213
214 TOOL_MANAGER* toolManager = new TOOL_MANAGER;
215 toolManager->SetEnvironment( schematic.get(), nullptr, nullptr, Kiface().KifaceSettings(), nullptr );
216
217 if( aCalculateConnectivity )
218 {
219 SCH_COMMIT dummyCommit( toolManager );
220 schematic->RecalculateConnections( &dummyCommit, GLOBAL_CLEANUP, toolManager );
221 }
222
223 schematic->ResolveERCExclusionsPostUpdate();
224
225 schematic->SetSheetNumberAndCount();
226 schematic->RecomputeIntersheetRefs();
227
228 for( SCH_SHEET_PATH& sheet : sheetList )
229 {
230 sheet.UpdateAllScreenReferences();
231 sheet.LastScreen()->TestDanglingEnds( nullptr, nullptr );
232 }
233
234 if( aCalculateConnectivity )
235 schematic->ConnectionGraph()->Recalculate( sheetList, true );
236
237 return schematic.release();
238}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static void SetSchEditFrame(SCH_EDIT_FRAME *aSchEditFrame)
static SCH_EDIT_FRAME * s_SchEditFrame
static SCHEMATIC * LoadSchematic(const wxString &aFileName, bool aSetActive, bool aForceDefaultProject, PROJECT *aProject=nullptr, bool aCalculateConnectivity=true)
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:124
Container for project specific data.
Definition project.h:62
Holds all the data relating to one schematic.
Definition schematic.h:90
Schematic editor (Eeschema) main window.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:746
SCH_SCREEN * GetNext()
void FixLegacyPowerSymbolMismatches()
Fix legacy power symbols that have mismatched value text fields and invisible power pin names.
SCH_SCREEN * GetFirst()
void PruneOrphanedSheetInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void UpdateSheetInstanceData(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
void SetInitialPageNumbers()
Set initial sheet page numbers.
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
void AnnotatePowerSymbols()
Silently annotate the not yet annotated power symbols of the entire hierarchy of the sheet path list.
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
bool RepairPageNumbers()
Assign valid page numbers to sheet paths whose stored page number is missing or collides with an earl...
void CheckForMissingSymbolInstances(const wxString &aProjectName)
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:44
wxString GetName() const
Definition sch_sheet.h:136
void SetName(const wxString &aName)
Definition sch_sheet.h:137
bool IsVirtualRootSheet() const
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.
Master controller class:
void SetEnvironment(EDA_ITEM *aModel, KIGFX::VIEW *aView, KIGFX::VIEW_CONTROLS *aViewControls, APP_SETTINGS_BASE *aSettings, TOOLS_HOLDER *aFrame)
Set the work environment (model, view, view controls and the parent window).
#define _(s)
static const std::string LegacySchematicFileExtension
static const std::string ProjectFileExtension
static const std::string KiCadSchematicFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PGM_BASE & Pgm()
The global program "get" accessor.
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
@ GLOBAL_CLEANUP
Definition schematic.h:79
std::vector< FAB_LAYER_COLOR > dummy
Information about a top-level schematic sheet.
Definition of file extensions used in Kicad.