KiCad PCB EDA Suite
Loading...
Searching...
No Matches
legacy_symbol_library.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) 2004-2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 2022 CERN
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27#include <algorithm>
28#include <kiface_base.h>
29#include <eda_base_frame.h>
30#include <string_utils.h>
31#include <macros.h>
32#include <richio.h>
35#include <project_rescue.h>
36#include <project_sch.h>
38
41
42#include <wx/log.h>
43#include <wx/progdlg.h>
44#include <wx/tokenzr.h>
45#include <sim/sim_model.h>
46
47LEGACY_SYMBOL_LIB::LEGACY_SYMBOL_LIB( SCH_LIB_TYPE aType, const wxString& aFileName,
48 SCH_IO_MGR::SCH_FILE_T aPluginType ) :
49 m_pluginType( aPluginType )
50{
51 type = aType;
52 isModified = false;
53 timeStamp = 0;
54 timeStamp = wxDateTime::Now();
55 versionMajor = 0; // Will be updated after reading the lib file
56 versionMinor = 0; // Will be updated after reading the lib file
57
58 fileName = aFileName;
59
60 if( !fileName.IsOk() )
61 fileName = "unnamed.lib";
62
63 m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
64 m_properties = std::make_unique<std::map<std::string, UTF8>>();
65 m_mod_hash = 0;
66}
67
68
72
73
74void LEGACY_SYMBOL_LIB::Save( bool aSaveDocFile )
75{
76 wxCHECK_RET( m_plugin != nullptr,
77 wxString::Format( wxT( "no plugin defined for library `%s`." ),
78 fileName.GetFullPath() ) );
79
80 std::map<std::string, UTF8> props;
81
82 if( !aSaveDocFile )
84
85 m_plugin->SaveLibrary( fileName.GetFullPath(), &props );
86 isModified = false;
87}
88
89
90void LEGACY_SYMBOL_LIB::Create( const wxString& aFileName )
91{
92 wxString tmpFileName = fileName.GetFullPath();
93
94 if( !aFileName.IsEmpty() )
95 tmpFileName = aFileName;
96
97 m_plugin->CreateLibrary( tmpFileName, m_properties.get() );
98}
99
100
101void LEGACY_SYMBOL_LIB::SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType )
102{
103 if( m_pluginType != aPluginType )
104 {
105 m_pluginType = aPluginType;
106 m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
107 }
108}
109
110
112{
114}
115
116
118{
119 (*m_properties)[ SCH_IO_KICAD_LEGACY::PropNoDocFile ] = "";
120}
121
122
127
128
130{
131 if( aEnable )
132 (*m_properties)[ SCH_IO_KICAD_LEGACY::PropBuffering ] = "";
133 else
135}
136
137
138void LEGACY_SYMBOL_LIB::GetSymbolNames( wxArrayString& aNames ) const
139{
140 m_plugin->EnumerateSymbolLib( aNames, fileName.GetFullPath(), m_properties.get() );
141
142 aNames.Sort();
143}
144
145
146void LEGACY_SYMBOL_LIB::GetSymbols( std::vector<LIB_SYMBOL*>& aSymbols ) const
147{
148 m_plugin->EnumerateSymbolLib( aSymbols, fileName.GetFullPath(), m_properties.get() );
149
150 std::sort( aSymbols.begin(), aSymbols.end(),
151 [](LIB_SYMBOL *lhs, LIB_SYMBOL *rhs) -> bool
152 {
153 return lhs->GetName() < rhs->GetName();
154 } );
155}
156
157
158LIB_SYMBOL* LEGACY_SYMBOL_LIB::FindSymbol( const wxString& aName ) const
159{
160 LIB_SYMBOL* symbol = m_plugin->LoadSymbol( fileName.GetFullPath(), aName, m_properties.get() );
161
162 if( symbol )
163 {
164 // Set the library to this even though technically the legacy cache plugin owns the
165 // symbols. This allows the symbol library table conversion tool to determine the
166 // correct library where the symbol was found.
167 if( !symbol->GetLib() )
168 symbol->SetLib( const_cast<LEGACY_SYMBOL_LIB*>( this ) );
169
170 SIM_MODEL::MigrateSimModel<LIB_SYMBOL>( *symbol, nullptr );
171 }
172
173 return symbol;
174}
175
176
178{
179 return FindSymbol( aLibId.Format().wx_str() );
180}
181
182
184{
185 // add a clone, not the caller's copy, the plugin take ownership of the new symbol.
186 m_plugin->SaveSymbol( fileName.GetFullPath(),
187 new LIB_SYMBOL( *aSymbol->SharedPtr().get(), this ),
188 m_properties.get() );
189
190 // If we are not buffering, the library file is updated immediately when the plugin
191 // SaveSymbol() function is called.
192 if( IsBuffering() )
193 isModified = true;
194
195 ++m_mod_hash;
196}
197
198
200{
201 wxCHECK_MSG( aEntry != nullptr, nullptr, "NULL pointer cannot be removed from library." );
202
203 m_plugin->DeleteSymbol( fileName.GetFullPath(), aEntry->GetName(), m_properties.get() );
204
205 // If we are not buffering, the library file is updated immediately when the plugin
206 // SaveSymbol() function is called.
207 if( IsBuffering() )
208 isModified = true;
209
210 ++m_mod_hash;
211 return nullptr;
212}
213
214
216{
217 wxASSERT( aOldSymbol != nullptr );
218 wxASSERT( aNewSymbol != nullptr );
219
220 m_plugin->DeleteSymbol( fileName.GetFullPath(), aOldSymbol->GetName(), m_properties.get() );
221
222 LIB_SYMBOL* my_part = new LIB_SYMBOL( *aNewSymbol, this );
223
224 m_plugin->SaveSymbol( fileName.GetFullPath(), my_part, m_properties.get() );
225
226 // If we are not buffering, the library file is updated immediately when the plugin
227 // SaveSymbol() function is called.
228 if( IsBuffering() )
229 isModified = true;
230
231 ++m_mod_hash;
232 return my_part;
233}
234
235
237{
238 std::unique_ptr<LEGACY_SYMBOL_LIB> lib = std::make_unique<LEGACY_SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
239 aFileName );
240
241 std::vector<LIB_SYMBOL*> parts;
242 // This loads the library.
243 lib->GetSymbols( parts );
244
245 // Now, set the LIB_SYMBOL m_library member but it will only be used
246 // when loading legacy libraries in the future. Once the symbols in the
247 // schematic have a full #LIB_ID, this will not get called.
248 for( size_t ii = 0; ii < parts.size(); ii++ )
249 {
250 LIB_SYMBOL* part = parts[ii];
251
252 part->SetLib( lib.get() );
253 }
254
255 LEGACY_SYMBOL_LIB* ret = lib.release();
256 return ret;
257}
258
259
261{
263
264 wxFileName fn = aFileName;
265 // Don't reload the library if it is already loaded.
266 lib = FindLibrary( fn.GetName() );
267
268 if( lib )
269 return lib;
270
271 try
272 {
273 lib = LEGACY_SYMBOL_LIB::LoadSymbolLibrary( aFileName );
274 push_back( lib );
275
276 return lib;
277 }
278 catch( ... )
279 {
280 return nullptr;
281 }
282}
283
284
285LEGACY_SYMBOL_LIB* LEGACY_SYMBOL_LIBS::AddLibrary( const wxString& aFileName, LEGACY_SYMBOL_LIBS::iterator& aIterator )
286{
287 // Don't reload the library if it is already loaded.
288 wxFileName fn( aFileName );
289 LEGACY_SYMBOL_LIB* lib = FindLibrary( fn.GetName() );
290
291 if( lib )
292 return lib;
293
294 try
295 {
296 lib = LEGACY_SYMBOL_LIB::LoadSymbolLibrary( aFileName );
297
298 if( aIterator >= begin() && aIterator < end() )
299 insert( aIterator, lib );
300 else
301 push_back( lib );
302
303 return lib;
304 }
305 catch( ... )
306 {
307 return nullptr;
308 }
309}
310
311
312bool LEGACY_SYMBOL_LIBS::ReloadLibrary( const wxString &aFileName )
313{
314 wxFileName fn = aFileName;
315 LEGACY_SYMBOL_LIB* lib = FindLibrary( fn.GetName() );
316
317 // Check if the library already exists.
318 if( !lib )
319 return false;
320
321 // Create a clone of the library pointer in case we need to re-add it
322 LEGACY_SYMBOL_LIB *cloneLib = lib;
323
324 // Try to find the iterator of the library
325 for( auto it = begin(); it != end(); ++it )
326 {
327 if( it->GetName() == fn.GetName() )
328 {
329 // Remove the old library and keep the pointer
330 lib = &*it;
331 release( it );
332 break;
333 }
334 }
335
336 // Try to reload the library
337 try
338 {
339 lib = LEGACY_SYMBOL_LIB::LoadSymbolLibrary( aFileName );
340
341 // If the library is successfully reloaded, add it back to the set.
342 push_back( lib );
343 return true;
344 }
345 catch( ... )
346 {
347 // If an exception occurs, ensure that the SYMBOL_LIBS remains unchanged
348 // by re-adding the old library back to the set.
349 push_back( cloneLib );
350 return false;
351 }
352}
353
354
356{
357 for( LEGACY_SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
358 {
359 if( it->GetName() == aName )
360 return &*it;
361 }
362
363 return nullptr;
364}
365
366
368{
369 for( LEGACY_SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
370 {
371 if( it->IsCache() )
372 return &*it;
373 }
374
375 return nullptr;
376}
377
378
380{
381 for( LEGACY_SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
382 {
383 if( it->GetFullFileName() == aFullFileName )
384 return &*it;
385 }
386
387 return nullptr;
388}
389
390
391wxArrayString LEGACY_SYMBOL_LIBS::GetLibraryNames( bool aSorted )
392{
393 wxArrayString cacheNames;
394 wxArrayString names;
395
396 for( LEGACY_SYMBOL_LIB& lib : *this )
397 {
398 if( lib.IsCache() && aSorted )
399 cacheNames.Add( lib.GetName() );
400 else
401 names.Add( lib.GetName() );
402 }
403
404 // Even sorted, the cache library is always at the end of the list.
405 if( aSorted )
406 names.Sort();
407
408 for( unsigned int i = 0; i<cacheNames.Count(); i++ )
409 names.Add( cacheNames.Item( i ) );
410
411 return names;
412}
413
414
415LIB_SYMBOL* LEGACY_SYMBOL_LIBS::FindLibSymbol( const LIB_ID& aLibId, const wxString& aLibraryName )
416{
417 LIB_SYMBOL* part = nullptr;
418
419 for( LEGACY_SYMBOL_LIB& lib : *this )
420 {
421 if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
422 continue;
423
424 part = lib.FindSymbol( aLibId.GetLibItemName().wx_str() );
425
426 if( part )
427 break;
428 }
429
430 return part;
431}
432
433
434void LEGACY_SYMBOL_LIBS::FindLibraryNearEntries( std::vector<LIB_SYMBOL*>& aCandidates,
435 const wxString& aEntryName,
436 const wxString& aLibraryName )
437{
438 for( LEGACY_SYMBOL_LIB& lib : *this )
439 {
440 if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
441 continue;
442
443 wxArrayString partNames;
444
445 lib.GetSymbolNames( partNames );
446
447 if( partNames.IsEmpty() )
448 continue;
449
450 for( size_t i = 0; i < partNames.size(); i++ )
451 {
452 if( partNames[i].CmpNoCase( aEntryName ) == 0 )
453 aCandidates.push_back( lib.FindSymbol( partNames[i] ) );
454 }
455 }
456}
457
458
459void LEGACY_SYMBOL_LIBS::GetLibNamesAndPaths( PROJECT* aProject, wxString* aPaths, wxArrayString* aNames )
460{
461 wxCHECK_RET( aProject, "Null PROJECT in GetLibNamesAndPaths" );
462
463 PROJECT_FILE& project = aProject->GetProjectFile();
464
465 if( aPaths )
466 *aPaths = project.m_LegacyLibDir;
467
468 if( aNames )
469 *aNames = project.m_LegacyLibNames;
470}
471
472
473void LEGACY_SYMBOL_LIBS::SetLibNamesAndPaths( PROJECT* aProject, const wxString& aPaths,
474 const wxArrayString& aNames )
475{
476 wxCHECK_RET( aProject, "Null PROJECT in SetLibNamesAndPaths" );
477
478 PROJECT_FILE& project = aProject->GetProjectFile();
479
480 project.m_LegacyLibDir = aPaths;
481 project.m_LegacyLibNames = aNames;
482}
483
484
485const wxString LEGACY_SYMBOL_LIBS::CacheName( const wxString& aFullProjectFilename )
486{
487 wxFileName filename( aFullProjectFilename );
488 wxString name = filename.GetName();
489
490 filename.SetName( name + "-cache" );
491 filename.SetExt( FILEEXT::LegacySymbolLibFileExtension );
492
493 if( filename.FileExists() )
494 return filename.GetFullPath();
495
496 // Try the old (2007) cache name
497 filename.SetName( name + ".cache" );
498
499 if( filename.FileExists() )
500 return filename.GetFullPath();
501
502 return wxEmptyString;
503}
504
505
506void LEGACY_SYMBOL_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress )
507{
508 wxString filename;
509 wxString libs_not_found;
510 SEARCH_STACK* lib_search = PROJECT_SCH::SchSearchS( aProject );
511
512#if defined(DEBUG) && 0
513 lib_search->Show( __func__ );
514#endif
515
516 wxArrayString lib_names;
517
518 GetLibNamesAndPaths( aProject, nullptr, &lib_names );
519
520 // Post symbol library table, this should be empty. Only the cache library should get loaded.
521 if( !lib_names.empty() )
522 {
523 APP_PROGRESS_DIALOG lib_dialog( _( "Loading Symbol Libraries" ),
524 wxEmptyString,
525 lib_names.GetCount(),
526 nullptr,
527 false,
528 wxPD_APP_MODAL );
529
530 if( aShowProgress )
531 {
532 lib_dialog.Show();
533 }
534
535 for( unsigned i = 0; i < lib_names.GetCount(); ++i )
536 {
537 if( aShowProgress )
538 {
539 lib_dialog.Update( i, wxString::Format( _( "Loading %s..." ), lib_names[i] ) );
540 }
541
542 // lib_names[] does not store the file extension. Set it.
543 // Remember lib_names[i] can contain a '.' in name, so using a wxFileName
544 // before adding the extension can create incorrect full filename
545 wxString fullname = lib_names[i] + "." + FILEEXT::LegacySymbolLibFileExtension;
546
547 // Now the full name is set, we can use a wxFileName.
548 wxFileName fn( fullname );
549
550 // Skip if the file name is not valid..
551 if( !fn.IsOk() )
552 continue;
553
554 if( !fn.FileExists() )
555 {
556 filename = lib_search->FindValidPath( fn.GetFullPath() );
557
558 if( !filename )
559 {
560 libs_not_found += fn.GetFullPath();
561 libs_not_found += '\n';
562 continue;
563 }
564 }
565 else
566 { // ensure the lib filename has a absolute path.
567 // If the lib has no absolute path, and is found in the cwd by fn.FileExists(),
568 // make a full absolute path, to avoid issues with load library functions which
569 // expects an absolute path.
570 if( !fn.IsAbsolute() )
571 fn.MakeAbsolute();
572
573 filename = fn.GetFullPath();
574 }
575
576 try
577 {
578 AddLibrary( filename );
579 }
580 catch( const IO_ERROR& ioe )
581 {
582 wxString msg;
583 msg.Printf( _( "Symbol library '%s' failed to load." ), filename );
584
585 wxLogError( msg + wxS( "\n" ) + ioe.What() );
586 }
587 }
588 }
589
590 // add the special cache library.
591 wxString cache_name = CacheName( aProject->GetProjectFullName() );
592 LEGACY_SYMBOL_LIB* cache_lib;
593
594 if( !aProject->IsNullProject() && !cache_name.IsEmpty() )
595 {
596 try
597 {
598 cache_lib = AddLibrary( cache_name );
599
600 if( cache_lib )
601 cache_lib->SetCache();
602 }
603 catch( const IO_ERROR& ioe )
604 {
605 wxString msg = wxString::Format( _( "Error loading symbol library '%s'." )
606 + wxS( "\n%s" ),
607 cache_name,
608 ioe.What() );
609
610 THROW_IO_ERROR( msg );
611 }
612 }
613
614 // Print the libraries not found
615 if( !libs_not_found.IsEmpty() )
616 {
617 // Use a different exception type so catch()er can route to proper use
618 // of the HTML_MESSAGE_BOX.
619 THROW_PARSE_ERROR( wxEmptyString, __func__, TO_UTF8( libs_not_found ), 0, 0 );
620 }
621}
const char * name
wxProgressDialog with the option to also update the application progress on the taskbar
virtual bool Update(int aValue, const wxString &aNewMsg=wxEmptyString, bool *aSkip=nullptr) override
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
LEGACY_SYMBOL_LIB * GetCacheLibrary()
wxArrayString GetLibraryNames(bool aSorted=true)
Return the list of symbol library file names without path and extension.
void FindLibraryNearEntries(std::vector< LIB_SYMBOL * > &aCandidates, const wxString &aEntryName, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a LIB_SYMBOL using a case insensitive comparison.
LEGACY_SYMBOL_LIB * FindLibraryByFullFileName(const wxString &aFullFileName)
static void GetLibNamesAndPaths(PROJECT *aProject, wxString *aPaths, wxArrayString *aNames=nullptr)
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it.
static void SetLibNamesAndPaths(PROJECT *aProject, const wxString &aPaths, const wxArrayString &aNames)
LEGACY_SYMBOL_LIB * FindLibrary(const wxString &aName)
Find a symbol library by aName.
LIB_SYMBOL * FindLibSymbol(const LIB_ID &aLibId, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a symbol.
LEGACY_SYMBOL_LIB * AddLibrary(const wxString &aFileName)
Allocate and adds a symbol library to the library list.
bool ReloadLibrary(const wxString &aFileName)
Refreshes the library from the (possibly updated) contents on disk.
static const wxString CacheName(const wxString &aFullProjectFilename)
Return the name of the cache library after potentially fixing it from an older naming scheme.
Object used to load, save, search, and otherwise manipulate symbol library files.
static LEGACY_SYMBOL_LIB * LoadSymbolLibrary(const wxString &aFileName)
Allocate and load a symbol library file.
wxFileName fileName
Library file name.
int versionMajor
Library major version number.
std::unique_ptr< std::map< std::string, UTF8 > > m_properties
Library properties.
void EnableBuffering(bool aEnable=true)
LIB_SYMBOL * ReplaceSymbol(LIB_SYMBOL *aOldSymbol, LIB_SYMBOL *aNewSymbol)
Replace an existing symbol entry in the library.
wxDateTime timeStamp
Library save time and date.
std::unique_ptr< SCH_IO > m_plugin
SCH_IO_MGR::SCH_FILE_T m_pluginType
LIB_SYMBOL * FindSymbol(const wxString &aName) const
Find LIB_SYMBOL by aName.
LIB_SYMBOL * RemoveSymbol(LIB_SYMBOL *aEntry)
Safely remove aEntry from the library and return the next entry.
void Create(const wxString &aFileName=wxEmptyString)
int m_mod_hash
incremented each time library is changed.
LEGACY_SYMBOL_LIB(SCH_LIB_TYPE aType, const wxString &aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType=SCH_IO_MGR::SCH_LEGACY)
void GetSymbolNames(wxArrayString &aNames) const
Load a string array with the names of all the entries in this library.
void AddSymbol(LIB_SYMBOL *aSymbol)
Add aSymbol entry to library.
const wxString GetName() const
Return the file name without path or extension.
void Save(bool aSaveDocFile=true)
bool isModified
Library modification status.
void GetSymbols(std::vector< LIB_SYMBOL * > &aSymbols) const
Load a vector with all the entries in this library.
int versionMinor
Library minor version number.
void SetPluginType(SCH_IO_MGR::SCH_FILE_T aPluginType)
SCH_LIB_TYPE type
Library type indicator.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
UTF8 Format() const
Definition lib_id.cpp:119
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
Define a library symbol object.
Definition lib_symbol.h:87
void SetLib(LEGACY_SYMBOL_LIB *aLibrary)
Definition lib_symbol.h:213
LEGACY_SYMBOL_LIB * GetLib() const
Definition lib_symbol.h:212
wxString GetName() const override
Definition lib_symbol.h:150
LIB_SYMBOL_SPTR SharedPtr() const
http://www.boost.org/doc/libs/1_55_0/libs/smart_ptr/sp_techniques.html#weak_without_shared.
Definition lib_symbol.h:97
The backing store for a PROJECT, in JSON format.
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
Container for project specific data.
Definition project.h:65
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:158
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition project.cpp:182
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
static const char * PropNoDocFile
The property used internally by the plugin to disable writing the library documentation (....
Look for files in a number of paths.
static void MigrateSimModel(T &aSymbol, const PROJECT *aProject)
wxString wx_str() const
Definition utf8.cpp:45
#define _(s)
Base window classes and related definitions.
static const std::string LegacySymbolLibFileExtension
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
This file contains miscellaneous commonly used macros and functions.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
VECTOR2I end
Definition of file extensions used in Kicad.