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 <kiface_i.h>
32 #include <eda_base_frame.h>
33 #include <kicad_string.h>
34 #include <gestfich.h>
35 #include <eda_doc.h>
36 #include <richio.h>
37 #include <config_params.h>
39 #include <project/project_file.h>
40 #include <project_rescue.h>
41 #include <properties.h>
43 
44 #include <general.h>
45 #include <class_library.h>
47 
48 #include <wx/progdlg.h>
49 #include <wx/tokenzr.h>
50 #include <wx/regex.h>
51 
52 #define DUPLICATE_NAME_MSG \
53  _( "Library \"%s\" has duplicate entry name \"%s\".\n" \
54  "This may cause some unexpected behavior when loading components into a schematic." )
55 
56 
57 PART_LIB::PART_LIB( SCH_LIB_TYPE aType, const wxString& aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType ) :
58  // start @ != 0 so each additional library added
59  // is immediately detectable, zero would not be.
60  m_mod_hash( PART_LIBS::s_modify_generation ),
61  m_pluginType( aPluginType )
62 {
63  type = aType;
64  isModified = false;
65  timeStamp = 0;
66  timeStamp = wxDateTime::Now();
67  versionMajor = 0; // Will be updated after reading the lib file
68  versionMinor = 0; // Will be updated after reading the lib file
69 
70  fileName = aFileName;
71 
72  if( !fileName.IsOk() )
73  fileName = "unnamed.lib";
74 
75  m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
76  m_properties = std::make_unique<PROPERTIES>();
77 }
78 
79 
81 {
82 }
83 
84 
85 void PART_LIB::Save( bool aSaveDocFile )
86 {
87  wxCHECK_RET( m_plugin != NULL, wxString::Format( "no plugin defined for library `%s`.",
88  fileName.GetFullPath() ) );
89 
90  PROPERTIES props;
91 
92  if( !aSaveDocFile )
94 
95  m_plugin->SaveLibrary( fileName.GetFullPath(), &props );
96  isModified = false;
97 }
98 
99 
100 void PART_LIB::Create( const wxString& aFileName )
101 {
102  wxString tmpFileName = fileName.GetFullPath();
103 
104  if( !aFileName.IsEmpty() )
105  tmpFileName = aFileName;
106 
107  m_plugin->CreateSymbolLib( tmpFileName, m_properties.get() );
108 }
109 
110 
111 void PART_LIB::SetPluginType( SCH_IO_MGR::SCH_FILE_T aPluginType )
112 {
113  if( m_pluginType != aPluginType )
114  {
115  m_pluginType = aPluginType;
116  m_plugin.reset( SCH_IO_MGR::FindPlugin( m_pluginType ) );
117  }
118 }
119 
120 
121 bool PART_LIB::IsCache() const
122 {
124 }
125 
126 
128 {
129  (*m_properties)[ SCH_LEGACY_PLUGIN::PropNoDocFile ] = "";
130 }
131 
132 
134 {
136 }
137 
138 
139 void PART_LIB::EnableBuffering( bool aEnable )
140 {
141  if( aEnable )
142  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
143  else
145 }
146 
147 
148 void PART_LIB::GetPartNames( wxArrayString& aNames ) const
149 {
150  m_plugin->EnumerateSymbolLib( aNames, fileName.GetFullPath(), m_properties.get() );
151 
152  aNames.Sort();
153 }
154 
155 
156 void PART_LIB::GetParts( std::vector<LIB_PART*>& aSymbols ) const
157 {
158  m_plugin->EnumerateSymbolLib( aSymbols, fileName.GetFullPath(), m_properties.get() );
159 
160  std::sort( aSymbols.begin(), aSymbols.end(),
161  [](LIB_PART *lhs, LIB_PART *rhs) -> bool
162  { return lhs->GetName() < rhs->GetName(); });
163 }
164 
165 
166 LIB_PART* PART_LIB::FindPart( const wxString& aName ) const
167 {
168  LIB_PART* symbol = m_plugin->LoadSymbol( fileName.GetFullPath(), aName, m_properties.get() );
169 
170  // Set the library to this even though technically the legacy cache plugin owns the
171  // symbols. This allows the symbol library table conversion tool to determine the
172  // correct library where the symbol was found.
173  if( symbol && !symbol->GetLib() )
174  symbol->SetLib( const_cast<PART_LIB*>( this ) );
175 
176  return symbol;
177 }
178 
179 
180 LIB_PART* PART_LIB::FindPart( const LIB_ID& aLibId ) const
181 {
182  return FindPart( aLibId.Format().wx_str() );
183 }
184 
185 
187 {
188  // add a clone, not the caller's copy, the plugin take ownership of the new symbol.
189  m_plugin->SaveSymbol( fileName.GetFullPath(), new LIB_PART( *aPart->SharedPtr().get(), this ),
190  m_properties.get() );
191 
192  // If we are not buffering, the library file is updated immediately when the plugin
193  // SaveSymbol() function is called.
194  if( IsBuffering() )
195  isModified = true;
196 
197  ++m_mod_hash;
198 }
199 
200 
202 {
203  wxCHECK_MSG( aEntry != NULL, NULL, "NULL pointer cannot be removed from library." );
204 
205  m_plugin->DeleteSymbol( fileName.GetFullPath(), aEntry->GetName(), m_properties.get() );
206 
207  // If we are not buffering, the library file is updated immediately when the plugin
208  // SaveSymbol() function is called.
209  if( IsBuffering() )
210  isModified = true;
211 
212  ++m_mod_hash;
213  return NULL;
214 }
215 
216 
218 {
219  wxASSERT( aOldPart != NULL );
220  wxASSERT( aNewPart != NULL );
221 
222  m_plugin->DeleteSymbol( fileName.GetFullPath(), aOldPart->GetName(), m_properties.get() );
223 
224  LIB_PART* my_part = new LIB_PART( *aNewPart, this );
225 
226  m_plugin->SaveSymbol( fileName.GetFullPath(), my_part, m_properties.get() );
227 
228  // If we are not buffering, the library file is updated immediately when the plugin
229  // SaveSymbol() function is called.
230  if( IsBuffering() )
231  isModified = true;
232 
233  ++m_mod_hash;
234  return my_part;
235 }
236 
237 
238 PART_LIB* PART_LIB::LoadLibrary( const wxString& aFileName )
239 {
240  std::unique_ptr<PART_LIB> lib = std::make_unique<PART_LIB>( SCH_LIB_TYPE::LT_EESCHEMA, aFileName );
241 
242  std::vector<LIB_PART*> parts;
243  // This loads the library.
244  lib->GetParts( parts );
245 
246  // Now, set the LIB_PART 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_PART* part = parts[ii];
252 
253  part->SetLib( lib.get() );
254  }
255 
256  PART_LIB* ret = lib.release();
257  return ret;
258 }
259 
260 
261 PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName )
262 {
263  PART_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 = PART_LIB::LoadLibrary( aFileName );
275  push_back( lib );
276 
277  return lib;
278  }
279  catch( ... )
280  {
281  return nullptr;
282  }
283 }
284 
285 
286 PART_LIB* PART_LIBS::AddLibrary( const wxString& aFileName, PART_LIBS::iterator& aIterator )
287 {
288  // Don't reload the library if it is already loaded.
289  wxFileName fn( aFileName );
290  PART_LIB* lib = FindLibrary( fn.GetName() );
291 
292  if( lib )
293  return lib;
294 
295  try
296  {
297  lib = PART_LIB::LoadLibrary( 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 
313 PART_LIB* PART_LIBS::FindLibrary( const wxString& aName )
314 {
315  for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
316  {
317  if( it->GetName() == aName )
318  return &*it;
319  }
320 
321  return NULL;
322 }
323 
324 
326 {
327  for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
328  {
329  if( it->IsCache() )
330  return &*it;
331  }
332 
333  return NULL;
334 }
335 
336 
337 PART_LIB* PART_LIBS::FindLibraryByFullFileName( const wxString& aFullFileName )
338 {
339  for( PART_LIBS::iterator it = begin(); it!=end(); ++it )
340  {
341  if( it->GetFullFileName() == aFullFileName )
342  return &*it;
343  }
344 
345  return NULL;
346 }
347 
348 
349 wxArrayString PART_LIBS::GetLibraryNames( bool aSorted )
350 {
351  wxArrayString cacheNames;
352  wxArrayString names;
353 
354  for( PART_LIB& lib : *this )
355  {
356  if( lib.IsCache() && aSorted )
357  cacheNames.Add( lib.GetName() );
358  else
359  names.Add( lib.GetName() );
360  }
361 
362  // Even sorted, the cache library is always at the end of the list.
363  if( aSorted )
364  names.Sort();
365 
366  for( unsigned int i = 0; i<cacheNames.Count(); i++ )
367  names.Add( cacheNames.Item( i ) );
368 
369  return names;
370 }
371 
372 
373 LIB_PART* PART_LIBS::FindLibPart( const LIB_ID& aLibId, const wxString& aLibraryName )
374 {
375  LIB_PART* part = NULL;
376 
377  for( PART_LIB& lib : *this )
378  {
379  if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
380  continue;
381 
382  part = lib.FindPart( aLibId.GetLibItemName().wx_str() );
383 
384  if( part )
385  break;
386  }
387 
388  return part;
389 }
390 
391 
392 void PART_LIBS::FindLibraryNearEntries( std::vector<LIB_PART*>& aCandidates,
393  const wxString& aEntryName,
394  const wxString& aLibraryName )
395 {
396  for( PART_LIB& lib : *this )
397  {
398  if( !aLibraryName.IsEmpty() && lib.GetName() != aLibraryName )
399  continue;
400 
401  wxArrayString partNames;
402 
403  lib.GetPartNames( partNames );
404 
405  if( partNames.IsEmpty() )
406  continue;
407 
408  for( size_t i = 0; i < partNames.size(); i++ )
409  {
410  if( partNames[i].CmpNoCase( aEntryName ) == 0 )
411  aCandidates.push_back( lib.FindPart( partNames[i] ) );
412  }
413  }
414 }
415 
416 
417 int PART_LIBS::s_modify_generation = 1; // starts at 1 and goes up
418 
419 
421 {
422  int hash = 0;
423 
424  for( PART_LIBS::const_iterator it = begin(); it != end(); ++it )
425  {
426  hash += it->GetModHash();
427  }
428 
429  // Rebuilding the cache (m_cache) does not change the GetModHash() value,
430  // but changes PART_LIBS::s_modify_generation.
431  // Take this change in account:
433 
434  return hash;
435 }
436 
437 
438 void PART_LIBS::LibNamesAndPaths( PROJECT* aProject, bool doSave,
439  wxString* aPaths, wxArrayString* aNames )
440 {
441  wxCHECK_RET( aProject, "Null PROJECT in LibNamesAndPaths" );
442 
443  PROJECT_FILE& project = aProject->GetProjectFile();
444 
445  if( doSave )
446  {
447  if( aPaths )
448  project.m_LegacyLibDir = *aPaths;
449 
450  if( aNames )
451  project.m_LegacyLibNames = *aNames;
452  }
453  else
454  {
455  if( aPaths )
456  *aPaths = project.m_LegacyLibDir;
457 
458  if( aNames )
459  *aNames = project.m_LegacyLibNames;
460  }
461 }
462 
463 
464 const wxString PART_LIBS::CacheName( const wxString& aFullProjectFilename )
465 {
466  wxFileName name = aFullProjectFilename;
467 
468  name.SetName( name.GetName() + "-cache" );
470 
471  if( name.FileExists() )
472  return name.GetFullPath();
473 
474  return wxEmptyString;
475 }
476 
477 
478 void PART_LIBS::LoadAllLibraries( PROJECT* aProject, bool aShowProgress )
479 {
480  wxString filename;
481  wxString libs_not_found;
482  SEARCH_STACK* lib_search = aProject->SchSearchS();
483 
484 #if defined(DEBUG) && 0
485  lib_search->Show( __func__ );
486 #endif
487 
488  wxArrayString lib_names;
489 
490  LibNamesAndPaths( aProject, false, NULL, &lib_names );
491 
492  // Post symbol library table, this should be empty. Only the cache library should get loaded.
493  if( !lib_names.empty() )
494  {
495  APP_PROGRESS_DIALOG lib_dialog( _( "Loading Symbol Libraries" ),
496  wxEmptyString,
497  lib_names.GetCount(),
498  NULL,
499  false,
500  wxPD_APP_MODAL );
501 
502  if( aShowProgress )
503  {
504  lib_dialog.Show();
505  }
506 
507  wxString progress_message;
508 
509  for( unsigned i = 0; i < lib_names.GetCount(); ++i )
510  {
511  if( aShowProgress )
512  {
513  lib_dialog.Update( i, _( "Loading " + lib_names[i] ) );
514  }
515 
516  // lib_names[] does not store the file extension. Set it.
517  // Remember lib_names[i] can contain a '.' in name, so using a wxFileName
518  // before adding the extension can create incorrect full filename
519  wxString fullname = lib_names[i] + "." + LegacySymbolLibFileExtension;
520  // Now the full name is set, we can use a wxFileName.
521  wxFileName fn( fullname );
522 
523  // Skip if the file name is not valid..
524  if( !fn.IsOk() )
525  continue;
526 
527  if( !fn.FileExists() )
528  {
529  filename = lib_search->FindValidPath( fn.GetFullPath() );
530 
531  if( !filename )
532  {
533  libs_not_found += fn.GetFullPath();
534  libs_not_found += '\n';
535  continue;
536  }
537  }
538  else
539  { // ensure the lib filename has a absolute path.
540  // If the lib has no absolute path, and is found in the cwd by fn.FileExists(),
541  // make a full absolute path, to avoid issues with load library functions which
542  // expects an absolute path.
543  if( !fn.IsAbsolute() )
544  fn.MakeAbsolute();
545 
546  filename = fn.GetFullPath();
547  }
548 
549  try
550  {
551  AddLibrary( filename );
552  }
553  catch( const IO_ERROR& ioe )
554  {
555  wxString msg;
556  msg.Printf( _( "Symbol library \"%s\" failed to load. Error:\n %s" ),
557  filename, ioe.What() );
558 
559  wxLogError( msg );
560  }
561  }
562  }
563 
564  // add the special cache library.
565  wxString cache_name = CacheName( aProject->GetProjectFullName() );
566  PART_LIB* cache_lib;
567 
568  if( !cache_name.IsEmpty() )
569  {
570  try
571  {
572  cache_lib = AddLibrary( cache_name );
573 
574  if( cache_lib )
575  cache_lib->SetCache();
576  }
577  catch( const IO_ERROR& ioe )
578  {
579  wxString msg =
580  wxString::Format( _( "Symbol library \"%s\" failed to load.\nError: %s" ),
581  cache_name, ioe.What() );
582 
583  THROW_IO_ERROR( msg );
584  }
585  }
586 
587  // Print the libraries not found
588  if( !libs_not_found.IsEmpty() )
589  {
590  // Use a different exception type so catch()er can route to proper use
591  // of the HTML_MESSAGE_BOX.
592  THROW_PARSE_ERROR( wxEmptyString, __func__, TO_UTF8( libs_not_found ), 0, 0 );
593  }
594 }
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.
SCH_LIB_TYPE type
Library type indicator.
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:63
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:143
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.
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.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:95
bool IsBuffering() const
void EnableBuffering(bool aEnable=true)
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:171
#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:143
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.
virtual bool Update(int aValue, const wxString &aNewMsg=wxEmptyString, bool *aSkip=NULL) override
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.
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:115
SCH_IO_MGR::SCH_FILE_T m_pluginType
LIB_PART * FindPart(const wxString &aName) const
Find LIB_PART by aName.
UTF8 Format() const
Definition: lib_id.cpp:237
SCH_LIB_TYPE
Definition: class_library.h:77
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.
PART_LIB(SCH_LIB_TYPE aType, const wxString &aFileName, SCH_IO_MGR::SCH_FILE_T aPluginType=SCH_IO_MGR::SCH_LEGACY)
const char * name
Definition: DXF_plotter.cpp:59
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:201
#define _(s)
Definition: 3d_actions.cpp:33
int versionMinor
Library minor version number.
wxString wx_str() const
Definition: utf8.cpp:51
wxProgressDialog with the option to also update the application progress on the taskbar
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:141
Definition for part library class.
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
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
bool IsCache() const
int versionMajor
Library major version number.