KiCad PCB EDA Suite
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) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <algorithm>
27#include <kiface_base.h>
28#include <eda_base_frame.h>
29#include <string_utils.h>
30#include <macros.h>
31#include <richio.h>
32#include <config_params.h>
35#include <project_rescue.h>
36#include <string_utf8_map.h>
38
39#include <general.h>
40#include <symbol_library.h>
42
43#include <wx/log.h>
44#include <wx/progdlg.h>
45#include <wx/tokenzr.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<STRING_UTF8_MAP>();
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 STRING_UTF8_MAP 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->CreateSymbolLib( 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_LEGACY_PLUGIN::PropNoDocFile ] = "";
120}
121
122
124{
126}
127
128
129void SYMBOL_LIB::EnableBuffering( bool aEnable )
130{
131 if( aEnable )
132 (*m_properties)[ SCH_LEGACY_PLUGIN::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 // Set the library to this even though technically the legacy cache plugin owns the
163 // symbols. This allows the symbol library table conversion tool to determine the
164 // correct library where the symbol was found.
165 if( symbol && !symbol->GetLib() )
166 symbol->SetLib( const_cast<SYMBOL_LIB*>( this ) );
167
168 return symbol;
169}
170
171
173{
174 return FindSymbol( aLibId.Format().wx_str() );
175}
176
177
179{
180 // add a clone, not the caller's copy, the plugin take ownership of the new symbol.
181 m_plugin->SaveSymbol( fileName.GetFullPath(),
182 new LIB_SYMBOL( *aSymbol->SharedPtr().get(), this ),
183 m_properties.get() );
184
185 // If we are not buffering, the library file is updated immediately when the plugin
186 // SaveSymbol() function is called.
187 if( IsBuffering() )
188 isModified = true;
189
190 ++m_mod_hash;
191}
192
193
195{
196 wxCHECK_MSG( aEntry != nullptr, nullptr, "NULL pointer cannot be removed from library." );
197
198 m_plugin->DeleteSymbol( fileName.GetFullPath(), aEntry->GetName(), m_properties.get() );
199
200 // If we are not buffering, the library file is updated immediately when the plugin
201 // SaveSymbol() function is called.
202 if( IsBuffering() )
203 isModified = true;
204
205 ++m_mod_hash;
206 return nullptr;
207}
208
209
211{
212 wxASSERT( aOldSymbol != nullptr );
213 wxASSERT( aNewSymbol != nullptr );
214
215 m_plugin->DeleteSymbol( fileName.GetFullPath(), aOldSymbol->GetName(), m_properties.get() );
216
217 LIB_SYMBOL* my_part = new LIB_SYMBOL( *aNewSymbol, this );
218
219 m_plugin->SaveSymbol( fileName.GetFullPath(), my_part, m_properties.get() );
220
221 // If we are not buffering, the library file is updated immediately when the plugin
222 // SaveSymbol() function is called.
223 if( IsBuffering() )
224 isModified = true;
225
226 ++m_mod_hash;
227 return my_part;
228}
229
230
231SYMBOL_LIB* SYMBOL_LIB::LoadLibrary( const wxString& aFileName )
232{
233 std::unique_ptr<SYMBOL_LIB> lib = std::make_unique<SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
234 aFileName );
235
236 std::vector<LIB_SYMBOL*> parts;
237 // This loads the library.
238 lib->GetSymbols( parts );
239
240 // Now, set the LIB_SYMBOL m_library member but it will only be used
241 // when loading legacy libraries in the future. Once the symbols in the
242 // schematic have a full #LIB_ID, this will not get called.
243 for( size_t ii = 0; ii < parts.size(); ii++ )
244 {
245 LIB_SYMBOL* part = parts[ii];
246
247 part->SetLib( lib.get() );
248 }
249
250 SYMBOL_LIB* ret = lib.release();
251 return ret;
252}
253
254
255SYMBOL_LIB* SYMBOL_LIBS::AddLibrary( const wxString& aFileName )
256{
257 SYMBOL_LIB* lib;
258
259 wxFileName fn = aFileName;
260 // Don't reload the library if it is already loaded.
261 lib = FindLibrary( fn.GetName() );
262
263 if( lib )
264 return lib;
265
266 try
267 {
268 lib = SYMBOL_LIB::LoadLibrary( aFileName );
269 push_back( lib );
270
271 return lib;
272 }
273 catch( ... )
274 {
275 return nullptr;
276 }
277}
278
279
280SYMBOL_LIB* SYMBOL_LIBS::AddLibrary( const wxString& aFileName, SYMBOL_LIBS::iterator& aIterator )
281{
282 // Don't reload the library if it is already loaded.
283 wxFileName fn( aFileName );
284 SYMBOL_LIB* lib = FindLibrary( fn.GetName() );
285
286 if( lib )
287 return lib;
288
289 try
290 {
291 lib = SYMBOL_LIB::LoadLibrary( aFileName );
292
293 if( aIterator >= begin() && aIterator < end() )
294 insert( aIterator, lib );
295 else
296 push_back( lib );
297
298 return lib;
299 }
300 catch( ... )
301 {
302 return nullptr;
303 }
304}
305
306
307SYMBOL_LIB* SYMBOL_LIBS::FindLibrary( const wxString& aName )
308{
309 for( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
310 {
311 if( it->GetName() == aName )
312 return &*it;
313 }
314
315 return nullptr;
316}
317
318
320{
321 for( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
322 {
323 if( it->IsCache() )
324 return &*it;
325 }
326
327 return nullptr;
328}
329
330
331SYMBOL_LIB* SYMBOL_LIBS::FindLibraryByFullFileName( const wxString& aFullFileName )
332{
333 for( SYMBOL_LIBS::iterator it = begin(); it!=end(); ++it )
334 {
335 if( it->GetFullFileName() == aFullFileName )
336 return &*it;
337 }
338
339 return nullptr;
340}
341
342
343wxArrayString SYMBOL_LIBS::GetLibraryNames( bool aSorted )
344{
345 wxArrayString cacheNames;
346 wxArrayString names;
347
348 for( SYMBOL_LIB& lib : *this )
349 {
350 if( lib.IsCache() && aSorted )
351 cacheNames.Add( lib.GetName() );
352 else
353 names.Add( lib.GetName() );
354 }
355
356 // Even sorted, the cache library is always at the end of the list.
357 if( aSorted )
358 names.Sort();
359
360 for( unsigned int i = 0; i<cacheNames.Count(); i++ )
361 names.Add( cacheNames.Item( i ) );
362
363 return names;
364}
365
366
367LIB_SYMBOL* SYMBOL_LIBS::FindLibSymbol( const LIB_ID& aLibId, const wxString& aLibraryName )
368{
369 LIB_SYMBOL* part = nullptr;
370
371 for( SYMBOL_LIB& lib : *this )
372 {
373 if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
374 continue;
375
376 part = lib.FindSymbol( aLibId.GetLibItemName().wx_str() );
377
378 if( part )
379 break;
380 }
381
382 return part;
383}
384
385
386void SYMBOL_LIBS::FindLibraryNearEntries( std::vector<LIB_SYMBOL*>& aCandidates,
387 const wxString& aEntryName,
388 const wxString& aLibraryName )
389{
390 for( SYMBOL_LIB& lib : *this )
391 {
392 if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
393 continue;
394
395 wxArrayString partNames;
396
397 lib.GetSymbolNames( partNames );
398
399 if( partNames.IsEmpty() )
400 continue;
401
402 for( size_t i = 0; i < partNames.size(); i++ )
403 {
404 if( partNames[i].CmpNoCase( aEntryName ) == 0 )
405 aCandidates.push_back( lib.FindSymbol( partNames[i] ) );
406 }
407 }
408}
409
410
411void SYMBOL_LIBS::GetLibNamesAndPaths( PROJECT* aProject, wxString* aPaths, wxArrayString* aNames )
412{
413 wxCHECK_RET( aProject, "Null PROJECT in GetLibNamesAndPaths" );
414
415 PROJECT_FILE& project = aProject->GetProjectFile();
416
417 if( aPaths )
418 *aPaths = project.m_LegacyLibDir;
419
420 if( aNames )
421 *aNames = project.m_LegacyLibNames;
422}
423
424
425void SYMBOL_LIBS::SetLibNamesAndPaths( PROJECT* aProject, const wxString& aPaths,
426 const wxArrayString& aNames )
427{
428 wxCHECK_RET( aProject, "Null PROJECT in SetLibNamesAndPaths" );
429
430 PROJECT_FILE& project = aProject->GetProjectFile();
431
432 project.m_LegacyLibDir = aPaths;
433 project.m_LegacyLibNames = aNames;
434}
435
436
437const wxString SYMBOL_LIBS::CacheName( const wxString& aFullProjectFilename )
438{
439 wxFileName name = aFullProjectFilename;
440
441 name.SetName( name.GetName() + "-cache" );
443
444 if( name.FileExists() )
445 return name.GetFullPath();
446
447 return wxEmptyString;
448}
449
450
451void SYMBOL_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress )
452{
453 wxString filename;
454 wxString libs_not_found;
455 SEARCH_STACK* lib_search = aProject->SchSearchS();
456
457#if defined(DEBUG) && 0
458 lib_search->Show( __func__ );
459#endif
460
461 wxArrayString lib_names;
462
463 GetLibNamesAndPaths( aProject, nullptr, &lib_names );
464
465 // Post symbol library table, this should be empty. Only the cache library should get loaded.
466 if( !lib_names.empty() )
467 {
468 APP_PROGRESS_DIALOG lib_dialog( _( "Loading Symbol Libraries" ),
469 wxEmptyString,
470 lib_names.GetCount(),
471 nullptr,
472 false,
473 wxPD_APP_MODAL );
474
475 if( aShowProgress )
476 {
477 lib_dialog.Show();
478 }
479
480 for( unsigned i = 0; i < lib_names.GetCount(); ++i )
481 {
482 if( aShowProgress )
483 {
484 lib_dialog.Update( i, wxString::Format( _( "Loading %s..." ), lib_names[i] ) );
485 }
486
487 // lib_names[] does not store the file extension. Set it.
488 // Remember lib_names[i] can contain a '.' in name, so using a wxFileName
489 // before adding the extension can create incorrect full filename
490 wxString fullname = lib_names[i] + "." + LegacySymbolLibFileExtension;
491 // Now the full name is set, we can use a wxFileName.
492 wxFileName fn( fullname );
493
494 // Skip if the file name is not valid..
495 if( !fn.IsOk() )
496 continue;
497
498 if( !fn.FileExists() )
499 {
500 filename = lib_search->FindValidPath( fn.GetFullPath() );
501
502 if( !filename )
503 {
504 libs_not_found += fn.GetFullPath();
505 libs_not_found += '\n';
506 continue;
507 }
508 }
509 else
510 { // ensure the lib filename has a absolute path.
511 // If the lib has no absolute path, and is found in the cwd by fn.FileExists(),
512 // make a full absolute path, to avoid issues with load library functions which
513 // expects an absolute path.
514 if( !fn.IsAbsolute() )
515 fn.MakeAbsolute();
516
517 filename = fn.GetFullPath();
518 }
519
520 try
521 {
522 AddLibrary( filename );
523 }
524 catch( const IO_ERROR& ioe )
525 {
526 wxString msg;
527 msg.Printf( _( "Symbol library '%s' failed to load." ), filename );
528
529 wxLogError( msg + wxS( "\n" ) + ioe.What() );
530 }
531 }
532 }
533
534 // add the special cache library.
535 wxString cache_name = CacheName( aProject->GetProjectFullName() );
536 SYMBOL_LIB* cache_lib;
537
538 if( !aProject->IsNullProject() && !cache_name.IsEmpty() )
539 {
540 try
541 {
542 cache_lib = AddLibrary( cache_name );
543
544 if( cache_lib )
545 cache_lib->SetCache();
546 }
547 catch( const IO_ERROR& ioe )
548 {
549 wxString msg = wxString::Format( _( "Error loading symbol library '%s'." )
550 + wxS( "\n%s" ),
551 cache_name,
552 ioe.What() );
553
554 THROW_IO_ERROR( msg );
555 }
556 }
557
558 // Print the libraries not found
559 if( !libs_not_found.IsEmpty() )
560 {
561 // Use a different exception type so catch()er can route to proper use
562 // of the HTML_MESSAGE_BOX.
563 THROW_PARSE_ERROR( wxEmptyString, __func__, TO_UTF8( libs_not_found ), 0, 0 );
564 }
565}
const char * name
Definition: DXF_plotter.cpp:56
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:76
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:117
const UTF8 & GetLibItemName() const
Definition: lib_id.h:101
Define a library symbol object.
Definition: lib_symbol.h:98
wxString GetName() const override
Definition: lib_symbol.h:136
void SetLib(SYMBOL_LIB *aLibrary)
Definition: lib_symbol.h:188
LIB_SYMBOL_SPTR SharedPtr() const
Definition: lib_symbol.h:108
SYMBOL_LIB * GetLib() const
Definition: lib_symbol.h:187
The backing store for a PROJECT, in JSON format.
Definition: project_file.h:65
Container for project specific data.
Definition: project.h:63
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition: project.cpp:120
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:148
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:138
static const char * PropNoDocFile
The property used internally by the plugin to disable writing the library documentation (....
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Look for files in a number of paths.
Definition: search_stack.h:42
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.
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.
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< SCH_PLUGIN > m_plugin
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)
static SYMBOL_LIB * LoadLibrary(const wxString &aFileName)
Allocate and load a symbol library file.
LIB_SYMBOL * FindSymbol(const wxString &aName) const
Find LIB_SYMBOL by aName.
void AddSymbol(LIB_SYMBOL *aSymbol)
Add aSymbol entry to library.
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:46
#define _(s)
Base window classes and related definitions.
const std::string LegacySymbolLibFileExtension
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
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: macros.h:96
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Definition for symbol library class.
Definition of file extensions used in Kicad.