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