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>
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 name = aFullProjectFilename;
488
489 name.SetName( name.GetName() + "-cache" );
491
492 if( name.FileExists() )
493 return name.GetFullPath();
494
495 return wxEmptyString;
496}
497
498
499void SYMBOL_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress )
500{
501 wxString filename;
502 wxString libs_not_found;
503 SEARCH_STACK* lib_search = PROJECT_SCH::SchSearchS( aProject );
504
505#if defined(DEBUG) && 0
506 lib_search->Show( __func__ );
507#endif
508
509 wxArrayString lib_names;
510
511 GetLibNamesAndPaths( aProject, nullptr, &lib_names );
512
513 // Post symbol library table, this should be empty. Only the cache library should get loaded.
514 if( !lib_names.empty() )
515 {
516 APP_PROGRESS_DIALOG lib_dialog( _( "Loading Symbol Libraries" ),
517 wxEmptyString,
518 lib_names.GetCount(),
519 nullptr,
520 false,
521 wxPD_APP_MODAL );
522
523 if( aShowProgress )
524 {
525 lib_dialog.Show();
526 }
527
528 for( unsigned i = 0; i < lib_names.GetCount(); ++i )
529 {
530 if( aShowProgress )
531 {
532 lib_dialog.Update( i, wxString::Format( _( "Loading %s..." ), lib_names[i] ) );
533 }
534
535 // lib_names[] does not store the file extension. Set it.
536 // Remember lib_names[i] can contain a '.' in name, so using a wxFileName
537 // before adding the extension can create incorrect full filename
538 wxString fullname = lib_names[i] + "." + FILEEXT::LegacySymbolLibFileExtension;
539 // Now the full name is set, we can use a wxFileName.
540 wxFileName fn( fullname );
541
542 // Skip if the file name is not valid..
543 if( !fn.IsOk() )
544 continue;
545
546 if( !fn.FileExists() )
547 {
548 filename = lib_search->FindValidPath( fn.GetFullPath() );
549
550 if( !filename )
551 {
552 libs_not_found += fn.GetFullPath();
553 libs_not_found += '\n';
554 continue;
555 }
556 }
557 else
558 { // ensure the lib filename has a absolute path.
559 // If the lib has no absolute path, and is found in the cwd by fn.FileExists(),
560 // make a full absolute path, to avoid issues with load library functions which
561 // expects an absolute path.
562 if( !fn.IsAbsolute() )
563 fn.MakeAbsolute();
564
565 filename = fn.GetFullPath();
566 }
567
568 try
569 {
570 AddLibrary( filename );
571 }
572 catch( const IO_ERROR& ioe )
573 {
574 wxString msg;
575 msg.Printf( _( "Symbol library '%s' failed to load." ), filename );
576
577 wxLogError( msg + wxS( "\n" ) + ioe.What() );
578 }
579 }
580 }
581
582 // add the special cache library.
583 wxString cache_name = CacheName( aProject->GetProjectFullName() );
584 SYMBOL_LIB* cache_lib;
585
586 if( !aProject->IsNullProject() && !cache_name.IsEmpty() )
587 {
588 try
589 {
590 cache_lib = AddLibrary( cache_name );
591
592 if( cache_lib )
593 cache_lib->SetCache();
594 }
595 catch( const IO_ERROR& ioe )
596 {
597 wxString msg = wxString::Format( _( "Error loading symbol library '%s'." )
598 + wxS( "\n%s" ),
599 cache_name,
600 ioe.What() );
601
602 THROW_IO_ERROR( msg );
603 }
604 }
605
606 // Print the libraries not found
607 if( !libs_not_found.IsEmpty() )
608 {
609 // Use a different exception type so catch()er can route to proper use
610 // of the HTML_MESSAGE_BOX.
611 THROW_PARSE_ERROR( wxEmptyString, __func__, TO_UTF8( libs_not_found ), 0, 0 );
612 }
613}
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:78
wxString GetName() const override
Definition: lib_symbol.h:137
void SetLib(SYMBOL_LIB *aLibrary)
Definition: lib_symbol.h:200
LIB_SYMBOL_SPTR SharedPtr() const
Definition: lib_symbol.h:89
SYMBOL_LIB * GetLib() const
Definition: lib_symbol.h:199
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:129
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: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
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:391
Definition for symbol library class.
Definition of file extensions used in Kicad.