KiCad PCB EDA Suite
lib_manager.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) 2017 CERN
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
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 3
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  * https://www.gnu.org/licenses/gpl-3.0.html
21  * or you may search the http://www.gnu.org website for the version 3 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 <lib_manager.h>
27 #include <class_libentry.h>
28 #include <class_library.h>
29 #include <lib_edit_frame.h>
30 #include <env_paths.h>
31 #include <pgm_base.h>
32 #include <kiway.h>
33 #include <profile.h>
34 #include <symbol_lib_table.h>
35 #include <sch_legacy_plugin.h>
36 #include <list>
37 
38 
40  m_frame( aFrame ),
41  m_syncHash( 0 )
42 {
44  m_adapter->ShowUnits( false );
45 }
46 
47 
48 void LIB_MANAGER::Sync( bool aForce,
49  std::function<void( int, int, const wxString& )> aProgressCallback )
50 {
52  {
53  int libTableHash = symTable()->GetModifyHash();
54 
55  if( aForce || m_syncHash != libTableHash )
56  {
57  getAdapter()->Sync( aForce, aProgressCallback );
58  m_syncHash = libTableHash;
59  }
60  }
62 }
63 
64 
66 {
67  for( const auto& lib : m_libs )
68  {
69  if( lib.second.IsModified() )
70  return true;
71  }
72 
73  return false;
74 }
75 
76 
78 {
79  int hash = symTable()->GetModifyHash();
80 
81  for( const auto& lib : m_libs )
82  hash += lib.second.GetHash();
83 
84  return hash;
85 }
86 
87 
88 int LIB_MANAGER::GetLibraryHash( const wxString& aLibrary ) const
89 {
90  const auto libBufIt = m_libs.find( aLibrary );
91 
92  if( libBufIt != m_libs.end() )
93  return libBufIt->second.GetHash();
94 
95  auto row = GetLibrary( aLibrary );
96 
97  // return -1 if library does not exist or 0 if not modified
98  return row ? std::hash<std::string>{}( aLibrary.ToStdString() +
99  row->GetFullURI( true ).ToStdString() ) : -1;
100 }
101 
102 
103 wxArrayString LIB_MANAGER::GetLibraryNames() const
104 {
105  wxArrayString res;
106 
107  for( const auto& libName : symTable()->GetLogicalLibs() )
108  res.Add( libName );
109 
110  return res;
111 }
112 
113 
114 SYMBOL_LIB_TABLE_ROW* LIB_MANAGER::GetLibrary( const wxString& aLibrary ) const
115 {
116  SYMBOL_LIB_TABLE_ROW* row = nullptr;
117 
118  try
119  {
120  row = symTable()->FindRow( aLibrary );
121  }
122  catch( const IO_ERROR& e )
123  {
124  wxLogMessage( _( "Cannot find library \"%s\" in the Symbol Library Table (%s)" ),
125  aLibrary, e.What() );
126  }
127 
128  return row;
129 }
130 
131 
132 bool LIB_MANAGER::SaveLibrary( const wxString& aLibrary, const wxString& aFileName )
133 {
134  wxCHECK( LibraryExists( aLibrary ), false );
135  wxFileName fn( aFileName );
136  wxCHECK( !fn.FileExists() || fn.IsFileWritable(), false );
137  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
138  bool res = true; // assume all libraries are successfully saved
139 
140  auto it = m_libs.find( aLibrary );
141 
142  if( it != m_libs.end() )
143  {
144  // Handle buffered library
145  LIB_BUFFER& libBuf = it->second;
146 
147  const auto& partBuffers = libBuf.GetBuffers();
148 
149  for( const auto& partBuf : partBuffers )
150  {
151  if( !libBuf.SaveBuffer( partBuf, &*pi, true ) )
152  {
153  // Something went wrong, but try to save other libraries
154  res = false;
155  }
156  }
157 
158  // clear the deleted parts buffer only if data is saved to the original file
159  wxFileName original, destination( aFileName );
160  auto row = GetLibrary( aLibrary );
161 
162  if( row )
163  {
164  original = row->GetFullURI( true );
165  original.Normalize();
166  }
167 
168  destination.Normalize();
169 
170  if( res && original == destination )
171  libBuf.ClearDeletedBuffer();
172  }
173  else
174  {
175  // Handle original library
176  PROPERTIES properties;
177  properties.emplace( SCH_LEGACY_PLUGIN::PropBuffering, "" );
178 
179  for( auto part : getOriginalParts( aLibrary ) )
180  {
181  LIB_PART* newSymbol;
182 
183  if( part->IsAlias() )
184  {
185  std::shared_ptr< LIB_PART > oldParent = part->GetParent().lock();
186 
187  wxCHECK_MSG( oldParent, false,
188  wxString::Format( "Derived symbol '%s' found with undefined parent.",
189  part->GetName() ) );
190 
191  LIB_PART* libParent = pi->LoadSymbol( aLibrary, oldParent->GetName(), &properties );
192 
193  if( !libParent )
194  {
195  libParent = new LIB_PART( *oldParent.get() );
196  pi->SaveSymbol( aLibrary, libParent, &properties );
197  }
198 
199  newSymbol = new LIB_PART( *part );
200  newSymbol->SetParent( libParent );
201  pi->SaveSymbol( aLibrary, newSymbol, &properties );
202  }
203  else if( !pi->LoadSymbol( aLibrary, part->GetName(), &properties ) )
204  {
205  pi->SaveSymbol( aLibrary, new LIB_PART( *part ), &properties );
206  }
207  }
208  }
209 
210  pi->SaveLibrary( aFileName );
211  return res;
212 }
213 
214 
215 bool LIB_MANAGER::IsLibraryModified( const wxString& aLibrary ) const
216 {
217  auto it = m_libs.find( aLibrary );
218  return it != m_libs.end() ? it->second.IsModified() : false;
219 }
220 
221 
222 bool LIB_MANAGER::IsPartModified( const wxString& aAlias, const wxString& aLibrary ) const
223 {
224  auto libIt = m_libs.find( aLibrary );
225 
226  if( libIt == m_libs.end() )
227  return false;
228 
229  const LIB_BUFFER& buf = libIt->second;
230  auto partBuf = buf.GetBuffer( aAlias );
231  return partBuf ? partBuf->IsModified() : false;
232 }
233 
234 
235 bool LIB_MANAGER::ClearLibraryModified( const wxString& aLibrary ) const
236 {
237  auto libIt = m_libs.find( aLibrary );
238 
239  if( libIt == m_libs.end() )
240  return false;
241 
242  for( auto& partBuf : libIt->second.GetBuffers() )
243  {
244  SCH_SCREEN* screen = partBuf->GetScreen();
245 
246  if( screen )
247  screen->ClrModify();
248  }
249 
250  return true;
251 }
252 
253 
254 bool LIB_MANAGER::ClearPartModified( const wxString& aAlias, const wxString& aLibrary ) const
255 {
256  auto libI = m_libs.find( aLibrary );
257 
258  if( libI == m_libs.end() )
259  return false;
260 
261  auto partBuf = libI->second.GetBuffer( aAlias );
262  wxCHECK( partBuf, false );
263 
264  partBuf->GetScreen()->ClrModify();
265  return true;
266 }
267 
268 
269 bool LIB_MANAGER::IsLibraryReadOnly( const wxString& aLibrary ) const
270 {
271  wxCHECK( LibraryExists( aLibrary ), true );
272  wxFileName fn( symTable()->GetFullURI( aLibrary ) );
273  return ( fn.FileExists() && !fn.IsFileWritable() ) || !fn.IsDirWritable();
274 }
275 
276 
277 std::list<LIB_PART*> LIB_MANAGER::GetAliases( const wxString& aLibrary ) const
278 {
279  std::list<LIB_PART*> ret;
280  wxCHECK( LibraryExists( aLibrary ), ret );
281 
282  auto libIt = m_libs.find( aLibrary );
283 
284  if( libIt != m_libs.end() )
285  {
286  for( auto& partBuf : libIt->second.GetBuffers() )
287  {
288  ret.push_back( partBuf->GetPart() );
289  }
290  }
291  else
292  {
293  std::vector<LIB_PART*> aliases;
294 
295  try
296  {
297  symTable()->LoadSymbolLib( aliases, aLibrary );
298  }
299  catch( const IO_ERROR& e )
300  {
301  wxLogWarning( e.Problem() );
302  }
303 
304  std::copy( aliases.begin(), aliases.end(), std::back_inserter( ret ) );
305  }
306 
307  return ret;
308 }
309 
310 
311 LIB_PART* LIB_MANAGER::GetBufferedPart( const wxString& aAlias, const wxString& aLibrary )
312 {
313  wxCHECK( LibraryExists( aLibrary ), nullptr );
314 
315  // try the library buffers first
316  LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
317  LIB_PART* bufferedPart = libBuf.GetPart( aAlias );
318 
319  if( !bufferedPart ) // no buffer part found
320  {
321  // create a copy of the part
322  try
323  {
324  LIB_PART* part = symTable()->LoadSymbol( aLibrary, aAlias );
325 
326  if( part == nullptr )
327  THROW_IO_ERROR( _( "Symbol not found." ) );
328 
329  LIB_PART* bufferedParent = nullptr;
330 
331  // Create parent symbols on demand so parent symbol can be set.
332  if( part->IsAlias() )
333  {
334  std::shared_ptr< LIB_PART > parent = part->GetParent().lock();
335  wxCHECK_MSG( parent, nullptr,
336  wxString::Format( "Derived symbol '%s' found with undefined parent.",
337  part->GetName() ) );
338 
339  // Check if the parent symbol buffer has already be created.
340  bufferedParent = libBuf.GetPart( parent->GetName() );
341 
342  if( !bufferedParent )
343  {
344  bufferedParent = new LIB_PART( *parent.get() );
345  libBuf.CreateBuffer( bufferedParent, new SCH_SCREEN( &m_frame.Kiway() ) );
346  }
347  }
348 
349  bufferedPart = new LIB_PART( *part );
350 
351  if( bufferedParent )
352  bufferedPart->SetParent( bufferedParent );
353 
354  libBuf.CreateBuffer( bufferedPart, new SCH_SCREEN( &m_frame.Kiway() ) );
355  }
356  catch( const IO_ERROR& e )
357  {
358  wxLogMessage( _( "Error loading symbol \"%s\" from library \"%s\". (%s)" ),
359  aAlias, aLibrary, e.What() );
360  bufferedPart = nullptr;
361  }
362  }
363 
364  return bufferedPart;
365 }
366 
367 
368 SCH_SCREEN* LIB_MANAGER::GetScreen( const wxString& aAlias, const wxString& aLibrary )
369 {
370  wxCHECK( LibraryExists( aLibrary ), nullptr );
371  wxCHECK( !aAlias.IsEmpty(), nullptr );
372  auto it = m_libs.find( aLibrary );
373  wxCHECK( it != m_libs.end(), nullptr );
374 
375  LIB_BUFFER& buf = it->second;
376  auto partBuf = buf.GetBuffer( aAlias );
377  return partBuf ? partBuf->GetScreen() : nullptr;
378 }
379 
380 
381 bool LIB_MANAGER::UpdatePart( LIB_PART* aPart, const wxString& aLibrary )
382 {
383  wxCHECK( LibraryExists( aLibrary ), false );
384  wxCHECK( aPart, false );
385  LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
386  auto partBuf = libBuf.GetBuffer( aPart->GetName() );
387 
388  if( partBuf ) // Existing symbol.
389  {
390  LIB_PART* bufferedPart = const_cast< LIB_PART* >( partBuf->GetPart() );
391 
392  wxCHECK( bufferedPart, false );
393 
394  *bufferedPart = *aPart;
395  partBuf->GetScreen()->SetModify();
396  }
397  else // New symbol
398  {
399  LIB_PART* partCopy = new LIB_PART( *aPart, nullptr );
400 
401  partCopy->SetLibId( LIB_ID( aLibrary, aPart->GetLibId().GetLibItemName() ) );
402 
403  SCH_SCREEN* screen = new SCH_SCREEN( &m_frame.Kiway() );
404  libBuf.CreateBuffer( partCopy, screen );
405  screen->SetModify();
406  }
407 
408  return true;
409 }
410 
411 
412 bool LIB_MANAGER::UpdatePartAfterRename( LIB_PART* aPart, const wxString& aOldName,
413  const wxString& aLibrary )
414 {
415  LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
416  auto partBuf = libBuf.GetBuffer( aOldName );
417 
418  wxCHECK( partBuf, false );
419 
420  libBuf.UpdateBuffer( partBuf, aPart );
421  SetCurrentPart( aPart->GetName() );
422  m_frame.SyncLibraries( false );
423 
424  return true;
425 }
426 
427 
428 bool LIB_MANAGER::FlushPart( const wxString& aAlias, const wxString& aLibrary )
429 {
430  auto it = m_libs.find( aLibrary );
431 
432  if( it == m_libs.end() ) // no items to flush
433  return true;
434 
435  auto partBuf = it->second.GetBuffer( aAlias );
436  wxCHECK( partBuf, false );
437 
438  return it->second.SaveBuffer( partBuf, symTable() );
439 }
440 
441 
442 LIB_ID LIB_MANAGER::RevertPart( const wxString& aAlias, const wxString& aLibrary )
443 {
444  auto it = m_libs.find( aLibrary );
445 
446  if( it == m_libs.end() ) // no items to flush
447  return LIB_ID( aLibrary, aAlias );
448 
449  auto partBuf = it->second.GetBuffer( aAlias );
450  wxCHECK( partBuf, LIB_ID( aLibrary, aAlias ) );
451  LIB_PART original( *partBuf->GetOriginal() );
452 
453  if( original.GetName() != aAlias )
454  {
455  UpdatePartAfterRename( &original, aAlias, aLibrary );
456  }
457  else
458  {
459  partBuf->SetPart( new LIB_PART( original ) );
460  m_frame.SyncLibraries( false );
461  }
462 
463  return LIB_ID( aLibrary, original.GetName() );
464 }
465 
466 
467 bool LIB_MANAGER::RevertLibrary( const wxString& aLibrary )
468 {
469  auto it = m_libs.find( aLibrary );
470 
471  if( it == m_libs.end() ) // nothing to reverse
472  return false;
473 
474  m_libs.erase( it );
475  m_frame.SyncLibraries( false );
476 
477  return true;
478 }
479 
480 
482 {
483  bool retv = true;
484 
485  // Nothing to revert.
486  if( GetHash() == 0 )
487  return true;
488 
489  for( const auto& lib : m_libs )
490  {
491  if( !lib.second.IsModified() )
492  continue;
493 
494  for( const auto& buffer : lib.second.GetBuffers() )
495  {
496  if( !buffer->IsModified() )
497  continue;
498 
499  RevertPart( lib.first, buffer->GetOriginal()->GetName() );
500  }
501  }
502 
503  return retv;
504 }
505 
506 
507 bool LIB_MANAGER::RemovePart( const wxString& aAlias, const wxString& aLibrary )
508 {
509  LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary );
510  auto partBuf = libBuf.GetBuffer( aAlias );
511  wxCHECK( partBuf, false );
512 
513  bool retv = true;
514 
515  retv &= libBuf.DeleteBuffer( partBuf );
516  m_frame.SyncLibraries( false );
517 
518  return retv;
519 }
520 
521 
522 LIB_PART* LIB_MANAGER::GetAlias( const wxString& aAlias, const wxString& aLibrary ) const
523 {
524  // Try the library buffers first
525  auto libIt = m_libs.find( aLibrary );
526 
527  if( libIt != m_libs.end() )
528  {
529  LIB_PART* part = libIt->second.GetPart( aAlias );
530 
531  if( part )
532  return part;
533  }
534 
535  // Get the original part
536  LIB_PART* alias = nullptr;
537 
538  try
539  {
540  alias = symTable()->LoadSymbol( aLibrary, aAlias );
541  }
542  catch( const IO_ERROR& e )
543  {
544  wxLogMessage( _( "Cannot load symbol \"%s\" from library \"%s\" (%s)" ),
545  aAlias, aLibrary, e.What() );
546  }
547 
548  return alias;
549 }
550 
551 
552 bool LIB_MANAGER::PartExists( const wxString& aAlias, const wxString& aLibrary ) const
553 {
554  auto libBufIt = m_libs.find( aLibrary );
555  LIB_PART* alias = nullptr;
556 
557  if( libBufIt != m_libs.end() )
558  return !!libBufIt->second.GetBuffer( aAlias );
559 
560  try
561  {
562  alias = symTable()->LoadSymbol( aLibrary, aAlias );
563  }
564  catch( IO_ERROR& )
565  {
566  // checking if certain symbol exists, so its absence is perfectly fine
567  }
568 
569  return alias != nullptr;
570 }
571 
572 
573 bool LIB_MANAGER::LibraryExists( const wxString& aLibrary, bool aCheckEnabled ) const
574 {
575  if( aLibrary.IsEmpty() )
576  return false;
577 
578  if( m_libs.count( aLibrary ) > 0 )
579  return true;
580 
581  return symTable()->HasLibrary( aLibrary, aCheckEnabled );
582 }
583 
584 
586 {
587  wxString name = "New_Library";
588 
589  if( !LibraryExists( name ) )
590  return name;
591 
592  name += "_";
593 
594  for( unsigned int i = 0; i < std::numeric_limits<unsigned int>::max(); ++i )
595  {
596  if( !LibraryExists( name + wxString::Format( "%u", i ) ) )
597  return name + wxString::Format( "%u", i );
598  }
599 
600  wxFAIL;
601  return wxEmptyString;
602 }
603 
604 
605 void LIB_MANAGER::GetRootSymbolNames( const wxString& aLibraryName,
606  wxArrayString& aRootSymbolNames )
607 {
608  LIB_BUFFER& libBuf = getLibraryBuffer( aLibraryName );
609 
610  libBuf.GetRootSymbolNames( aRootSymbolNames );
611 }
612 
613 
614 bool LIB_MANAGER:: HasDerivedSymbols( const wxString& aSymbolName,
615  const wxString& aLibraryName )
616 {
617  LIB_BUFFER& libBuf = getLibraryBuffer( aLibraryName );
618 
619  return libBuf.HasDerivedSymbols( aSymbolName );
620 }
621 
622 
623 wxString LIB_MANAGER::getLibraryName( const wxString& aFilePath )
624 {
625  wxFileName fn( aFilePath );
626  return fn.GetName();
627 }
628 
629 
630 bool LIB_MANAGER::addLibrary( const wxString& aFilePath, bool aCreate, SYMBOL_LIB_TABLE* aTable )
631 {
632  wxCHECK( aTable, false );
633  wxString libName = getLibraryName( aFilePath );
634  wxCHECK( !LibraryExists( libName ), false ); // either create or add an existing one
635 
636  // try to use path normalized to an environmental variable or project path
637  wxString relPath = NormalizePath( aFilePath, &Pgm().GetLocalEnvVariables(), &m_frame.Prj() );
638 
639  if( relPath.IsEmpty() )
640  relPath = aFilePath;
641 
642  wxString typeName = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY );
643  SYMBOL_LIB_TABLE_ROW* libRow = new SYMBOL_LIB_TABLE_ROW( libName, relPath, typeName );
644  aTable->InsertRow( libRow );
645 
646  if( aCreate )
647  {
648  try
649  {
650  aTable->CreateSymbolLib( libName );
651  }
652  catch( const IO_ERROR& e )
653  {
654  aTable->RemoveRow( libRow );
655  return false;
656  }
657  }
658 
659  m_frame.SyncLibraries( false );
660 
661  return true;
662 }
663 
664 
666 {
667  return m_frame.Prj().SchSymbolLibTable();
668 }
669 
670 
671 std::set<LIB_PART*> LIB_MANAGER::getOriginalParts( const wxString& aLibrary )
672 {
673  std::set<LIB_PART*> parts;
674  wxCHECK( LibraryExists( aLibrary ), parts );
675 
676  try
677  {
678  wxArrayString aliases;
679  symTable()->EnumerateSymbolLib( aLibrary, aliases );
680 
681  for( const auto& aliasName : aliases )
682  {
683  LIB_PART* alias = symTable()->LoadSymbol( aLibrary, aliasName );
684  parts.insert( alias );
685  }
686  }
687  catch( const IO_ERROR& e )
688  {
689  wxLogMessage( _( "Cannot enumerate library \"%s\" (%s)" ), aLibrary, e.What() );
690  }
691 
692  return parts;
693 }
694 
695 
697 {
698  auto it = m_libs.find( aLibrary );
699 
700  if( it != m_libs.end() )
701  return it->second;
702 
703  // The requested buffer does not exist yet, so create one
704  auto ret = m_libs.emplace( aLibrary, LIB_BUFFER( aLibrary ) );
705  LIB_BUFFER& buf = ret.first->second;
706 
707  for( auto part : getOriginalParts( aLibrary ) )
708  {
709  LIB_PART* newSymbol;
710 
711  if( part->IsAlias() )
712  {
713  std::shared_ptr< LIB_PART > oldParent = part->GetParent().lock();
714 
715  wxCHECK_MSG( oldParent, buf,
716  wxString::Format( "Derived symbol '%s' found with undefined parent.",
717  part->GetName() ) );
718 
719  LIB_PART* libParent = buf.GetPart( oldParent->GetName() );
720 
721  if( !libParent )
722  {
723  libParent = new LIB_PART( *oldParent.get() );
724  buf.CreateBuffer( libParent, new SCH_SCREEN( &m_frame.Kiway() ) );
725  }
726 
727  newSymbol = new LIB_PART( *part );
728  newSymbol->SetParent( libParent );
729  buf.CreateBuffer( newSymbol, new SCH_SCREEN( &m_frame.Kiway() ) );
730  }
731  else if( !buf.GetPart( part->GetName() ) )
732  {
733  buf.CreateBuffer( new LIB_PART( *part ), new SCH_SCREEN( &m_frame.Kiway() ) );
734  }
735  }
736 
737  return buf;
738 }
739 
740 
741 LIB_MANAGER::PART_BUFFER::PART_BUFFER( LIB_PART* aPart, std::unique_ptr<SCH_SCREEN> aScreen ) :
742  m_screen( std::move( aScreen ) ),
743  m_part( aPart )
744 {
745  m_original = new LIB_PART( *aPart );
746 }
747 
748 
750 {
751  delete m_part;
752  delete m_original;
753 }
754 
755 
757 {
758  wxCHECK( m_part != aPart, /* void */ );
759  wxASSERT( aPart );
760  delete m_part;
761  m_part = aPart;
762 
763  // If the part moves libraries then the original moves with it
764  if( m_original->GetLibId().GetLibNickname() != m_part->GetLibId().GetLibNickname() )
765  {
766  m_original->SetLibId( LIB_ID( m_part->GetLibId().GetLibNickname(),
767  m_original->GetLibId().GetLibItemName() ) );
768  }
769 }
770 
771 
773 {
774  wxCHECK( m_original != aPart, /* void */ );
775  wxASSERT( aPart );
776  delete m_original;
777  m_original = aPart;
778 
779  // The original is not allowed to have a different library than its part
780  if( m_original->GetLibId().GetLibNickname() != m_part->GetLibId().GetLibNickname() )
781  {
782  m_original->SetLibId( LIB_ID( m_part->GetLibId().GetLibNickname(),
783  m_original->GetLibId().GetLibItemName() ) );
784  }
785 }
786 
787 
789 {
790  return m_screen && m_screen->IsModify();
791 }
792 
793 
794 LIB_PART* LIB_MANAGER::LIB_BUFFER::GetPart( const wxString& aAlias ) const
795 {
796  auto buf = GetBuffer( aAlias );
797 
798  if( !buf )
799  return nullptr;
800 
801  LIB_PART* part = buf->GetPart();
802 
803  wxCHECK( part, nullptr );
804 
805  return part;
806 }
807 
808 
810 {
811  wxASSERT( aCopy );
812  wxASSERT( aCopy->GetLib() == nullptr );
813  std::unique_ptr<SCH_SCREEN> screen( aScreen );
814  auto partBuf = std::make_shared<PART_BUFFER>( aCopy, std::move( screen ) );
815  m_parts.push_back( partBuf );
816 
817  // Set the parent library name,
818  // otherwise it is empty as no library has been given as the owner during object construction
819  LIB_ID libId = aCopy->GetLibId();
820  libId.SetLibNickname( m_libName );
821  aCopy->SetLibId( libId );
822  ++m_hash;
823 
824  return true;
825 }
826 
827 
829  LIB_PART* aCopy )
830 {
831  wxCHECK( aCopy && aPartBuf, false );
832 
833  LIB_PART* bufferedPart = aPartBuf->GetPart();
834 
835  wxCHECK( bufferedPart, false );
836 
837  *bufferedPart = *aCopy;
838  ++m_hash;
839 
840  return true;
841 }
842 
843 
845 {
846  auto partBufIt = std::find( m_parts.begin(), m_parts.end(), aPartBuf );
847  wxCHECK( partBufIt != m_parts.end(), false );
848 
849  bool retv = true;
850 
851  // Remove all derived symbols to prevent broken inheritance.
852  if( aPartBuf->GetPart()->IsRoot() && HasDerivedSymbols( aPartBuf->GetPart()->GetName() )
853  && removeChildSymbols( aPartBuf ) == 0 )
854  retv = false;
855 
856  m_deleted.emplace_back( *partBufIt );
857  m_parts.erase( partBufIt );
858  ++m_hash;
859 
860  return retv;
861 }
862 
863 
865  SYMBOL_LIB_TABLE* aLibTable )
866 {
867  wxCHECK( aPartBuf, false );
868  LIB_PART* part = aPartBuf->GetPart();
869  wxCHECK( part, false );
871 
872  if( part->IsAlias() )
873  {
874  LIB_PART* originalPart;
875  LIB_PART* newCachedPart = new LIB_PART( *part );
876  std::shared_ptr< LIB_PART > bufferedParent = part->GetParent().lock();
877 
878  wxCHECK( bufferedParent, false );
879 
880  LIB_PART* cachedParent = aLibTable->LoadSymbol( m_libName, bufferedParent->GetName() );
881 
882  if( !cachedParent )
883  {
884  cachedParent = new LIB_PART( *bufferedParent.get() );
885  newCachedPart->SetParent( cachedParent );
886  result = aLibTable->SaveSymbol( m_libName, cachedParent );
887  wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
888  result = aLibTable->SaveSymbol( m_libName, newCachedPart );
889  wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
890 
891  LIB_PART* originalParent = new LIB_PART( *bufferedParent.get() );
892  aPartBuf->SetOriginal( originalParent );
893  originalPart = new LIB_PART( *part );
894  originalPart->SetParent( originalParent );
895  aPartBuf->SetOriginal( originalPart );
896  }
897  else
898  {
899  newCachedPart->SetParent( cachedParent );
900  result = aLibTable->SaveSymbol( m_libName, newCachedPart );
901  wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
902 
903  LIB_MANAGER::PART_BUFFER::PTR originalBufferedParent =
904  GetBuffer( bufferedParent->GetName() );
905  wxCHECK( originalBufferedParent, false );
906  originalPart = new LIB_PART( *part );
907  originalPart->SetParent( originalBufferedParent->GetPart() );
908  aPartBuf->SetOriginal( originalPart );
909  }
910  }
911  else
912  {
913  wxArrayString derivedSymbols;
914 
915  if( GetDerivedSymbolNames( part->GetName(), derivedSymbols ) == 0 )
916  {
917  result = aLibTable->SaveSymbol( m_libName, new LIB_PART( *part ) );
918  wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
919  aPartBuf->SetOriginal( new LIB_PART( *part ) );
920  }
921  else
922  {
923  LIB_PART* parentSymbol = new LIB_PART( *part );
924 
925  aLibTable->SaveSymbol( m_libName, parentSymbol );
926 
927  for( auto entry : derivedSymbols )
928  {
929  LIB_MANAGER::PART_BUFFER::PTR symbol = GetBuffer( entry );
930  LIB_PART* derivedSymbol = new LIB_PART( *symbol->GetPart() );
931  derivedSymbol->SetParent( parentSymbol );
932  result = aLibTable->SaveSymbol( m_libName, derivedSymbol );
933  wxCHECK( result == SYMBOL_LIB_TABLE::SAVE_OK, false );
934  }
935  }
936  }
937 
938  ++m_hash;
939  return true;
940 }
941 
942 
944  SCH_PLUGIN* aPlugin, bool aBuffer )
945 {
946  wxCHECK( aPartBuf, false );
947  LIB_PART* part = aPartBuf->GetPart();
948  wxCHECK( part, false );
949 
950  wxString errorMsg = _( "An error \"%s\" occurred saving symbol \"%s\" to library \"%s\"" );
951 
952  // set properties to prevent save file on every symbol save
953  PROPERTIES properties;
954  properties.emplace( SCH_LEGACY_PLUGIN::PropBuffering, "" );
955 
956  if( part->IsAlias() )
957  {
958  LIB_PART* originalPart;
959  LIB_PART* newCachedPart = new LIB_PART( *part );
960  std::shared_ptr< LIB_PART > bufferedParent = part->GetParent().lock();
961 
962  wxCHECK( bufferedParent, false );
963 
964  LIB_PART* cachedParent = nullptr;
965 
966  try
967  {
968  cachedParent = aPlugin->LoadSymbol( m_libName, bufferedParent->GetName() );
969  }
970  catch( const IO_ERROR& ioe )
971  {
972  return false;
973  }
974 
975  if( !cachedParent )
976  {
977  cachedParent = new LIB_PART( *bufferedParent.get() );
978  newCachedPart->SetParent( cachedParent );
979 
980  try
981  {
982  aPlugin->SaveSymbol( m_libName, cachedParent, aBuffer ? &properties : nullptr );
983  }
984  catch( const IO_ERROR& ioe )
985  {
986  wxLogError( errorMsg, ioe.What(), cachedParent->GetName() );
987  return false;
988  }
989 
990  try
991  {
992  aPlugin->SaveSymbol( m_libName, newCachedPart, aBuffer ? &properties : nullptr );
993  }
994  catch( const IO_ERROR& ioe )
995  {
996  wxLogError( errorMsg, ioe.What(), newCachedPart->GetName() );
997  return false;
998  }
999 
1000  LIB_PART* originalParent = new LIB_PART( *bufferedParent.get() );
1001  aPartBuf->SetOriginal( originalParent );
1002  originalPart = new LIB_PART( *part );
1003  originalPart->SetParent( originalParent );
1004  aPartBuf->SetOriginal( originalPart );
1005  }
1006  else
1007  {
1008  newCachedPart->SetParent( cachedParent );
1009 
1010  try
1011  {
1012  aPlugin->SaveSymbol( m_libName, newCachedPart, aBuffer ? &properties : nullptr );
1013  }
1014  catch( const IO_ERROR& ioe )
1015  {
1016  wxLogError( errorMsg, ioe.What(), newCachedPart->GetName() );
1017  return false;
1018  }
1019 
1020  LIB_MANAGER::PART_BUFFER::PTR originalBufferedParent =
1021  GetBuffer( bufferedParent->GetName() );
1022  wxCHECK( originalBufferedParent, false );
1023  originalPart = new LIB_PART( *part );
1024  originalPart->SetParent( originalBufferedParent->GetPart() );
1025  aPartBuf->SetOriginal( originalPart );
1026  }
1027  }
1028  else
1029  {
1030  wxArrayString derivedSymbols;
1031 
1032  if( GetDerivedSymbolNames( part->GetName(), derivedSymbols ) == 0 )
1033  {
1034  try
1035  {
1036  aPlugin->SaveSymbol( m_libName, new LIB_PART( *part ),
1037  aBuffer ? &properties : nullptr );
1038  }
1039  catch( const IO_ERROR& ioe )
1040  {
1041  wxLogError( errorMsg, ioe.What(), part->GetName() );
1042  return false;
1043  }
1044 
1045  aPartBuf->SetOriginal( new LIB_PART( *part ) );
1046  }
1047  else
1048  {
1049  LIB_PART* parentSymbol = new LIB_PART( *part );
1050 
1051  // Save the modified root symbol.
1052  try
1053  {
1054  aPlugin->SaveSymbol( m_libName, new LIB_PART( *part ),
1055  aBuffer ? &properties : nullptr );
1056  }
1057  catch( const IO_ERROR& ioe )
1058  {
1059  wxLogError( errorMsg, ioe.What(), part->GetName() );
1060  return false;
1061  }
1062 
1063  aPartBuf->SetOriginal( new LIB_PART( *part ) );
1064 
1065  // Save the derived symbols.
1066  for( auto entry : derivedSymbols )
1067  {
1068  LIB_MANAGER::PART_BUFFER::PTR symbol = GetBuffer( entry );
1069  LIB_PART* derivedSymbol = new LIB_PART( *symbol->GetPart() );
1070  derivedSymbol->SetParent( parentSymbol );
1071 
1072  try
1073  {
1074  aPlugin->SaveSymbol( m_libName, new LIB_PART( *derivedSymbol ),
1075  aBuffer ? &properties : nullptr );
1076  }
1077  catch( const IO_ERROR& ioe )
1078  {
1079  wxLogError( errorMsg, ioe.What(), derivedSymbol->GetName() );
1080  return false;
1081  }
1082  }
1083  }
1084  }
1085 
1086  ++m_hash;
1087  return true;
1088 }
1089 
1090 
1092 {
1093  for( auto entry : m_parts )
1094  {
1095  if( entry->GetPart()->GetName() == aAlias )
1096  return entry;
1097  }
1098 
1099  return PART_BUFFER::PTR( nullptr );
1100 }
1101 
1102 
1103 bool LIB_MANAGER::LIB_BUFFER::HasDerivedSymbols( const wxString& aParentName ) const
1104 {
1105  for( auto entry : m_parts )
1106  {
1107  if( entry->GetPart()->IsAlias() )
1108  {
1109  PART_SPTR parent = entry->GetPart()->GetParent().lock();
1110 
1111  // Check for inherited part without a valid parent.
1112  wxCHECK( parent, false );
1113 
1114  if( parent->GetName() == aParentName )
1115  return true;
1116  }
1117  }
1118 
1119  return false;
1120 }
1121 
1122 
1123 void LIB_MANAGER::LIB_BUFFER::GetRootSymbolNames( wxArrayString& aRootSymbolNames )
1124 {
1125  for( auto entry : m_parts )
1126  {
1127  if( entry->GetPart()->IsAlias() )
1128  continue;
1129 
1130  aRootSymbolNames.Add( entry->GetPart()->GetName() );
1131  }
1132 }
1133 
1134 
1135 size_t LIB_MANAGER::LIB_BUFFER::GetDerivedSymbolNames( const wxString& aSymbolName,
1136  wxArrayString& aList )
1137 {
1138  wxCHECK( !aSymbolName.IsEmpty(), 0 );
1139 
1140  for( auto entry : m_parts )
1141  {
1142  if( entry->GetPart()->IsAlias() )
1143  {
1144  PART_SPTR parent = entry->GetPart()->GetParent().lock();
1145 
1146  // Check for inherited part without a valid parent.
1147  wxCHECK( parent, false );
1148 
1149  if( parent->GetName() == aSymbolName )
1150  aList.Add( entry->GetPart()->GetName() );
1151  }
1152  }
1153 
1154  return aList.GetCount();
1155 }
1156 
1157 
1159 {
1160  wxCHECK( aPartBuf && aPartBuf->GetPart()->IsRoot(), 0 );
1161 
1162  int cnt = 0;
1163  std::deque< LIB_MANAGER::PART_BUFFER::PTR >::iterator it = m_parts.begin();
1164 
1165  while( it != m_parts.end() )
1166  {
1167 
1168  if( (*it)->GetPart()->IsRoot() )
1169  {
1170  ++it;
1171  }
1172  else
1173  {
1174  PART_SPTR parent = (*it)->GetPart()->GetParent().lock();
1175 
1176  wxCHECK2( parent, ++it; continue );
1177 
1178  if( parent->GetName() == aPartBuf->GetPart()->GetName() )
1179  {
1180  wxCHECK2( parent == aPartBuf->GetPart()->SharedPtr(), ++it; continue );
1181 
1182  m_deleted.emplace_back( *it );
1183  it = m_parts.erase( it );
1184  cnt++;
1185  }
1186  else
1187  {
1188  ++it;
1189  }
1190  }
1191  }
1192 
1193  return cnt;
1194 }
PART_LIB * GetLib()
SAVE_T SaveSymbol(const wxString &aNickname, const LIB_PART *aSymbol, bool aOverwrite=true)
Write aSymbol to an existing library given by aNickname.
void Sync(bool aForce=false, std::function< void(int, int, const wxString &)> aProgressCallback=[](int, int, const wxString &){})
Updates the LIB_MANAGER data to synchronize with Symbol Library Table.
Definition: lib_manager.cpp:48
static PTR Create(LIB_EDIT_FRAME *aParent, LIB_MANAGER *aLibs)
void EnumerateSymbolLib(const wxString &aNickname, wxArrayString &aAliasNames, bool aPowerSymbolsOnly=false)
Return a list of symbol alias names contained within the library given by aNickname.
SYMBOL_LIB_TABLE_ROW * FindRow(const wxString &aNickName)
Return an SYMBOL_LIB_TABLE_ROW if aNickName is found in this table or in any chained fallBack table f...
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:98
LIB_ID GetLibId() const override
bool HasDerivedSymbols(const wxString &aSymbolName, const wxString &aLibraryName)
Check if symbol aSymbolName in library aLibraryName is a root symbol that has derived symbols.
wxString GetName() const override
void CreateSymbolLib(const wxString &aNickname)
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
std::list< LIB_PART * > GetAliases(const wxString &aLibrary) const
bool RemovePart(const wxString &aName, const wxString &aLibrary)
Removes the part from the part buffer.
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
Definition: sch_io_mgr.cpp:76
bool CreateBuffer(LIB_PART *aCopy, SCH_SCREEN *aScreen)
Creates a new buffer to store a part. LIB_BUFFER takes ownership of aCopy.
void SetPart(LIB_PART *aPart)
LIB_PART * GetPart(const wxString &aAlias) const
Returns the working copy of a LIB_PART root object with specified alias.
LIB_PART * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_PART having aName from the library given by aNickname.
Template specialization to enable wxStrings for certain containers (e.g. unordered_map)
Definition: bitmap.cpp:55
const std::deque< PART_BUFFER::PTR > & GetBuffers() const
Returns all buffered parts
Definition: lib_manager.h:404
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:49
bool DeleteBuffer(PART_BUFFER::PTR aPartBuf)
void GetRootSymbolNames(wxArrayString &aRootSymbolNames)
Fetchs a list of root symbols names from the library buffer.
LIB_PART * GetAlias(const wxString &aAlias, const wxString &aLibrary) const
Returns either an alias of a working LIB_PART copy, or alias of the original part if there is no work...
int GetLibraryHash(const wxString &aLibrary) const
Returns a library hash value to determine if it has changed.
Definition: lib_manager.cpp:88
PART_BUFFER(LIB_PART *aPart=nullptr, std::unique_ptr< SCH_SCREEN > aScreen=nullptr)
Base class that schematic file and library loading and saving plugins should derive from.
Definition: sch_io_mgr.h:187
bool UpdateBuffer(PART_BUFFER::PTR aPartBuf, LIB_PART *aCopy)
Updates the buffered part with the contents of aCopy.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
wxString GetUniqueLibraryName() const
Returns a library name that is not currently in use.
LIB_ID RevertPart(const wxString &aAlias, const wxString &aLibrary)
Reverts unsaved changes for a particular part.
bool IsPartModified(const wxString &aAlias, const wxString &aLibrary) const
Returns true if part has unsaved modifications.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
Class LIB_PIN definition.
std::shared_ptr< LIB_PART > PART_SPTR
shared pointer to LIB_PART
SCH_SCREEN * GetScreen(const wxString &aAlias, const wxString &aLibrary)
Returns the screen used to edit a specific part.
virtual LIB_PART * LoadSymbol(const wxString &aLibraryPath, const wxString &aPartName, const PROPERTIES *aProperties=NULL)
Load a LIB_PART object having aPartName from the aLibraryPath containing a library format that this S...
Definition: sch_plugin.cpp:84
LIB_EDIT_FRAME & m_frame
Definition: lib_manager.h:460
LIB_LOGGER m_logger
Definition: lib_manager.h:461
void SetParent(LIB_PART *aParent=nullptr)
PART_REF & GetParent()
int GetHash() const
Definition: lib_manager.cpp:77
void LoadSymbolLib(std::vector< LIB_PART * > &aAliasList, const wxString &aNickname, bool aPowerSymbolsOnly=false)
Define a library symbol object.
SYMBOL_TREE_SYNCHRONIZING_ADAPTER::PTR m_adapter
Definition: lib_manager.h:467
int removeChildSymbols(PART_BUFFER::PTR aPartBuf)
Remove all symbols derived from aParent from the library buffer.
wxArrayString GetLibraryNames() const
Returns the array of library names.
SYMBOL_LIB_TABLE_ROW * GetLibrary(const wxString &aLibrary) const
Finds a single library within the (aggregate) library table.
#define THROW_IO_ERROR(msg)
LIB_PART(const wxString &aName, LIB_PART *aParent=nullptr, PART_LIB *aLibrary=nullptr)
Class to store a working copy of a library
Definition: lib_manager.h:352
void SetCurrentPart(const wxString &aPart)
Definition: lib_manager.h:281
bool FlushPart(const wxString &aAlias, const wxString &aLibrary)
Saves part changes to the library copy used by the schematic editor.
bool PartExists(const wxString &aAlias, const wxString &aLibrary) const
Returns true if part with a specific alias exists in library (either original one or buffered).
size_t GetDerivedSymbolNames(const wxString &aSymbolName, wxArrayString &aList)
Fetch all of the symbols derived from a aSymbolName into aList.
bool ClearLibraryModified(const wxString &aLibrary) const
Clears the modified flag for all parts in a library.
bool SaveLibrary(const wxString &aLibrary, const wxString &aFileName)
Saves library to a file, including unsaved changes.
PART_BUFFER::PTR GetBuffer(const wxString &aAlias) const
Returns a part buffer with LIB_PART holding a particular alias
bool UpdatePart(LIB_PART *aPart, const wxString &aLibrary)
Updates the part buffer with a new version of the part.
bool SaveBuffer(PART_BUFFER::PTR aPartBuf, SYMBOL_LIB_TABLE *aLibTable)
Saves stored modifications to Symbol Lib Table.
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:193
bool RemoveRow(LIB_TABLE_ROW *aRow)
Removes a row from the table.
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:497
void GetRootSymbolNames(const wxString &aLibName, wxArrayString &aRootSymbolNames)
void SyncLibraries(bool aShowProgress)
Synchronize the library manager to the symbol library table, and then the symbol tree to the library ...
bool addLibrary(const wxString &aFilePath, bool aCreate, SYMBOL_LIB_TABLE *aTable)
Helper function to add either existing or create new library
LIB_PART * GetBufferedPart(const wxString &aAlias, const wxString &aLibrary)
Returns the part copy from the buffer.
void Activate()
Definition: lib_manager.h:59
The symbol library editor main window.
void Deactivate()
Definition: lib_manager.h:69
see class PGM_BASE
LIB_MANAGER(LIB_EDIT_FRAME &aFrame)
Definition: lib_manager.cpp:39
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
std::set< LIB_PART * > getOriginalParts(const wxString &aLibrary)
Returns a set of LIB_PART objects belonging to the original library
LIB_BUFFER & getLibraryBuffer(const wxString &aLibrary)
Returns an existing library buffer or creates one to using Symbol Library Table to get the original d...
#define _(s)
Definition: 3d_actions.cpp:31
bool LibraryExists(const wxString &aLibrary, bool aCheckEnabled=false) const
Returns true if library exists.
SYMBOL_LIB_TABLE * symTable() const
Returns the current Symbol Library Table
bool HasDerivedSymbols(const wxString &aParentName) const
Checks to see any parts in the buffer are derived from a parent named aParentName.
bool IsAlias() const
void ClrModify()
Definition: base_screen.h:225
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
bool HasModifications() const
Definition: lib_manager.cpp:65
bool IsLibraryModified(const wxString &aLibrary) const
Returns true if library has unsaved modifications.
std::shared_ptr< PART_BUFFER > PTR
Definition: lib_manager.h:340
virtual void SaveSymbol(const wxString &aLibraryPath, const LIB_PART *aSymbol, const PROPERTIES *aProperties=NULL)
Write aSymbol to an existing library located at aLibraryPath.
Definition: sch_plugin.cpp:93
SAVE_T
The set of return values from SaveSymbol() below.
void SetOriginal(LIB_PART *aPart)
void Sync(bool aForce=false, std::function< void(int, int, const wxString &)> aProgressCallback=[](int, int, const wxString &){})
std::map< wxString, LIB_BUFFER > m_libs
The library buffers
Definition: lib_manager.h:458
Definition for part library class.
void SetModify()
Definition: base_screen.h:224
static wxString getLibraryName(const wxString &aFilePath)
Extracts library name basing on the file name
void SetLibId(const LIB_ID &aLibId)
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 RevertAll()
Revert all pending changes.
bool IsLibraryReadOnly(const wxString &aLibrary) const
Returns true if the library is stored in a read-only file.
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalizes a file path to an environmental variable, if possible.
Definition: env_paths.cpp:67
bool ClearPartModified(const wxString &aAlias, const wxString &aLibrary) const
Clears the modified flag for a part.
bool RevertLibrary(const wxString &aLibrary)
Reverts unsaved changes for a particular library.
bool UpdatePartAfterRename(LIB_PART *aPart, const wxString &oldAlias, const wxString &aLibrary)
Updates the part buffer with a new version of the part when the name has changed.
SYMBOL_TREE_SYNCHRONIZING_ADAPTER * getAdapter()
Definition: lib_manager.h:468