KiCad PCB EDA Suite
class_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 <stambaughw@gmail.com>
6  * Copyright (C) 2004-2020 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 
30 #include <algorithm>
31 #include <fctsys.h>
32 #include <kiface_i.h>
33 #include <gr_basic.h>
34 #include <macros.h>
35 #include <eda_base_frame.h>
36 #include <kicad_string.h>
37 #include <gestfich.h>
38 #include <eda_doc.h>
39 #include <richio.h>
40 #include <config_params.h>
42 #include <project/project_file.h>
43 #include <project_rescue.h>
44 #include <properties.h>
45 
46 #include <general.h>
47 #include <class_library.h>
48 #include <sch_legacy_plugin.h>
49 
50 #include <wx/progdlg.h>
51 #include <wx/tokenzr.h>
52 #include <wx/regex.h>
53 
54 #define DUPLICATE_NAME_MSG \
55  _( "Library \"%s\" has duplicate entry name \"%s\".\n" \
56  "This may cause some unexpected behavior when loading components into a schematic." )
57 
58 
59 PART_LIB::PART_LIB( int aType, const wxString& aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType ) :
60  // start @ != 0 so each additional library added
61  // is immediately detectable, zero would not be.
62  m_mod_hash( PART_LIBS::s_modify_generation ),
63  m_pluginType( aPluginType )
64 {
65  type = aType;
66  isModified = false;
67  timeStamp = 0;
68  timeStamp = wxDateTime::Now();
69  versionMajor = 0; // Will be updated after reading the lib file
70  versionMinor = 0; // Will be updated after reading the lib file
71 
72  fileName = aFileName;
73 
74  if( !fileName.IsOk() )
75  fileName = "unnamed.lib";
76 
77  m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
78  m_properties = std::make_unique<PROPERTIES>();
79 }
80 
81 
83 {
84 }
85 
86 
87 void PART_LIB::Save( bool aSaveDocFile )
88 {
89  wxCHECK_RET( m_plugin != NULL, wxString::Format( "no plugin defined for library `%s`.",
90  fileName.GetFullPath() ) );
91 
92  PROPERTIES props;
93 
94  if( !aSaveDocFile )
96 
97  m_plugin->SaveLibrary( fileName.GetFullPath(), &props );
98  isModified = false;
99 }
100 
101 
102 void PART_LIB::Create( const wxString& aFileName )
103 {
104  wxString tmpFileName = fileName.GetFullPath();
105 
106  if( !aFileName.IsEmpty() )
107  tmpFileName = aFileName;
108 
109  m_plugin->CreateSymbolLib( tmpFileName, m_properties.get() );
110 }
111 
112 
113 void PART_LIB::SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType )
114 {
115  if( m_pluginType != aPluginType )
116  {
117  m_pluginType = aPluginType;
118  m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
119  }
120 }
121 
122 
123 bool PART_LIB::IsCache() const
124 {
126 }
127 
128 
130 {
131  (*m_properties)[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
132 }
133 
134 
136 {
138 }
139 
140 
141 void PART_LIB::EnableBuffering( bool aEnable )
142 {
143  if( aEnable )
144  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
145  else
147 }
148 
149 
150 void PART_LIB::GetPartNames( wxArrayString& aNames ) const
151 {
152  m_plugin->EnumerateSymbolLib( aNames, fileName.GetFullPath(), m_properties.get() );
153 
154  aNames.Sort();
155 }
156 
157 
158 void PART_LIB::GetParts( std::vector<LIB_PART*>& aSymbols ) const
159 {
160  m_plugin->EnumerateSymbolLib( aSymbols, fileName.GetFullPath(), m_properties.get() );
161 
162  std::sort( aSymbols.begin(), aSymbols.end(),
163  [](LIB_PART *lhs, LIB_PART *rhs) -> bool
164  { return lhs->GetName() < rhs->GetName(); });
165 }
166 
167 
168 LIB_PART* PART_LIB::FindPart( const wxString& aName ) const
169 {
170  LIB_PART* symbol = m_plugin->LoadSymbol( fileName.GetFullPath(), aName, m_properties.get() );
171 
172  // Set the library to this even though technically the legacy cache plugin owns the
173  // symbols. This allows the symbol library table conversion tool to determine the
174  // correct library where the symbol was found.
175  if( symbol && !symbol->GetLib() )
176  symbol->SetLib( const_cast<PART_LIB*>( this ) );
177 
178  return symbol;
179 }
180 
181 
182 LIB_PART* PART_LIB::FindPart( const LIB_ID& aLibId ) const
183 {
184  return FindPart( aLibId.Format().wx_str() );
185 }
186 
187 
189 {
190  // add a clone, not the caller's copy, the plugin take ownership of the new symbol.
191  m_plugin->SaveSymbol( fileName.GetFullPath(), new LIB_PART( *aPart->SharedPtr().get(), this ),
192  m_properties.get() );
193 
194  // If we are not buffering, the library file is updated immediately when the plugin
195  // SaveSymbol() function is called.
196  if( IsBuffering() )
197  isModified = true;
198 
199  ++m_mod_hash;
200 }
201 
202 
204 {
205  wxCHECK_MSG( aEntry != NULL, NULL, "NULL pointer cannot be removed from library." );
206 
207  m_plugin->DeleteSymbol( fileName.GetFullPath(), aEntry->GetName(), m_properties.get() );
208 
209  // If we are not buffering, the library file is updated immediately when the plugin
210  // SaveSymbol() function is called.
211  if( IsBuffering() )
212  isModified = true;
213 
214  ++m_mod_hash;
215  return NULL;
216 }
217 
218 
220 {
221  wxASSERT( aOldPart != NULL );
222  wxASSERT( aNewPart != NULL );
223 
224  m_plugin->DeleteSymbol( fileName.GetFullPath(), aOldPart->GetName(), m_properties.get() );
225 
226  LIB_PART* my_part = new LIB_PART( *aNewPart, this );
227 
228  m_plugin->SaveSymbol( fileName.GetFullPath(), my_part, m_properties.get() );
229 
230  // If we are not buffering, the library file is updated immediately when the plugin
231  // SaveSymbol() function is called.
232  if( IsBuffering() )
233  isModified = true;
234 
235  ++m_mod_hash;
236  return my_part;
237 }
238 
239 
240 PART_LIB* PART_LIB::LoadLibrary( const wxString& aFileName )
241 {
242  std::unique_ptr<PART_LIB> lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, aFileName ) );
243 
244  std::vector<LIB_PART*> parts;
245  // This loads the library.
246  lib->GetParts( parts );
247 
248  // Now, set the LIB_PART m_library member but it will only be used
249  // when loading legacy libraries in the future. Once the symbols in the
250  // schematic have a full #LIB_ID, this will not get called.
251  for( size_t ii = 0; ii < parts.size(); ii++ )
252  {
253  LIB_PART* part = parts[ii];
254 
255  part->SetLib( lib.get() );
256  }
257 
258  PART_LIB* ret = lib.release();
259  return ret;
260 }
261 
262 
263 PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName )
264 {
265  PART_LIB* lib;
266 
267  wxFileName fn = aFileName;
268  // Don't reload the library if it is already loaded.
269  lib = FindLibrary( fn.GetName() );
270 
271  if( lib )
272  return lib;
273 
274  try
275  {
276  lib = PART_LIB::LoadLibrary( aFileName );
277  push_back( lib );
278 
279  return lib;
280  }
281  catch( ... )
282  {
283  return nullptr;
284  }
285 }
286 
287 
288 PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName, PART_LIBS::iterator& aIterator )
289 {
290  // Don't reload the library if it is already loaded.
291  wxFileName fn( aFileName );
292  PART_LIB* lib = FindLibrary( fn.GetName() );
293 
294  if( lib )
295  return lib;
296 
297  try
298  {
299  lib = PART_LIB::LoadLibrary( aFileName );
300 
301  if( aIterator >= begin() && aIterator < end() )
302  insert( aIterator, lib );
303  else
304  push_back( lib );
305 
306  return lib;
307  }
308  catch( ... )
309  {
310  return nullptr;
311  }
312 }
313 
314 
315 PART_LIB* PART_LIBS::FindLibrary( const wxString& aName )
316 {
317  for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
318  {
319  if( it->GetName() == aName )
320  return &*it;
321  }
322 
323  return NULL;
324 }
325 
326 
328 {
329  for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
330  {
331  if( it->IsCache() )
332  return &*it;
333  }
334 
335  return NULL;
336 }
337 
338 
339 PART_LIB* PART_LIBS::FindLibraryByFullFileName( const wxString& aFullFileName )
340 {
341  for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
342  {
343  if( it->GetFullFileName() == aFullFileName )
344  return &*it;
345  }
346 
347  return NULL;
348 }
349 
350 
351 wxArrayString PART_LIBS::GetLibraryNames( bool aSorted )
352 {
353  wxArrayString cacheNames;
354  wxArrayString names;
355 
356  for( PART_LIB& lib : *this )
357  {
358  if( lib.IsCache() && aSorted )
359  cacheNames.Add( lib.GetName() );
360  else
361  names.Add( lib.GetName() );
362  }
363 
364  // Even sorted, the cache library is always at the end of the list.
365  if( aSorted )
366  names.Sort();
367 
368  for( unsigned int i = 0; i<cacheNames.Count(); i++ )
369  names.Add( cacheNames.Item( i ) );
370 
371  return names;
372 }
373 
374 
375 LIB_PART* PART_LIBS::FindLibPart( const LIB_ID& aLibId, const wxString& aLibraryName )
376 {
377  LIB_PART* part = NULL;
378 
379  for( PART_LIB& lib : *this )
380  {
381  if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
382  continue;
383 
384  part = lib.FindPart( aLibId.GetLibItemName().wx_str() );
385 
386  if( part )
387  break;
388  }
389 
390  return part;
391 }
392 
393 
394 void PART_LIBS::FindLibraryNearEntries( std::vector<LIB_PART*>& aCandidates,
395  const wxString& aEntryName,
396  const wxString& aLibraryName )
397 {
398  for( PART_LIB& lib : *this )
399  {
400  if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
401  continue;
402 
403  wxArrayString partNames;
404 
405  lib.GetPartNames( partNames );
406 
407  if( partNames.IsEmpty() )
408  continue;
409 
410  for( size_t i = 0; i < partNames.size(); i++ )
411  {
412  if( partNames[i].CmpNoCase( aEntryName ) == 0 )
413  aCandidates.push_back( lib.FindPart( partNames[i] ) );
414  }
415  }
416 }
417 
418 
419 int PART_LIBS::s_modify_generation = 1; // starts at 1 and goes up
420 
421 
423 {
424  int hash = 0;
425 
426  for( PART_LIBS::const_iterator it = begin(); it != end(); ++it )
427  {
428  hash += it->GetModHash();
429  }
430 
431  // Rebuilding the cache (m_cache) does not change the GetModHash() value,
432  // but changes PART_LIBS::s_modify_generation.
433  // Take this change in account:
435 
436  return hash;
437 }
438 
439 
440 void PART_LIBS::LibNamesAndPaths( PROJECT* aProject, bool doSave,
441  wxString* aPaths, wxArrayString* aNames )
442 {
443  wxCHECK_RET( aProject, "Null PROJECT in LibNamesAndPaths" );
444 
445  PROJECT_FILE& project = aProject->GetProjectFile();
446 
447  if( doSave )
448  {
449  if( aPaths )
450  project.m_LegacyLibDir = *aPaths;
451 
452  if( aNames )
453  project.m_LegacyLibNames = *aNames;
454  }
455  else
456  {
457  if( aPaths )
458  *aPaths = project.m_LegacyLibDir;
459 
460  if( aNames )
461  *aNames = project.m_LegacyLibNames;
462  }
463 }
464 
465 
466 const wxString PART_LIBS::CacheName( const wxString& aFullProjectFilename )
467 {
468  wxFileName name = aFullProjectFilename;
469 
470  name.SetName( name.GetName() + "-cache" );
472 
473  if( name.FileExists() )
474  return name.GetFullPath();
475 
476  return wxEmptyString;
477 }
478 
479 
480 void PART_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress )
481 {
482  wxString filename;
483  wxString libs_not_found;
484  SEARCH_STACK* lib_search = aProject->SchSearchS();
485 
486 #if defined(DEBUG) && 0
487  lib_search->Show( __func__ );
488 #endif
489 
490  wxArrayString lib_names;
491 
492  LibNamesAndPaths( aProject, false, NULL, &lib_names );
493 
494  // Post symbol library table, this should be empty. Only the cache library should get loaded.
495  if( !lib_names.empty() )
496  {
497  wxProgressDialog lib_dialog( _( "Loading Symbol Libraries" ),
498  wxEmptyString,
499  lib_names.GetCount(),
500  NULL,
501  wxPD_APP_MODAL );
502 
503  if( aShowProgress )
504  {
505  lib_dialog.Show();
506  }
507 
508  wxString progress_message;
509 
510  for( unsigned i = 0; i < lib_names.GetCount(); ++i )
511  {
512  if( aShowProgress )
513  {
514  lib_dialog.Update( i, _( "Loading " + lib_names[i] ) );
515  }
516 
517  // lib_names[] does not store the file extension. Set it.
518  // Remember lib_names[i] can contain a '.' in name, so using a wxFileName
519  // before adding the extension can create incorrect full filename
520  wxString fullname = lib_names[i] + "." + LegacySymbolLibFileExtension;
521  // Now the full name is set, we can use a wxFileName.
522  wxFileName fn( fullname );
523 
524  // Skip if the file name is not valid..
525  if( !fn.IsOk() )
526  continue;
527 
528  if( !fn.FileExists() )
529  {
530  filename = lib_search->FindValidPath( fn.GetFullPath() );
531 
532  if( !filename )
533  {
534  libs_not_found += fn.GetFullPath();
535  libs_not_found += '\n';
536  continue;
537  }
538  }
539  else
540  { // ensure the lib filename has a absolute path.
541  // If the lib has no absolute path, and is found in the cwd by fn.FileExists(),
542  // make a full absolute path, to avoid issues with load library functions which
543  // expects an absolute path.
544  if( !fn.IsAbsolute() )
545  fn.MakeAbsolute();
546 
547  filename = fn.GetFullPath();
548  }
549 
550  try
551  {
552  AddLibrary( filename );
553  }
554  catch( const IO_ERROR& ioe )
555  {
556  wxString msg;
557  msg.Printf( _( "Symbol library \"%s\" failed to load. Error:\n %s" ),
558  GetChars( filename ), GetChars( ioe.What() ) );
559 
560  wxLogError( msg );
561  }
562  }
563  }
564 
565  // add the special cache library.
566  wxString cache_name = CacheName( aProject->GetProjectFullName() );
567  PART_LIB* cache_lib;
568 
569  if( !cache_name.IsEmpty() )
570  {
571  try
572  {
573  cache_lib = AddLibrary( cache_name );
574 
575  if( cache_lib )
576  cache_lib->SetCache();
577  }
578  catch( const IO_ERROR& ioe )
579  {
580  wxString msg = wxString::Format( _(
581  "Symbol library \"%s\" failed to load.\nError: %s" ),
582  GetChars( cache_name ),
583  GetChars( ioe.What() )
584  );
585 
586  THROW_IO_ERROR( msg );
587  }
588  }
589 
590  // Print the libraries not found
591  if( !libs_not_found.IsEmpty() )
592  {
593  // Use a different exception type so catch()er can route to proper use
594  // of the HTML_MESSAGE_BOX.
595  THROW_PARSE_ERROR( wxEmptyString, __func__, TO_UTF8( libs_not_found ), 0, 0 );
596  }
597 
598 #if defined(DEBUG) && 1
599  printf( "%s: lib_names:\n", __func__ );
600 
601  for( PART_LIBS::const_iterator it = begin(); it < end(); ++it )
602  printf( " %s\n", TO_UTF8( it->GetName() ) );
603 #endif
604 }
PART_LIB * GetLib()
const wxString GetName() const
Return the file name without path or extension.
int m_mod_hash
incremented each time library is changed.
void SetLib(PART_LIB *aLibrary)
wxString FindValidPath(const wxString &aFileName) const
Definition: search_stack.h:73
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
LIB_PART * ReplacePart(LIB_PART *aOldPart, LIB_PART *aNewPart)
Replace an existing part entry in the library.
std::unique_ptr< SCH_PLUGIN > m_plugin
static void LibNamesAndPaths(PROJECT *aProject, bool doSave, wxString *aPaths, wxArrayString *aNames=NULL)
Save or load the names of the currently configured part libraries (without paths).
PROJECT holds project specific data.
Definition: project.h:61
This file is part of the common library TODO brief description.
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it.
wxString GetName() const override
static int s_modify_generation
helper for GetModifyHash()
void Save(bool aSaveDocFile=true)
bool isModified
Library modification status.
const std::string LegacySymbolLibFileExtension
wxArrayString m_LegacyLibNames
Definition: project_file.h:154
This file is part of the common library.
PART_LIB * GetCacheLibrary()
wxArrayString GetLibraryNames(bool aSorted=true)
Return the list of part library file names without path and extension.
int GetModifyHash()
Return the modification hash for all libraries.
void FindLibraryNearEntries(std::vector< LIB_PART * > &aCandidates, const wxString &aEntryName, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a LIB_PART using a case insensitive comparison.
int type
Library type indicator.
LIB_PART * RemovePart(LIB_PART *aEntry)
Safely remove aEntry from the library and return the next entry.
SEARCH_STACK looks for files in a number of places.
Definition: search_stack.h:41
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
PART_LIB * FindLibrary(const wxString &aName)
Find a part library by aName.
static const wxString CacheName(const wxString &aFullProjectFilename)
Return the name of the cache library after potentially fixing it from an older naming scheme.
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
PROJECT_FILE is the backing store for a PROJECT, in JSON format.
Definition: project_file.h:62
void GetPartNames(wxArrayString &aNames) const
Load a string array with the names of all the entries in this library.
This file contains miscellaneous commonly used macros and functions.
bool IsBuffering() const
void EnableBuffering(bool aEnable=true)
#define NULL
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
VTBL_ENTRY PROJECT_FILE & GetProjectFile() const
Definition: project.h:137
wxDateTime timeStamp
Library save time and date.
PART_LIB * AddLibrary(const wxString &aFileName)
Allocate and adds a part library to the library list.
PART_SPTR SharedPtr()
static PART_LIB * LoadLibrary(const wxString &aFileName)
Allocate and load a symbol library file.
Define a library symbol object.
Definition of file extensions used in Kicad.
Base window classes and related definitions.
void SetCache()
std::unique_ptr< PROPERTIES > m_properties
Library properties.
LIB_PART * FindLibPart(const LIB_ID &aLibId, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a part.
#define THROW_IO_ERROR(msg)
static const char * PropNoDocFile
The property used internally by the plugin to disable writing the library documentation (....
VTBL_ENTRY const wxString GetProjectFullName() const
Function GetProjectFullName returns the full path and name of the project.
Definition: project.cpp:117
SCH_IO_MGR::SCH_FILE_T m_pluginType
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
LIB_PART * FindPart(const wxString &aName) const
Find LIB_PART by aName.
UTF8 Format() const
Definition: lib_id.cpp:237
wxFileName fileName
Library file name.
void GetParts(std::vector< LIB_PART * > &aPart) const
Load a vector with all the entries in this library.
A collection of PART_LIB objects.
void AddPart(LIB_PART *aPart)
Add aPart entry to library.
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:153
const char * name
Definition: DXF_plotter.cpp:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
#define _(s)
Definition: 3d_actions.cpp:33
int versionMinor
Library minor version number.
wxString wx_str() const
Definition: utf8.cpp:51
#define TO_UTF8(wxstring)
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
PART_LIB * FindLibraryByFullFileName(const wxString &aFullFileName)
void SetPluginType(SCH_IO_MGR::SCH_FILE_T aPluginType)
wxString m_LegacyLibDir
Definition: project_file.h:152
Definition for part library class.
PART_LIB(int aType, const wxString &aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType=SCH_IO_MGR::SCH_LEGACY)
void Create(const wxString &aFileName=wxEmptyString)
Object used to load, save, search, and otherwise manipulate symbol library files.
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
bool IsCache() const
int versionMajor
Library major version number.