KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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
39#include <symbol_library.h>
41
42#include <wx/log.h>
43#include <wx/progdlg.h>
44#include <wx/tokenzr.h>
45#include "sim/sim_model.h"
46
47SYMBOL_LIB::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
70{
71}
72
73
74void 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 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 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
124{
126}
127
128
129void SYMBOL_LIB::EnableBuffering( bool aEnable )
130{
131 if( aEnable )
132 (*m_properties)[ SCH_IO_KICAD_LEGACY::PropBuffering ] = "";
133 else
135}
136
137
138void 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 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* 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<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
236SYMBOL_LIB* SYMBOL_LIB::LoadSymbolLibrary( const wxString& aFileName )
237{
238 std::unique_ptr<SYMBOL_LIB> lib = std::make_unique<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 SYMBOL_LIB* ret = lib.release();
256 return ret;
257}
258
259
260SYMBOL_LIB* SYMBOL_LIBS::AddLibrary( const wxString& aFileName )
261{
262 SYMBOL_LIB* lib;
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 = SYMBOL_LIB::LoadSymbolLibrary( aFileName );
274 push_back( lib );
275
276 return lib;
277 }
278 catch( ... )
279 {
280 return nullptr;
281 }
282}
283
284
285SYMBOL_LIB* SYMBOL_LIBS::AddLibrary( const wxString& aFileName, SYMBOL_LIBS::iterator& aIterator )
286{
287 // Don't reload the library if it is already loaded.
288 wxFileName fn( aFileName );
289 SYMBOL_LIB* lib = FindLibrary( fn.GetName() );
290
291 if( lib )
292 return lib;
293
294 try
295 {
296 lib = 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 SYMBOL_LIBS::ReloadLibrary( const wxString &aFileName )
313{
314 wxFileName fn = aFileName;
315 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 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 = 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
355SYMBOL_LIB* SYMBOL_LIBS::FindLibrary( const wxString& aName )
356{
357 for( 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( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
370 {
371 if( it->IsCache() )
372 return &*it;
373 }
374
375 return nullptr;
376}
377
378
379SYMBOL_LIB* SYMBOL_LIBS::FindLibraryByFullFileName( const wxString& aFullFileName )
380{
381 for( 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 SYMBOL_LIBS::GetLibraryNames( bool aSorted )
392{
393 wxArrayString cacheNames;
394 wxArrayString names;
395
396 for( 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* SYMBOL_LIBS::FindLibSymbol( const LIB_ID& aLibId, const wxString& aLibraryName )
416{
417 LIB_SYMBOL* part = nullptr;
418
419 for( 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 SYMBOL_LIBS::FindLibraryNearEntries( std::vector<LIB_SYMBOL*>& aCandidates,
435 const wxString& aEntryName,
436 const wxString& aLibraryName )
437{
438 for( 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 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 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 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 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 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
Definition: DXF_plotter.cpp:59
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.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
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:118
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
Define a library symbol object.
Definition: lib_symbol.h:84
wxString GetName() const override
Definition: lib_symbol.h:148
void SetLib(SYMBOL_LIB *aLibrary)
Definition: lib_symbol.h:211
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:95
SYMBOL_LIB * GetLib() const
Definition: lib_symbol.h:210
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:72
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
Definition: project_sch.cpp:41
Container for project specific data.
Definition: project.h:64
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:140
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:200
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:164
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.
Definition: search_stack.h:43
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.
static void SetLibNamesAndPaths(PROJECT *aProject, const wxString &aPaths, const wxArrayString &aNames)
SYMBOL_LIB * FindLibrary(const wxString &aName)
Find a symbol library by aName.
SYMBOL_LIB * FindLibraryByFullFileName(const wxString &aFullFileName)
wxArrayString GetLibraryNames(bool aSorted=true)
Return the list of symbol library file names without path and extension.
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it.
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.
LIB_SYMBOL * FindLibSymbol(const LIB_ID &aLibId, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a symbol.
SYMBOL_LIB * AddLibrary(const wxString &aFileName)
Allocate and adds a symbol library to the library list.
static void GetLibNamesAndPaths(PROJECT *aProject, wxString *aPaths, wxArrayString *aNames=nullptr)
SYMBOL_LIB * GetCacheLibrary()
Object used to load, save, search, and otherwise manipulate symbol library files.
std::unique_ptr< SCH_IO > m_plugin
SCH_IO_MGR::SCH_FILE_T m_pluginType
void Create(const wxString &aFileName=wxEmptyString)
void GetSymbols(std::vector< LIB_SYMBOL * > &aSymbols) const
Load a vector with all the entries in this library.
bool IsBuffering() const
bool IsCache() const
std::unique_ptr< std::map< std::string, UTF8 > > m_properties
Library properties.
void SetPluginType(SCH_IO_MGR::SCH_FILE_T aPluginType)
SCH_LIB_TYPE type
Library type indicator.
SYMBOL_LIB(SCH_LIB_TYPE aType, const wxString &aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType=SCH_IO_MGR::SCH_LEGACY)
void EnableBuffering(bool aEnable=true)
void Save(bool aSaveDocFile=true)
LIB_SYMBOL * FindSymbol(const wxString &aName) const
Find LIB_SYMBOL by aName.
void AddSymbol(LIB_SYMBOL *aSymbol)
Add aSymbol entry to library.
static SYMBOL_LIB * LoadSymbolLibrary(const wxString &aFileName)
Allocate and load a symbol library file.
bool isModified
Library modification status.
void GetSymbolNames(wxArrayString &aNames) const
Load a string array with the names of all the entries in this library.
wxDateTime timeStamp
Library save time and date.
int versionMinor
Library minor version number.
int m_mod_hash
incremented each time library is changed.
LIB_SYMBOL * ReplaceSymbol(LIB_SYMBOL *aOldSymbol, LIB_SYMBOL *aNewSymbol)
Replace an existing symbol entry in the library.
wxFileName fileName
Library file name.
int versionMajor
Library major version number.
const wxString GetName() const
Return the file name without path or extension.
LIB_SYMBOL * RemoveSymbol(LIB_SYMBOL *aEntry)
Safely remove aEntry from the library and return the next entry.
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)
Definition: ki_exception.h:39
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:165
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.
Definition: string_utils.h:403
Definition for symbol library class.
VECTOR2I end
Definition of file extensions used in Kicad.