KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
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 <lib_symbol.h>
26#include <progress_reporter.h>
27#include <project_sch.h>
28#include <string_utf8_map.h>
29#include <sch_screen.h>
30#include <sch_sheet.h>
31#include <schematic.h>
34#include <wx_filename.h>
35#include <wx/dir.h>
36#include <wx/wfstream.h>
37#include <wx/txtstrm.h>
38
39
40bool SCH_IO_CADSTAR_ARCHIVE::CanReadLibrary( const wxString& aFileName ) const
41{
42 if( !SCH_IO::CanReadLibrary( aFileName ) )
43 return false;
44
45 try
46 {
48 return p.CheckFileHeader( aFileName.utf8_string() );
49 }
50 catch( const std::runtime_error& )
51 {
52 }
53
54 return false;
55}
56
57
59{
60 return 0;
61}
62
63
65 SCHEMATIC* aSchematic,
66 SCH_SHEET* aAppendToMe,
67 const STRING_UTF8_MAP* aProperties )
68{
69 wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr );
70
71 SCH_SHEET* rootSheet = nullptr;
72
73
74 if( aAppendToMe )
75 {
76 wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
77 rootSheet = &aSchematic->Root();
78 }
79 else
80 {
81 rootSheet = new SCH_SHEET( aSchematic );
82 rootSheet->SetFileName( aFileName );
83 aSchematic->SetRoot( rootSheet );
84 }
85
86 if( !rootSheet->GetScreen() )
87 {
88 SCH_SCREEN* screen = new SCH_SCREEN( aSchematic );
89 screen->SetFileName( aFileName );
90 rootSheet->SetScreen( screen );
91 }
92
94 csaLoader.Load( aSchematic, rootSheet );
95
96 // SAVE SYMBOLS TO PROJECT LIBRARY:
97 SYMBOL_LIB_TABLE* libTable = PROJECT_SCH::SchSymbolLibTable( &aSchematic->Prj() );
98
99 wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
100
101 // Lets come up with a nice library name
102 wxString libName = aSchematic->Prj().GetProjectName();
103
104 if( libName.IsEmpty() )
105 {
106 wxFileName fn( rootSheet->GetFileName() );
107 libName = fn.GetName();
108 }
109
110 if( libName.IsEmpty() )
111 libName = "noname";
112
113 libName = LIB_ID::FixIllegalChars( libName, true ).wx_str();
114
115 wxFileName libFileName( aSchematic->Prj().GetProjectPath(), libName,
117
118 IO_RELEASER<SCH_IO> sch_plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
119
120 if( !libTable->HasLibrary( libName ) )
121 {
122 // Create a new empty symbol library.
123 sch_plugin->CreateLibrary( libFileName.GetFullPath() );
124 wxString libTableUri = "${KIPRJMOD}/" + libFileName.GetFullName();
125
126 // Add the new library to the project symbol library table.
127 libTable->InsertRow(
128 new SYMBOL_LIB_TABLE_ROW( libName, libTableUri, wxString( "KiCad" ) ) );
129
130 // Save project symbol library table.
131 wxFileName fn( aSchematic->Prj().GetProjectPath(),
133
134 // So output formatter goes out of scope and closes the file before reloading.
135 {
136 FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
137 libTable->Format( &formatter, 0 );
138 }
139
140 // Relaod the symbol library table.
141 aSchematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
142 PROJECT_SCH::SchSymbolLibTable( &aSchematic->Prj() );
143 }
144
145 // set properties to prevent save file on every symbol save
146 STRING_UTF8_MAP properties;
147 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, "" );
148
149 for( LIB_SYMBOL* const& symbol : csaLoader.GetLoadedSymbols() )
150 sch_plugin->SaveSymbol( libFileName.GetFullPath(), symbol, &properties );
151
152 sch_plugin->SaveLibrary( libFileName.GetFullPath() );
153
154 // Link up all symbols in the design to the newly created library
155 for( SCH_SHEET_PATH& sheet : aSchematic->GetSheets() )
156 {
157 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
158 {
159 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
160
161 if( sym->GetLibId().IsLegacy() )
162 {
163 LIB_ID libid = sym->GetLibId();
164 libid.SetLibNickname( libName );
165 sym->SetLibId( libid );
166 }
167 };
168 }
169
170 // Need to fix up junctions after import to retain connectivity
171 aSchematic->FixupJunctions();
172
173 return rootSheet;
174}
175
176
177void SCH_IO_CADSTAR_ARCHIVE::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
178 const wxString& aLibraryPath,
179 const STRING_UTF8_MAP* aProperties )
180{
181 ensureLoadedLibrary( aLibraryPath, aProperties );
182
183 for( auto& [libnameStr, libSymbol] : m_libCache )
184 aSymbolNameList.Add( libSymbol->GetName() );
185}
186
187
188void SCH_IO_CADSTAR_ARCHIVE::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
189 const wxString& aLibraryPath,
190 const STRING_UTF8_MAP* aProperties )
191{
192 ensureLoadedLibrary( aLibraryPath, aProperties );
193
194 for( auto& [libnameStr, libSymbol] : m_libCache )
195 aSymbolList.push_back( libSymbol.get() );
196}
197
198
199LIB_SYMBOL* SCH_IO_CADSTAR_ARCHIVE::LoadSymbol( const wxString& aLibraryPath,
200 const wxString& aAliasName,
201 const STRING_UTF8_MAP* aProperties )
202{
203 ensureLoadedLibrary( aLibraryPath, aProperties );
204
205 if( m_libCache.count( aAliasName ) )
206 return m_libCache.at( aAliasName ).get();
207
208 return nullptr;
209}
210
211
212void SCH_IO_CADSTAR_ARCHIVE::GetAvailableSymbolFields( std::vector<wxString>& aNames )
213{
214 std::set<wxString> fieldNames;
215
216 for( auto& [libnameStr, libSymbol] : m_libCache )
217 {
218 std::vector<SCH_FIELD*> fields;
219 libSymbol->GetFields( fields );
220
221 for( SCH_FIELD* field : fields )
222 {
223 if( field->IsMandatory() )
224 continue;
225
226 fieldNames.insert( field->GetName() );
227 }
228 }
229
230 std::copy( fieldNames.begin(), fieldNames.end(), std::back_inserter( aNames ) );
231}
232
233
235{
236 ( *aListToAppendTo )["csa"] =
237 UTF8( _( "Path to the CADSTAR schematic archive (*.csa) file related to this CADSTAR "
238 "parts library. If none specified it is assumed to be 'symbol.csa' in the "
239 "same folder." ) );
240
241 ( *aListToAppendTo )["fplib"] =
242 UTF8( _( "Name of the footprint library related to the symbols in this library. You "
243 "should create a separate entry for the CADSTAR PCB Archive (*.cpa) file in "
244 "the footprint library tables. If none specified, 'cadstarpcblib' is assumed." ) );
245}
246
247
248void SCH_IO_CADSTAR_ARCHIVE::ensureLoadedLibrary( const wxString& aLibraryPath,
249 const STRING_UTF8_MAP* aProperties )
250{
251 wxFileName csafn;
252 wxString fplibname = "cadstarpcblib";
253
254 if( aProperties && aProperties->count( "csa" ) )
255 {
256 csafn = wxFileName( aProperties->at( "csa" ) );
257
258 if( !csafn.IsAbsolute() )
259 {
260 wxFileName libDir( aLibraryPath );
261 libDir.ClearExt();
262 libDir.SetName( "" );
263 // wxPATH_NORM_ALL is deprecated in wxWidgets 3.1, so use our flags
264 csafn.Normalize( FN_NORMALIZE_FLAGS, libDir.GetAbsolutePath() );
265 }
266 }
267 else
268 {
269 // If none specified, look for the
270 // .csa file in same folder as the .lib
271 csafn = wxFileName( aLibraryPath );
272 csafn.SetExt( "csa" );
273
274 if( !csafn.FileExists() )
275 {
276 csafn.SetName( "symbol" );
277
278 if( !csafn.FileExists() )
279 {
280 csafn = wxDir::FindFirst( csafn.GetPath(), wxS( "*.csa" ),
281 wxDIR_FILES | wxDIR_HIDDEN );
282
283 if( !csafn.FileExists() )
284 {
285 THROW_IO_ERROR( wxString::Format(
286 _( "Cannot find the .csa file corresponding to library '%s'." ),
287 aLibraryPath ) );
288 }
289 }
290 }
291 }
292
293 if( aProperties && aProperties->count( "fplib" ) )
294 {
295 fplibname = aProperties->at( "fplib" ).wx_str();
296 }
297
298 // Get timestamp
299 long long timestamp = 0;
300 wxFileName fn( aLibraryPath );
301
302 if( fn.IsFileReadable() )
303 timestamp = fn.GetModificationTime().GetValue().GetValue();
304
305
306 if( fn.IsFileReadable()
307 && m_cachePath == aLibraryPath
308 && m_cachecsafn.GetFullPath() == csafn.GetFullPath()
309 && m_cachefplibname == fplibname
310 && m_cacheTimestamp == timestamp )
311 {
312 return;
313 }
314
315 // Update cache
316 m_libCache.clear();
317
318 CADSTAR_SCH_ARCHIVE_LOADER csaLoader( csafn.GetFullPath(), m_reporter, m_progressReporter );
319 csaLoader.SetFpLibName( fplibname );
320
321 std::vector<LIB_SYMBOL*> symbols = csaLoader.LoadPartsLib( aLibraryPath );
322
323 for( LIB_SYMBOL* sym : symbols )
324 {
325 m_libCache.insert( { sym->GetName(), std::unique_ptr<LIB_SYMBOL>( sym ) } );
326 }
327
328 m_cachePath = aLibraryPath;
329 m_cachecsafn = csafn;
330 m_cachefplibname = fplibname;
331 m_cacheTimestamp = timestamp;
332}
333
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.
std::vector< LIB_SYMBOL * > LoadPartsLib(const wxString &aFilename)
void SetFpLibName(const wxString &aLibName)
Used for text file output.
Definition: richio.h:475
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition: io_base.h:210
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition: io_base.h:213
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition: io_base.cpp:67
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
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:191
Define a library symbol object.
Definition: lib_symbol.h:77
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 GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition: project.cpp:147
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:309
@ ELEM_SYMBOL_LIB_TABLE
Definition: project.h:228
Holds all the data relating to one schematic.
Definition: schematic.h:75
void FixupJunctions()
Add junctions to this schematic where required.
Definition: schematic.cpp:721
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:100
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:184
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:121
SCH_SHEET & Root() const
Definition: schematic.h:105
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:90
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:51
int GetModifyHash() const override
Return the modification hash from the library cache.
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
SCH_SHEET * LoadSchematicFile(const wxString &aFileName, SCHEMATIC *aSchematic, SCH_SHEET *aAppendToMe=nullptr, const STRING_UTF8_MAP *aProperties=nullptr) override
Load information from some input file format that this SCH_IO implementation knows about,...
void ensureLoadedLibrary(const wxString &aLibraryPath, const STRING_UTF8_MAP *aProperties)
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const STRING_UTF8_MAP *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
void GetLibraryOptions(STRING_UTF8_MAP *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:174
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:115
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:312
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:306
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:162
Schematic symbol object.
Definition: sch_symbol.h:108
void SetLibId(const LIB_ID &aName)
Definition: sch_symbol.cpp:259
const LIB_ID & GetLibId() const override
Definition: sch_symbol.h:197
A name/value tuple with unique names and optional values.
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
wxString wx_str() const
Definition: utf8.cpp:45
#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