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 (C) 2004-2023 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>
37#include <string_utf8_map.h>
39
40#include <symbol_library.h>
42
43#include <wx/log.h>
44#include <wx/progdlg.h>
45#include <wx/tokenzr.h>
46#include "sim/sim_model.h"
47
48SYMBOL_LIB::SYMBOL_LIB( SCH_LIB_TYPE aType, const wxString& aFileName,
49 SCH_IO_MGR::SCH_FILE_T aPluginType ) :
50 m_pluginType( aPluginType )
51{
52 type = aType;
53 isModified = false;
54 timeStamp = 0;
55 timeStamp = wxDateTime::Now();
56 versionMajor = 0; // Will be updated after reading the lib file
57 versionMinor = 0; // Will be updated after reading the lib file
58
59 fileName = aFileName;
60
61 if( !fileName.IsOk() )
62 fileName = "unnamed.lib";
63
64 m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
65 m_properties = std::make_unique<STRING_UTF8_MAP>();
66 m_mod_hash = 0;
67}
68
69
71{
72}
73
74
75void SYMBOL_LIB::Save( bool aSaveDocFile )
76{
77 wxCHECK_RET( m_plugin != nullptr,
78 wxString::Format( wxT( "no plugin defined for library `%s`." ),
79 fileName.GetFullPath() ) );
80
81 STRING_UTF8_MAP props;
82
83 if( !aSaveDocFile )
85
86 m_plugin->SaveLibrary( fileName.GetFullPath(), &props );
87 isModified = false;
88}
89
90
91void SYMBOL_LIB::Create( const wxString& aFileName )
92{
93 wxString tmpFileName = fileName.GetFullPath();
94
95 if( !aFileName.IsEmpty() )
96 tmpFileName = aFileName;
97
98 m_plugin->CreateLibrary( tmpFileName, m_properties.get() );
99}
100
101
102void SYMBOL_LIB::SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType )
103{
104 if( m_pluginType != aPluginType )
105 {
106 m_pluginType = aPluginType;
107 m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
108 }
109}
110
111
113{
115}
116
117
119{
120 (*m_properties)[ SCH_IO_KICAD_LEGACY::PropNoDocFile ] = "";
121}
122
123
125{
127}
128
129
130void SYMBOL_LIB::EnableBuffering( bool aEnable )
131{
132 if( aEnable )
133 (*m_properties)[ SCH_IO_KICAD_LEGACY::PropBuffering ] = "";
134 else
136}
137
138
139void SYMBOL_LIB::GetSymbolNames( wxArrayString& aNames ) const
140{
141 m_plugin->EnumerateSymbolLib( aNames, fileName.GetFullPath(), m_properties.get() );
142
143 aNames.Sort();
144}
145
146
147void SYMBOL_LIB::GetSymbols( std::vector<LIB_SYMBOL*>& aSymbols ) const
148{
149 m_plugin->EnumerateSymbolLib( aSymbols, fileName.GetFullPath(), m_properties.get() );
150
151 std::sort( aSymbols.begin(), aSymbols.end(),
152 [](LIB_SYMBOL *lhs, LIB_SYMBOL *rhs) -> bool
153 {
154 return lhs->GetName() < rhs->GetName();
155 } );
156}
157
158
159LIB_SYMBOL* SYMBOL_LIB::FindSymbol( const wxString& aName ) const
160{
161 LIB_SYMBOL* symbol = m_plugin->LoadSymbol( fileName.GetFullPath(), aName, m_properties.get() );
162
163 if( symbol )
164 {
165 // Set the library to this even though technically the legacy cache plugin owns the
166 // symbols. This allows the symbol library table conversion tool to determine the
167 // correct library where the symbol was found.
168 if( !symbol->GetLib() )
169 symbol->SetLib( const_cast<SYMBOL_LIB*>( this ) );
170
171 SIM_MODEL::MigrateSimModel<LIB_SYMBOL, LIB_FIELD>( *symbol, nullptr );
172 }
173
174 return symbol;
175}
176
177
179{
180 return FindSymbol( aLibId.Format().wx_str() );
181}
182
183
185{
186 // add a clone, not the caller's copy, the plugin take ownership of the new symbol.
187 m_plugin->SaveSymbol( fileName.GetFullPath(),
188 new LIB_SYMBOL( *aSymbol->SharedPtr().get(), this ),
189 m_properties.get() );
190
191 // If we are not buffering, the library file is updated immediately when the plugin
192 // SaveSymbol() function is called.
193 if( IsBuffering() )
194 isModified = true;
195
196 ++m_mod_hash;
197}
198
199
201{
202 wxCHECK_MSG( aEntry != nullptr, nullptr, "NULL pointer cannot be removed from library." );
203
204 m_plugin->DeleteSymbol( fileName.GetFullPath(), aEntry->GetName(), m_properties.get() );
205
206 // If we are not buffering, the library file is updated immediately when the plugin
207 // SaveSymbol() function is called.
208 if( IsBuffering() )
209 isModified = true;
210
211 ++m_mod_hash;
212 return nullptr;
213}
214
215
217{
218 wxASSERT( aOldSymbol != nullptr );
219 wxASSERT( aNewSymbol != nullptr );
220
221 m_plugin->DeleteSymbol( fileName.GetFullPath(), aOldSymbol->GetName(), m_properties.get() );
222
223 LIB_SYMBOL* my_part = new LIB_SYMBOL( *aNewSymbol, this );
224
225 m_plugin->SaveSymbol( fileName.GetFullPath(), my_part, m_properties.get() );
226
227 // If we are not buffering, the library file is updated immediately when the plugin
228 // SaveSymbol() function is called.
229 if( IsBuffering() )
230 isModified = true;
231
232 ++m_mod_hash;
233 return my_part;
234}
235
236
237SYMBOL_LIB* SYMBOL_LIB::LoadSymbolLibrary( const wxString& aFileName )
238{
239 std::unique_ptr<SYMBOL_LIB> lib = std::make_unique<SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
240 aFileName );
241
242 std::vector<LIB_SYMBOL*> parts;
243 // This loads the library.
244 lib->GetSymbols( parts );
245
246 // Now, set the LIB_SYMBOL m_library member but it will only be used
247 // when loading legacy libraries in the future. Once the symbols in the
248 // schematic have a full #LIB_ID, this will not get called.
249 for( size_t ii = 0; ii < parts.size(); ii++ )
250 {
251 LIB_SYMBOL* part = parts[ii];
252
253 part->SetLib( lib.get() );
254 }
255
256 SYMBOL_LIB* ret = lib.release();
257 return ret;
258}
259
260
261SYMBOL_LIB* SYMBOL_LIBS::AddLibrary( const wxString& aFileName )
262{
263 SYMBOL_LIB* lib;
264
265 wxFileName fn = aFileName;
266 // Don't reload the library if it is already loaded.
267 lib = FindLibrary( fn.GetName() );
268
269 if( lib )
270 return lib;
271
272 try
273 {
274 lib = SYMBOL_LIB::LoadSymbolLibrary( aFileName );
275 push_back( lib );
276
277 return lib;
278 }
279 catch( ... )
280 {
281 return nullptr;
282 }
283}
284
285
286SYMBOL_LIB* SYMBOL_LIBS::AddLibrary( const wxString& aFileName, SYMBOL_LIBS::iterator& aIterator )
287{
288 // Don't reload the library if it is already loaded.
289 wxFileName fn( aFileName );
290 SYMBOL_LIB* lib = FindLibrary( fn.GetName() );
291
292 if( lib )
293 return lib;
294
295 try
296 {
297 lib = SYMBOL_LIB::LoadSymbolLibrary( aFileName );
298
299 if( aIterator >= begin() && aIterator < end() )
300 insert( aIterator, lib );
301 else
302 push_back( lib );
303
304 return lib;
305 }
306 catch( ... )
307 {
308 return nullptr;
309 }
310}
311
312
313bool SYMBOL_LIBS::ReloadLibrary( const wxString &aFileName )
314{
315 SYMBOL_LIB *lib;
316 wxFileName fn = aFileName;
317
318 // Check if the library already exists.
319 if( !( lib = FindLibrary( fn.GetName() ) ) )
320 return false;
321
322 // Create a clone of the library pointer in case we need to re-add it
323 SYMBOL_LIB *cloneLib = lib;
324
325 // Try to find the iterator of the library
326 for( auto it = begin(); it != end(); ++it )
327 {
328 if( it->GetName() == fn.GetName() )
329 {
330 // Remove the old library and keep the pointer
331 lib = &*it;
332 release( it );
333 break;
334 }
335 }
336
337 // Try to reload the library
338 try
339 {
340 lib = SYMBOL_LIB::LoadSymbolLibrary( aFileName );
341
342 // If the library is successfully reloaded, add it back to the set.
343 push_back( lib );
344 return true;
345 }
346 catch( ... )
347 {
348 // If an exception occurs, ensure that the SYMBOL_LIBS remains unchanged
349 // by re-adding the old library back to the set.
350 push_back( cloneLib );
351 return false;
352 }
353}
354
355
356SYMBOL_LIB* SYMBOL_LIBS::FindLibrary( const wxString& aName )
357{
358 for( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
359 {
360 if( it->GetName() == aName )
361 return &*it;
362 }
363
364 return nullptr;
365}
366
367
369{
370 for( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
371 {
372 if( it->IsCache() )
373 return &*it;
374 }
375
376 return nullptr;
377}
378
379
380SYMBOL_LIB* SYMBOL_LIBS::FindLibraryByFullFileName( const wxString& aFullFileName )
381{
382 for( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
383 {
384 if( it->GetFullFileName() == aFullFileName )
385 return &*it;
386 }
387
388 return nullptr;
389}
390
391
392wxArrayString SYMBOL_LIBS::GetLibraryNames( bool aSorted )
393{
394 wxArrayString cacheNames;
395 wxArrayString names;
396
397 for( SYMBOL_LIB& lib : *this )
398 {
399 if( lib.IsCache() && aSorted )
400 cacheNames.Add( lib.GetName() );
401 else
402 names.Add( lib.GetName() );
403 }
404
405 // Even sorted, the cache library is always at the end of the list.
406 if( aSorted )
407 names.Sort();
408
409 for( unsigned int i = 0; i<cacheNames.Count(); i++ )
410 names.Add( cacheNames.Item( i ) );
411
412 return names;
413}
414
415
416LIB_SYMBOL* SYMBOL_LIBS::FindLibSymbol( const LIB_ID& aLibId, const wxString& aLibraryName )
417{
418 LIB_SYMBOL* part = nullptr;
419
420 for( SYMBOL_LIB& lib : *this )
421 {
422 if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
423 continue;
424
425 part = lib.FindSymbol( aLibId.GetLibItemName().wx_str() );
426
427 if( part )
428 break;
429 }
430
431 return part;
432}
433
434
435void SYMBOL_LIBS::FindLibraryNearEntries( std::vector<LIB_SYMBOL*>& aCandidates,
436 const wxString& aEntryName,
437 const wxString& aLibraryName )
438{
439 for( SYMBOL_LIB& lib : *this )
440 {
441 if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
442 continue;
443
444 wxArrayString partNames;
445
446 lib.GetSymbolNames( partNames );
447
448 if( partNames.IsEmpty() )
449 continue;
450
451 for( size_t i = 0; i < partNames.size(); i++ )
452 {
453 if( partNames[i].CmpNoCase( aEntryName ) == 0 )
454 aCandidates.push_back( lib.FindSymbol( partNames[i] ) );
455 }
456 }
457}
458
459
460void SYMBOL_LIBS::GetLibNamesAndPaths( PROJECT* aProject, wxString* aPaths, wxArrayString* aNames )
461{
462 wxCHECK_RET( aProject, "Null PROJECT in GetLibNamesAndPaths" );
463
464 PROJECT_FILE& project = aProject->GetProjectFile();
465
466 if( aPaths )
467 *aPaths = project.m_LegacyLibDir;
468
469 if( aNames )
470 *aNames = project.m_LegacyLibNames;
471}
472
473
474void SYMBOL_LIBS::SetLibNamesAndPaths( PROJECT* aProject, const wxString& aPaths,
475 const wxArrayString& aNames )
476{
477 wxCHECK_RET( aProject, "Null PROJECT in SetLibNamesAndPaths" );
478
479 PROJECT_FILE& project = aProject->GetProjectFile();
480
481 project.m_LegacyLibDir = aPaths;
482 project.m_LegacyLibNames = aNames;
483}
484
485
486const wxString SYMBOL_LIBS::CacheName( const wxString& aFullProjectFilename )
487{
488 wxFileName name = aFullProjectFilename;
489
490 name.SetName( name.GetName() + "-cache" );
492
493 if( name.FileExists() )
494 return name.GetFullPath();
495
496 return wxEmptyString;
497}
498
499
500void SYMBOL_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress )
501{
502 wxString filename;
503 wxString libs_not_found;
504 SEARCH_STACK* lib_search = PROJECT_SCH::SchSearchS( aProject );
505
506#if defined(DEBUG) && 0
507 lib_search->Show( __func__ );
508#endif
509
510 wxArrayString lib_names;
511
512 GetLibNamesAndPaths( aProject, nullptr, &lib_names );
513
514 // Post symbol library table, this should be empty. Only the cache library should get loaded.
515 if( !lib_names.empty() )
516 {
517 APP_PROGRESS_DIALOG lib_dialog( _( "Loading Symbol Libraries" ),
518 wxEmptyString,
519 lib_names.GetCount(),
520 nullptr,
521 false,
522 wxPD_APP_MODAL );
523
524 if( aShowProgress )
525 {
526 lib_dialog.Show();
527 }
528
529 for( unsigned i = 0; i < lib_names.GetCount(); ++i )
530 {
531 if( aShowProgress )
532 {
533 lib_dialog.Update( i, wxString::Format( _( "Loading %s..." ), lib_names[i] ) );
534 }
535
536 // lib_names[] does not store the file extension. Set it.
537 // Remember lib_names[i] can contain a '.' in name, so using a wxFileName
538 // before adding the extension can create incorrect full filename
539 wxString fullname = lib_names[i] + "." + FILEEXT::LegacySymbolLibFileExtension;
540 // Now the full name is set, we can use a wxFileName.
541 wxFileName fn( fullname );
542
543 // Skip if the file name is not valid..
544 if( !fn.IsOk() )
545 continue;
546
547 if( !fn.FileExists() )
548 {
549 filename = lib_search->FindValidPath( fn.GetFullPath() );
550
551 if( !filename )
552 {
553 libs_not_found += fn.GetFullPath();
554 libs_not_found += '\n';
555 continue;
556 }
557 }
558 else
559 { // ensure the lib filename has a absolute path.
560 // If the lib has no absolute path, and is found in the cwd by fn.FileExists(),
561 // make a full absolute path, to avoid issues with load library functions which
562 // expects an absolute path.
563 if( !fn.IsAbsolute() )
564 fn.MakeAbsolute();
565
566 filename = fn.GetFullPath();
567 }
568
569 try
570 {
571 AddLibrary( filename );
572 }
573 catch( const IO_ERROR& ioe )
574 {
575 wxString msg;
576 msg.Printf( _( "Symbol library '%s' failed to load." ), filename );
577
578 wxLogError( msg + wxS( "\n" ) + ioe.What() );
579 }
580 }
581 }
582
583 // add the special cache library.
584 wxString cache_name = CacheName( aProject->GetProjectFullName() );
585 SYMBOL_LIB* cache_lib;
586
587 if( !aProject->IsNullProject() && !cache_name.IsEmpty() )
588 {
589 try
590 {
591 cache_lib = AddLibrary( cache_name );
592
593 if( cache_lib )
594 cache_lib->SetCache();
595 }
596 catch( const IO_ERROR& ioe )
597 {
598 wxString msg = wxString::Format( _( "Error loading symbol library '%s'." )
599 + wxS( "\n%s" ),
600 cache_name,
601 ioe.What() );
602
603 THROW_IO_ERROR( msg );
604 }
605 }
606
607 // Print the libraries not found
608 if( !libs_not_found.IsEmpty() )
609 {
610 // Use a different exception type so catch()er can route to proper use
611 // of the HTML_MESSAGE_BOX.
612 THROW_PARSE_ERROR( wxEmptyString, __func__, TO_UTF8( libs_not_found ), 0, 0 );
613 }
614}
const char * name
Definition: DXF_plotter.cpp:57
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:99
wxString GetName() const override
Definition: lib_symbol.h:160
void SetLib(SYMBOL_LIB *aLibrary)
Definition: lib_symbol.h:220
LIB_SYMBOL_SPTR SharedPtr() const
Definition: lib_symbol.h:110
SYMBOL_LIB * GetLib() const
Definition: lib_symbol.h:219
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:70
static SEARCH_STACK * SchSearchS(PROJECT *aProject)
Accessor for Eeschema search stack.
Definition: project_sch.cpp:41
Container for project specific data.
Definition: project.h:62
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:129
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:166
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:153
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
A name/value tuple with unique names and optional values.
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
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.
std::unique_ptr< STRING_UTF8_MAP > m_properties
Library properties.
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:391
Definition for symbol library class.
Definition of file extensions used in Kicad.