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 wxFileName prj_fn = aSchematic->Prj().GetProjectFullName();
102 wxString libName = CADSTAR_SCH_ARCHIVE_LOADER::CreateLibName( prj_fn, nullptr );
103
104 wxFileName libFileName( aSchematic->Prj().GetProjectPath(), libName,
106
107 IO_RELEASER<SCH_IO> sch_plugin( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
108
109 if( !libTable->HasLibrary( libName ) )
110 {
111 // Create a new empty symbol library.
112 sch_plugin->CreateLibrary( libFileName.GetFullPath() );
113 wxString libTableUri = "${KIPRJMOD}/" + libFileName.GetFullName();
114
115 // Add the new library to the project symbol library table.
116 libTable->InsertRow(
117 new SYMBOL_LIB_TABLE_ROW( libName, libTableUri, wxString( "KiCad" ) ) );
118
119 // Save project symbol library table.
120 wxFileName libtab_fn( aSchematic->Prj().GetProjectPath(),
122
123 // So output formatter goes out of scope and closes the file before reloading.
124 {
125 FILE_OUTPUTFORMATTER formatter( libtab_fn.GetFullPath() );
126 libTable->Format( &formatter, 0 );
127 }
128
129 // Relaod the symbol library table.
130 aSchematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
131 PROJECT_SCH::SchSymbolLibTable( &aSchematic->Prj() );
132 }
133
134 // set properties to prevent save file on every symbol save
135 STRING_UTF8_MAP properties;
136 properties.emplace( SCH_IO_KICAD_SEXPR::PropBuffering, "" );
137
138 for( LIB_SYMBOL* const& symbol : csaLoader.GetLoadedSymbols() )
139 sch_plugin->SaveSymbol( libFileName.GetFullPath(), symbol, &properties );
140
141 sch_plugin->SaveLibrary( libFileName.GetFullPath() );
142
143 // Link up all symbols in the design to the newly created library
144 for( SCH_SHEET_PATH& sheet : aSchematic->BuildUnorderedSheetList() )
145 {
146 for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
147 {
148 SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
149
150 if( sym->GetLibId().IsLegacy() )
151 {
152 LIB_ID libid = sym->GetLibId();
153 libid.SetLibNickname( libName );
154 sym->SetLibId( libid );
155 }
156 };
157 }
158
159 // Need to fix up junctions after import to retain connectivity
160 aSchematic->FixupJunctions();
161
162 return rootSheet;
163}
164
165
166void SCH_IO_CADSTAR_ARCHIVE::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
167 const wxString& aLibraryPath,
168 const STRING_UTF8_MAP* aProperties )
169{
170 ensureLoadedLibrary( aLibraryPath, aProperties );
171
172 for( auto& [libnameStr, libSymbol] : m_libCache )
173 aSymbolNameList.Add( libSymbol->GetName() );
174}
175
176
177void SCH_IO_CADSTAR_ARCHIVE::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
178 const wxString& aLibraryPath,
179 const STRING_UTF8_MAP* aProperties )
180{
181 ensureLoadedLibrary( aLibraryPath, aProperties );
182
183 for( auto& [libnameStr, libSymbol] : m_libCache )
184 aSymbolList.push_back( libSymbol.get() );
185}
186
187
188LIB_SYMBOL* SCH_IO_CADSTAR_ARCHIVE::LoadSymbol( const wxString& aLibraryPath,
189 const wxString& aAliasName,
190 const STRING_UTF8_MAP* aProperties )
191{
192 ensureLoadedLibrary( aLibraryPath, aProperties );
193
194 if( m_libCache.count( aAliasName ) )
195 return m_libCache.at( aAliasName ).get();
196
197 return nullptr;
198}
199
200
201void SCH_IO_CADSTAR_ARCHIVE::GetAvailableSymbolFields( std::vector<wxString>& aNames )
202{
203 std::set<wxString> fieldNames;
204
205 for( auto& [libnameStr, libSymbol] : m_libCache )
206 {
207 std::vector<SCH_FIELD*> fields;
208 libSymbol->GetFields( fields );
209
210 for( SCH_FIELD* field : fields )
211 {
212 if( field->IsMandatory() )
213 continue;
214
215 fieldNames.insert( field->GetName() );
216 }
217 }
218
219 std::copy( fieldNames.begin(), fieldNames.end(), std::back_inserter( aNames ) );
220}
221
222
224{
225 ( *aListToAppendTo )["csa"] =
226 UTF8( _( "Path to the CADSTAR schematic archive (*.csa) file related to this CADSTAR "
227 "parts library. If none specified it is assumed to be 'symbol.csa' in the "
228 "same folder." ) );
229
230 ( *aListToAppendTo )["fplib"] =
231 UTF8( _( "Name of the footprint library related to the symbols in this library. You "
232 "should create a separate entry for the CADSTAR PCB Archive (*.cpa) file in "
233 "the footprint library tables. If none specified, 'cadstarpcblib' is assumed." ) );
234}
235
236
237void SCH_IO_CADSTAR_ARCHIVE::ensureLoadedLibrary( const wxString& aLibraryPath,
238 const STRING_UTF8_MAP* aProperties )
239{
240 wxFileName csafn;
241 wxString fplibname = "cadstarpcblib";
242
243 if( aProperties && aProperties->count( "csa" ) )
244 {
245 csafn = wxFileName( aProperties->at( "csa" ) );
246
247 if( !csafn.IsAbsolute() )
248 {
249 wxFileName libDir( aLibraryPath );
250 libDir.ClearExt();
251 libDir.SetName( "" );
252 // wxPATH_NORM_ALL is deprecated in wxWidgets 3.1, so use our flags
253 csafn.Normalize( FN_NORMALIZE_FLAGS, libDir.GetAbsolutePath() );
254 }
255 }
256 else
257 {
258 // If none specified, look for the
259 // .csa file in same folder as the .lib
260 csafn = wxFileName( aLibraryPath );
261 csafn.SetExt( "csa" );
262
263 if( !csafn.FileExists() )
264 {
265 csafn.SetName( "symbol" );
266
267 if( !csafn.FileExists() )
268 {
269 csafn = wxDir::FindFirst( csafn.GetPath(), wxS( "*.csa" ),
270 wxDIR_FILES | wxDIR_HIDDEN );
271
272 if( !csafn.FileExists() )
273 {
274 THROW_IO_ERROR( wxString::Format(
275 _( "Cannot find the .csa file corresponding to library '%s'." ),
276 aLibraryPath ) );
277 }
278 }
279 }
280 }
281
282 if( aProperties && aProperties->count( "fplib" ) )
283 {
284 fplibname = aProperties->at( "fplib" ).wx_str();
285 }
286
287 // Get timestamp
288 long long timestamp = 0;
289 wxFileName fn( aLibraryPath );
290
291 if( fn.IsFileReadable() )
292 timestamp = fn.GetModificationTime().GetValue().GetValue();
293
294
295 if( fn.IsFileReadable()
296 && m_cachePath == aLibraryPath
297 && m_cachecsafn.GetFullPath() == csafn.GetFullPath()
298 && m_cachefplibname == fplibname
299 && m_cacheTimestamp == timestamp )
300 {
301 return;
302 }
303
304 // Update cache
305 m_libCache.clear();
306
307 CADSTAR_SCH_ARCHIVE_LOADER csaLoader( csafn.GetFullPath(), m_reporter, m_progressReporter );
308 csaLoader.SetFpLibName( fplibname );
309
310 std::vector<LIB_SYMBOL*> symbols = csaLoader.LoadPartsLib( aLibraryPath );
311
312 for( LIB_SYMBOL* sym : symbols )
313 {
314 m_libCache.insert( { sym->GetName(), std::unique_ptr<LIB_SYMBOL>( sym ) } );
315 }
316
317 m_cachePath = aLibraryPath;
318 m_cachecsafn = csafn;
319 m_cachefplibname = fplibname;
320 m_cacheTimestamp = timestamp;
321}
322
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:475
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition: io_base.h:215
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition: io_base.h:218
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: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 GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:129
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:135
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
SCH_SHEET_LIST BuildUnorderedSheetList() const
Definition: schematic.h:100
void FixupJunctions()
Add junctions to this schematic where required.
Definition: schematic.cpp:726
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:186
bool IsValid() const
A simple test if the schematic is loaded, not a complete one.
Definition: schematic.h:128
SCH_SHEET & Root() const
Definition: schematic.h:112
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:166
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:117
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
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:172
Schematic symbol object.
Definition: sch_symbol.h:105
void SetLibId(const LIB_ID &aName)
Definition: sch_symbol.cpp:217
const LIB_ID & GetLibId() const override
Definition: sch_symbol.h:179
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
#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