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