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