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