KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
sch_io_cadstar_archive.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) 2020 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
5 * Copyright (C) 2020-2024 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
24
25#include <font/fontconfig.h>
26#include <lib_symbol.h>
27#include <progress_reporter.h>
28#include <project_sch.h>
29#include <sch_screen.h>
30#include <sch_sheet.h>
31#include <schematic.h>
33#include <symbol_lib_table.h>
35#include <wx_filename.h>
36#include <wx/dir.h>
37#include <wx/wfstream.h>
38#include <wx/txtstrm.h>
39
40
41bool SCH_IO_CADSTAR_ARCHIVE::CanReadLibrary( const wxString& aFileName ) const
42{
43 if( !SCH_IO::CanReadLibrary( aFileName ) )
44 return false;
45
46 try
47 {
49 return p.CheckFileHeader( aFileName.utf8_string() );
50 }
51 catch( const std::runtime_error& )
52 {
53 }
54
55 return false;
56}
57
58
60{
61 return 0;
62}
63
64
66 SCHEMATIC* aSchematic,
67 SCH_SHEET* aAppendToMe,
68 const std::map<std::string, UTF8>* aProperties )
69{
70 wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr );
71
72 // Show the font substitution warnings
74
75 SCH_SHEET* rootSheet = nullptr;
76
77
78 if( aAppendToMe )
79 {
80 wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
81 rootSheet = &aSchematic->Root();
82 }
83 else
84 {
85 rootSheet = new SCH_SHEET( aSchematic );
86 rootSheet->SetFileName( aFileName );
87 aSchematic->SetRoot( rootSheet );
88 }
89
90 if( !rootSheet->GetScreen() )
91 {
92 SCH_SCREEN* screen = new SCH_SCREEN( aSchematic );
93 screen->SetFileName( aFileName );
94 rootSheet->SetScreen( screen );
95 }
96
98 csaLoader.Load( aSchematic, rootSheet );
99
100 // SAVE SYMBOLS TO PROJECT LIBRARY:
101 SYMBOL_LIB_TABLE* libTable = PROJECT_SCH::SchSymbolLibTable( &aSchematic->Prj() );
102
103 wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
104
105 wxFileName prj_fn = aSchematic->Prj().GetProjectFullName();
106 wxString libName = CADSTAR_SCH_ARCHIVE_LOADER::CreateLibName( prj_fn, nullptr );
107
108 wxFileName libFileName( aSchematic->Prj().GetProjectPath(), libName,
110
111 IO_RELEASER<SCH_IO> sch_plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
112
113 if( !libTable->HasLibrary( libName ) )
114 {
115 // Create a new empty symbol library.
116 sch_plugin->CreateLibrary( libFileName.GetFullPath() );
117 wxString libTableUri = "${KIPRJMOD}/" + libFileName.GetFullName();
118
119 // Add the new library to the project symbol library table.
120 libTable->InsertRow(
121 new SYMBOL_LIB_TABLE_ROW( libName, libTableUri, wxString( "KiCad" ) ) );
122
123 // Save project symbol library table.
124 wxFileName libtab_fn( aSchematic->Prj().GetProjectPath(),
126
127 // So output formatter goes out of scope and closes the file before reloading.
128 {
129 FILE_OUTPUTFORMATTER formatter( libtab_fn.GetFullPath() );
130 libTable->Format( &formatter, 0 );
131 }
132
133 // Relaod the symbol library table.
134 aSchematic->Prj().SetElem( PROJECT::ELEM::SYMBOL_LIB_TABLE, NULL );
135 PROJECT_SCH::SchSymbolLibTable( &aSchematic->Prj() );
136 }
137
138 // set properties to prevent save file on every symbol save
139 std::map<std::string, UTF8> properties;
140 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, "" );
141
142 for( LIB_SYMBOL* const& symbol : csaLoader.GetLoadedSymbols() )
143 sch_plugin->SaveSymbol( libFileName.GetFullPath(), symbol, &properties );
144
145 sch_plugin->SaveLibrary( libFileName.GetFullPath() );
146
147 // Link up all symbols in the design to the newly created library
148 for( SCH_SHEET_PATH& sheet : aSchematic->Hierarchy() )
149 {
150 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
151 {
152 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
153
154 if( sym->GetLibId().IsLegacy() )
155 {
156 LIB_ID libid = sym->GetLibId();
157 libid.SetLibNickname( libName );
158 sym->SetLibId( libid );
159 }
160 };
161 }
162
163 // Need to fix up junctions after import to retain connectivity
164 aSchematic->FixupJunctions();
165
166 return rootSheet;
167}
168
169
170void SCH_IO_CADSTAR_ARCHIVE::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
171 const wxString& aLibraryPath,
172 const std::map<std::string, UTF8>* aProperties )
173{
174 ensureLoadedLibrary( aLibraryPath, aProperties );
175
176 for( auto& [libnameStr, libSymbol] : m_libCache )
177 aSymbolNameList.Add( libSymbol->GetName() );
178}
179
180
181void SCH_IO_CADSTAR_ARCHIVE::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
182 const wxString& aLibraryPath,
183 const std::map<std::string, UTF8>* aProperties )
184{
185 ensureLoadedLibrary( aLibraryPath, aProperties );
186
187 for( auto& [libnameStr, libSymbol] : m_libCache )
188 aSymbolList.push_back( libSymbol.get() );
189}
190
191
192LIB_SYMBOL* SCH_IO_CADSTAR_ARCHIVE::LoadSymbol( const wxString& aLibraryPath,
193 const wxString& aAliasName,
194 const std::map<std::string, UTF8>* aProperties )
195{
196 ensureLoadedLibrary( aLibraryPath, aProperties );
197
198 if( m_libCache.count( aAliasName ) )
199 return m_libCache.at( aAliasName ).get();
200
201 return nullptr;
202}
203
204
205void SCH_IO_CADSTAR_ARCHIVE::GetAvailableSymbolFields( std::vector<wxString>& aNames )
206{
207 std::set<wxString> fieldNames;
208
209 for( auto& [libnameStr, libSymbol] : m_libCache )
210 {
211 std::vector<SCH_FIELD*> fields;
212 libSymbol->GetFields( fields );
213
214 for( SCH_FIELD* field : fields )
215 {
216 if( field->IsMandatory() )
217 continue;
218
219 fieldNames.insert( field->GetName() );
220 }
221 }
222
223 std::copy( fieldNames.begin(), fieldNames.end(), std::back_inserter( aNames ) );
224}
225
226
227void SCH_IO_CADSTAR_ARCHIVE::GetLibraryOptions( std::map<std::string, UTF8>* aListToAppendTo ) const
228{
229 ( *aListToAppendTo )["csa"] =
230 UTF8( _( "Path to the CADSTAR schematic archive (*.csa) file related to this CADSTAR "
231 "parts library. If none specified it is assumed to be 'symbol.csa' in the "
232 "same folder." ) );
233
234 ( *aListToAppendTo )["fplib"] =
235 UTF8( _( "Name of the footprint library related to the symbols in this library. You "
236 "should create a separate entry for the CADSTAR PCB Archive (*.cpa) file in "
237 "the footprint library tables. If none specified, 'cadstarpcblib' is assumed." ) );
238}
239
240
241void SCH_IO_CADSTAR_ARCHIVE::ensureLoadedLibrary( const wxString& aLibraryPath,
242 const std::map<std::string, UTF8>* aProperties )
243{
244 wxFileName csafn;
245 wxString fplibname = "cadstarpcblib";
246
247 // Suppress font substitution warnings
249
250 if( aProperties && aProperties->contains( "csa" ) )
251 {
252 csafn = wxFileName( aProperties->at( "csa" ) );
253
254 if( !csafn.IsAbsolute() )
255 {
256 wxFileName libDir( aLibraryPath );
257 libDir.ClearExt();
258 libDir.SetName( "" );
259 // wxPATH_NORM_ALL is deprecated in wxWidgets 3.1, so use our flags
260 csafn.Normalize( FN_NORMALIZE_FLAGS, libDir.GetAbsolutePath() );
261 }
262 }
263 else
264 {
265 // If none specified, look for the
266 // .csa file in same folder as the .lib
267 csafn = wxFileName( aLibraryPath );
268 csafn.SetExt( "csa" );
269
270 if( !csafn.FileExists() )
271 {
272 csafn.SetName( "symbol" );
273
274 if( !csafn.FileExists() )
275 {
276 csafn = wxDir::FindFirst( csafn.GetPath(), wxS( "*.csa" ),
277 wxDIR_FILES | wxDIR_HIDDEN );
278
279 if( !csafn.FileExists() )
280 {
281 THROW_IO_ERROR( wxString::Format(
282 _( "Cannot find the .csa file corresponding to library '%s'." ),
283 aLibraryPath ) );
284 }
285 }
286 }
287 }
288
289 if( aProperties && aProperties->contains( "fplib" ) )
290 {
291 fplibname = aProperties->at( "fplib" );
292 }
293
294 // Get timestamp
295 long long timestamp = 0;
296 wxFileName fn( aLibraryPath );
297
298 if( fn.IsFileReadable() )
299 timestamp = fn.GetModificationTime().GetValue().GetValue();
300
301
302 if( fn.IsFileReadable()
303 && m_cachePath == aLibraryPath
304 && m_cachecsafn.GetFullPath() == csafn.GetFullPath()
305 && m_cachefplibname == fplibname
306 && m_cacheTimestamp == timestamp )
307 {
308 return;
309 }
310
311 // Update cache
312 m_libCache.clear();
313
314 CADSTAR_SCH_ARCHIVE_LOADER csaLoader( csafn.GetFullPath(), m_reporter, m_progressReporter );
315 csaLoader.SetFpLibName( fplibname );
316
317 std::vector<LIB_SYMBOL*> symbols = csaLoader.LoadPartsLib( aLibraryPath );
318
319 for( LIB_SYMBOL* sym : symbols )
320 {
321 m_libCache.insert( { sym->GetName(), std::unique_ptr<LIB_SYMBOL>( sym ) } );
322 }
323
324 m_cachePath = aLibraryPath;
325 m_cachecsafn = csafn;
326 m_cachefplibname = fplibname;
327 m_cacheTimestamp = timestamp;
328}
329
Loads a csa file into a KiCad SCHEMATIC object.
bool CheckFileHeader(const std::filesystem::path &aPath) const
const std::vector< LIB_SYMBOL * > & GetLoadedSymbols() const
void Load(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet)
Loads a CADSTAR Schematic Archive file into the KiCad SCHEMATIC object given.
static wxString CreateLibName(const wxFileName &aFileName, const SCH_SHEET *aRootSheet)
std::vector< LIB_SYMBOL * > LoadPartsLib(const wxString &aFilename)
void SetFpLibName(const wxString &aLibName)
Used for text file output.
Definition: richio.h:491
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition: io_base.h:218
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition: io_base.h:221
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition: io_base.cpp:69
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition: lib_id.cpp:99
bool IsLegacy() const
Definition: lib_id.h:180
Define a library symbol object.
Definition: lib_symbol.h:78
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:129
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition: project.cpp:348
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
Holds all the data relating to one schematic.
Definition: schematic.h:77
void FixupJunctions()
Add junctions to this schematic where required.
Definition: schematic.cpp:738
SCH_SHEET_LIST Hierarchy() const override
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:214
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:194
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:141
SCH_SHEET & Root() const
Definition: schematic.h:125
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:92
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
int GetModifyHash() const override
Return the modification hash from the library cache.
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
void ensureLoadedLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties)
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
void GetLibraryOptions(std::map< std::string, UTF8 > *aListToAppendTo) const override
Append supported SCH_IO options to aListToAppenTo along with internationalized descriptions.
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
NAME_TO_SYMBOL_MAP m_libCache
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:168
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:118
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
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:311
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:109
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:172
Schematic symbol object.
Definition: sch_symbol.h:77
void SetLibId(const LIB_ID &aName)
Definition: sch_symbol.cpp:264
const LIB_ID & GetLibId() const override
Definition: sch_symbol.h:166
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_IO object i...
static const wxString & GetSymbolLibTableFileName()
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indentation level of aIndentLevel.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:72
static REPORTER & GetInstance()
Definition: reporter.cpp:199
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
Definition: fontconfig.cpp:64
#define _(s)
static const std::string KiCadSymbolLibFileExtension
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 THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
@ SCH_SYMBOL_T
Definition: typeinfo.h:172
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:39