KiCad PCB EDA Suite
schematic_file_util.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 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, you may find one at
18 * http://www.gnu.org/licenses/
19 */
20
21#include <schematic_file_util.h>
22
24
25#include <connection_graph.h>
26#include <lib_textbox.h>
27#include <schematic.h>
28#include <sch_screen.h>
29
30// For SCH parsing
33#include <richio.h>
34
36
37namespace KI_TEST
38{
39
40#ifndef QA_EESCHEMA_DATA_LOCATION
41 #define QA_EESCHEMA_DATA_LOCATION "???"
42#endif
43
45{
46 const char* env = std::getenv( "KICAD_TEST_EESCHEMA_DATA_DIR" );
47 std::string fn;
48
49 if( !env )
50 {
51 // Use the compiled-in location of the data dir (i.e. where the files were at build time)
53 }
54 else
55 {
56 // Use whatever was given in the env var
57 fn = env;
58 }
59
60 // Ensure the string ends in / to force a directory interpretation
61 fn += "/";
62
63 return fn;
64}
65
66
67void DumpSchematicToFile( SCHEMATIC& aSchematic, SCH_SHEET& aSheet, const std::string& aFilename )
68{
70 io.Save( aFilename, &aSheet, &aSchematic );
71}
72
73void LoadSheetSchematicContents( const std::string& fileName, SCH_SHEET* sheet )
74{
75 std::ifstream fileStream;
76 fileStream.open( fileName );
77 wxASSERT( fileStream.is_open() );
79 reader.SetStream( fileStream );
80 SCH_SEXPR_PARSER parser( &reader );
81 parser.ParseSchematic( sheet );
82}
83
84void LoadHierarchy( SCHEMATIC* schematic, SCH_SHEET* sheet, const std::string& sheetFilename,
85 std::unordered_map<std::string, SCH_SCREEN*>& parsedScreens )
86{
87 SCH_SCREEN* screen = nullptr;
88
89 if( !sheet->GetScreen() )
90 {
91 // Construct paths
92 const wxFileName fileName( sheetFilename );
93 const std::string filePath( fileName.GetPath( wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR ) );
94 const std::string fileBareName( fileName.GetFullName() );
95
96 // Check for existing screen
97 auto screenFound = parsedScreens.find( fileBareName );
98 if( screenFound != parsedScreens.end() )
99 screen = screenFound->second;
100
101 // Configure sheet with existing screen, or load screen
102 if( screen )
103 {
104 // Screen already loaded - assign to sheet
105 sheet->SetScreen( screen );
106 sheet->GetScreen()->SetParent( schematic );
107 }
108 else
109 {
110 // Load screen and assign to sheet
111 screen = new SCH_SCREEN( schematic );
112 parsedScreens.insert( { fileBareName, screen } );
113 sheet->SetScreen( screen );
114 sheet->GetScreen()->SetFileName( sheetFilename );
115 LoadSheetSchematicContents( sheetFilename, sheet );
116 }
117
118 // Recurse through child sheets
119 for( SCH_ITEM* item : sheet->GetScreen()->Items().OfType( SCH_SHEET_T ) )
120 {
121 SCH_SHEET* childSheet = static_cast<SCH_SHEET*>( item );
122 wxFileName childSheetFilename = childSheet->GetFileName();
123 if( !childSheetFilename.IsAbsolute() )
124 childSheetFilename.MakeAbsolute( filePath );
125 std::string childSheetFullFilename( childSheetFilename.GetFullPath() );
126 LoadHierarchy( schematic, childSheet, childSheetFullFilename, parsedScreens );
127 }
128 }
129}
130
131std::unique_ptr<SCHEMATIC> LoadHierarchyFromRoot( const std::string& rootFilename,
132 PROJECT* project )
133{
134 std::unique_ptr<SCHEMATIC> schematic( new SCHEMATIC( nullptr ) );
135 std::unordered_map<std::string, SCH_SCREEN*> parsedScreens;
136
137 schematic->SetProject( project );
138 SCH_SHEET* rootSheet = new SCH_SHEET( schematic.get() );
139 schematic->SetRoot( rootSheet );
140 LoadHierarchy( schematic.get(), rootSheet, rootFilename, parsedScreens );
141
142 return schematic;
143}
144
145
146void LoadSchematic( SETTINGS_MANAGER& aSettingsManager, const wxString& aRelPath,
147 std::unique_ptr<SCHEMATIC>& aSchematic )
148{
149 if( aSchematic )
150 {
151 PROJECT* prj = &aSchematic->Prj();
152
153 aSchematic->SetProject( nullptr );
154 aSettingsManager.UnloadProject( prj, false );
155 aSchematic->Reset();
156 }
157
158 std::string absPath = getEeschemaTestDataDir() + aRelPath.ToStdString();
159 wxFileName projectFile( absPath + ".kicad_pro" );
160 wxFileName legacyProject( absPath + ".pro" );
161 std::string schematicPath = absPath + ".kicad_sch";
162
163 if( projectFile.Exists() )
164 aSettingsManager.LoadProject( projectFile.GetFullPath() );
165 else if( legacyProject.Exists() )
166 aSettingsManager.LoadProject( legacyProject.GetFullPath() );
167 else
168 aSettingsManager.LoadProject( "" );
169
170 aSettingsManager.Prj().SetElem( PROJECT::ELEM_SCH_SYMBOL_LIBS, nullptr );
171
172 aSchematic = LoadHierarchyFromRoot( schematicPath, &aSettingsManager.Prj() );
173
174 aSchematic->CurrentSheet().push_back( &aSchematic->Root() );
175
176 SCH_SCREENS screens( aSchematic->Root() );
177
178 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
179 screen->UpdateLocalLibSymbolLinks();
180
181 SCH_SHEET_LIST sheets = aSchematic->GetSheets();
182
183 // Restore all of the loaded symbol instances from the root sheet screen.
184 sheets.UpdateSymbolInstanceData( aSchematic->RootScreen()->GetSymbolInstances() );
185 sheets.UpdateSheetInstanceData( aSchematic->RootScreen()->GetSheetInstances() );
186
187 if( aSchematic->RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
189
190 if( aSchematic->RootScreen()->GetFileFormatVersionAtLoad() < 20221206 )
191 {
192 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
193 screen->MigrateSimModels();
194 }
195
196 sheets.AnnotatePowerSymbols();
197
198 // NOTE: This is required for multi-unit symbols to be correct
199 // Normally called from SCH_EDIT_FRAME::FixupJunctions() but could be refactored
200 for( SCH_SHEET_PATH& sheet : sheets )
201 sheet.UpdateAllScreenReferences();
202
203 // NOTE: SchematicCleanUp is not called; QA schematics must already be clean or else
204 // SchematicCleanUp must be freed from its UI dependencies.
205
206 aSchematic->ConnectionGraph()->Recalculate( sheets, true );
207}
208
209} // namespace KI_TEST
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:100
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
Container for project specific data.
Definition: project.h:64
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:294
@ ELEM_SCH_SYMBOL_LIBS
Definition: project.h:208
Holds all the data relating to one schematic.
Definition: schematic.h:61
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:662
SCH_SCREEN * GetNext()
void FixLegacyPowerSymbolMismatches()
Fix legacy power symbols that have mismatched value text fields and invisible power pin names.
SCH_SCREEN * GetFirst()
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:110
Object to parser s-expression symbol library and schematic file formats.
void ParseSchematic(SCH_SHEET *aSheet, bool aIsCopyablyOnly=false, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
Parse the internal LINE_READER object into aSheet.
A SCH_PLUGIN derivation for loading schematic files using the new s-expression file format.
void Save(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const STRING_UTF8_MAP *aProperties=nullptr) override
Write aSchematic to a storage file in a format that this SCH_PLUGIN implementation knows about,...
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 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.
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:57
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:302
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:106
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:162
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Saves, unloads and unregisters the given PROJECT.
PROJECT & Prj() const
A helper while we are not MDI-capable – return the one and only project.
LINE_READER that wraps a given std::istream instance.
void SetStream(std::istream &aStream)
Set the stream for this line reader.
std::unique_ptr< SCHEMATIC > LoadHierarchyFromRoot(const std::string &rootFilename, PROJECT *project)
void LoadSheetSchematicContents(const std::string &fileName, SCH_SHEET *sheet)
void LoadHierarchy(SCHEMATIC *schematic, SCH_SHEET *sheet, const std::string &sheetFilename, std::unordered_map< std::string, SCH_SCREEN * > &parsedScreens)
void LoadSchematic(SETTINGS_MANAGER &aSettingsManager, const wxString &aRelPath, std::unique_ptr< SCHEMATIC > &aSchematic)
void DumpSchematicToFile(SCHEMATIC &aSchematic, SCH_SHEET &aSheet, const std::string &aFilename)
std::string getEeschemaTestDataDir()
Schematic and symbol library s-expression file format parser definitions.
#define QA_EESCHEMA_DATA_LOCATION
@ SCH_SHEET_T
Definition: typeinfo.h:158