KiCad PCB EDA Suite
Loading...
Searching...
No Matches
project_rescue.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) 2015 Chris Pavlina <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <sch_draw_panel.h>
27#include <confirm.h>
28#include <connection_graph.h>
29#include <invoke_sch_dialog.h>
30#include <kiway.h>
31#include <symbol_viewer_frame.h>
32#include <project_rescue.h>
33#include <project_sch.h>
34#include <sch_edit_frame.h>
35#include <string_utils.h>
37#include <wx/msgdlg.h>
38
39#include <cctype>
40#include <map>
41#include <pgm_base.h>
43
44
45// Helper sort function, used in getSymbols, to sort a symbol list by lib_id
46static bool sort_by_libid( const SCH_SYMBOL* ref, SCH_SYMBOL* cmp )
47{
48 return ref->GetLibId() < cmp->GetLibId();
49}
50
51
61static void getSymbols( SCHEMATIC* aSchematic, std::vector<SCH_SYMBOL*>& aSymbols )
62{
63 SCH_SCREENS screens( aSchematic->Root() );
64
65 // Get the full list
66 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
67 {
68 for( EDA_ITEM* aItem : screen->Items().OfType( SCH_SYMBOL_T ) )
69 aSymbols.push_back( static_cast<SCH_SYMBOL*>( aItem ) );
70 }
71
72 if( aSymbols.empty() )
73 return;
74
75 // sort aSymbols by lib symbol. symbols will be grouped by same lib symbol.
76 std::sort( aSymbols.begin(), aSymbols.end(), sort_by_libid );
77}
78
79
87static LIB_SYMBOL* findSymbol( const wxString& aName, LEGACY_SYMBOL_LIBS* aLibs, bool aCached )
88{
89 LIB_SYMBOL *symbol = nullptr;
90
91 for( LEGACY_SYMBOL_LIB& each_lib : *aLibs )
92 {
93 if( aCached && !each_lib.IsCache() )
94 continue;
95
96 if( !aCached && each_lib.IsCache() )
97 continue;
98
99 symbol = each_lib.FindSymbol( aName );
100
101 if( symbol )
102 break;
103 }
104
105 return symbol;
106}
107
108
109static wxFileName GetRescueLibraryFileName( SCHEMATIC* aSchematic )
110{
111 wxFileName fn = aSchematic->GetFileName();
112 fn.SetName( fn.GetName() + wxT( "-rescue" ) );
114 return fn;
115}
116
117
118RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName,
119 LIB_SYMBOL* aLibCandidate, int aUnit, int aBodyStyle ) :
120 RESCUE_CANDIDATE( aRequestedName, aNewName, aLibCandidate, aUnit, aBodyStyle )
121{}
122
123
124void RESCUE_CASE_CANDIDATE::FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
125{
126 std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map;
127
128 // Remember the list of symbols is sorted by symbol name.
129 // So a search in libraries is made only once by group
130 LIB_SYMBOL* case_sensitive_match = nullptr;
131 std::vector<LIB_SYMBOL*> case_insensitive_matches;
132
133 wxString symbol_name;
134 wxString last_symbol_name;
135
136 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
137 {
138 symbol_name = eachSymbol->GetLibId().GetUniStringLibItemName();
139
140 if( last_symbol_name != symbol_name )
141 {
142 // A new symbol name is found (a new group starts here).
143 // Search the symbol names candidates only once for this group:
144 last_symbol_name = symbol_name;
145 case_insensitive_matches.clear();
146
147 LIB_ID id( wxEmptyString, symbol_name );
148
149 case_sensitive_match = PROJECT_SCH::LegacySchLibs( aRescuer.GetPrj() )->FindLibSymbol( id );
150
151 if( case_sensitive_match )
152 continue;
153
154 // If the case sensitive match failed, try a case insensitive match.
156 ->FindLibraryNearEntries( case_insensitive_matches, symbol_name );
157
158 // If there are not case insensitive matches either, the symbol cannot be rescued.
159 if( !case_insensitive_matches.size() )
160 continue;
161
162 RESCUE_CASE_CANDIDATE candidate( symbol_name, case_insensitive_matches[0]->GetName(),
163 case_insensitive_matches[0], eachSymbol->GetUnit(),
164 eachSymbol->GetBodyStyle() );
165
166 candidate_map[symbol_name] = candidate;
167 }
168 }
169
170 // Now, dump the map into aCandidates
171 for( const auto& [ name, candidate ] : candidate_map )
172 aCandidates.push_back( new RESCUE_CASE_CANDIDATE( candidate ) );
173}
174
175
177{
178 wxString action;
179 action.Printf( _( "Rename %s to %s" ), m_requested_name, m_new_name );
180 return action;
181}
182
183
185{
186 wxCHECK( m_lib_candidate, true );
187
188 std::unique_ptr<LIB_SYMBOL> new_symbol = m_lib_candidate->Flatten();
189 new_symbol->SetName( m_new_name );
190 aRescuer->AddSymbol( new_symbol.get() );
191
192 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
193 {
194 if( eachSymbol->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
195 continue;
196
197 LIB_ID libId;
198
199 libId.SetLibItemName( m_new_name );
200 eachSymbol->SetLibId( libId );
201 eachSymbol->ClearFlags();
202 aRescuer->LogRescue( eachSymbol, m_requested_name, m_new_name );
203 }
204
205 return true;
206}
207
208
209void RESCUE_CACHE_CANDIDATE::FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
210{
211 std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map;
212
213 // Remember the list of symbols is sorted by symbol name.
214 // So a search in libraries is made only once by group
215 LIB_SYMBOL* cache_match = nullptr;
216 LIB_SYMBOL* lib_match = nullptr;
217 wxString symbol_name;
218 wxString old_symbol_name;
219
220 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
221 {
222 symbol_name = eachSymbol->GetLibId().GetUniStringLibItemName();
223
224 if( old_symbol_name != symbol_name )
225 {
226 // A new symbol name is found (a new group starts here).
227 // Search the symbol names candidates only once for this group:
228 old_symbol_name = symbol_name;
229 cache_match = findSymbol( symbol_name, PROJECT_SCH::LegacySchLibs( aRescuer.GetPrj() ), true );
230 lib_match = findSymbol( symbol_name, PROJECT_SCH::LegacySchLibs( aRescuer.GetPrj() ), false );
231
232 // At some point during V5 development, the LIB_ID delimiter character ':' was
233 // replaced by '_' when writing the symbol cache library so we have to test for
234 // the LIB_NICKNAME_LIB_SYMBOL_NAME case.
235 if( !cache_match && eachSymbol->GetLibId().IsValid() )
236 {
237 wxString tmp = wxString::Format( wxT( "%s-%s" ),
238 eachSymbol->GetLibId().GetLibNickname().wx_str(),
239 eachSymbol->GetLibId().GetLibItemName().wx_str() );
240 cache_match = findSymbol( tmp, PROJECT_SCH::LegacySchLibs( aRescuer.GetPrj() ),
241 true );
242 }
243
244 // Test whether there is a conflict or if the symbol can only be found in the cache
245 // and the symbol name does not have any illegal characters.
246 if( cache_match && lib_match
247 && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
248 {
249 continue;
250 }
251
252 if( !cache_match && lib_match )
253 continue;
254
255 // Check if the symbol has already been rescued.
256 RESCUE_CACHE_CANDIDATE candidate( symbol_name, symbol_name, cache_match, lib_match,
257 eachSymbol->GetUnit(), eachSymbol->GetBodyStyle() );
258
259 candidate_map[symbol_name] = candidate;
260 }
261 }
262
263 // Now, dump the map into aCandidates
264 for( const auto& [name, candidate] : candidate_map )
265 aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( candidate ) );
266}
267
268
270{
271 wxString action;
272
274 {
275 action.Printf( _( "Cannot rescue symbol %s which is not available in any library or the cache." ),
277 }
279 {
280 action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
282 m_new_name );
283 }
284 else
285 {
286 action.Printf( _( "Rescue modified symbol %s to %s" ),
288 m_new_name );
289 }
290
291 return action;
292}
293
294
296{
298
299 // A symbol that cannot be rescued is a valid condition so just bail out here.
300 if( !tmp )
301 return true;
302
303 std::unique_ptr<LIB_SYMBOL> new_symbol = tmp->Flatten();
304 new_symbol->SetName( m_new_name );
305 aRescuer->AddSymbol( new_symbol.get() );
306
307 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
308 {
309 if( eachSymbol->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
310 continue;
311
312 LIB_ID libId;
313
314 libId.SetLibItemName( m_new_name );
315 eachSymbol->SetLibId( libId );
316 eachSymbol->ClearFlags();
317 aRescuer->LogRescue( eachSymbol, m_requested_name, m_new_name );
318 }
319
320 return true;
321}
322
323
325 const LIB_ID& aNewId,
326 LIB_SYMBOL* aCacheCandidate,
327 LIB_SYMBOL* aLibCandidate,
328 int aUnit, int aBodyStyle ) :
329 RESCUE_CANDIDATE( aRequestedId.Format().wx_str(), wxEmptyString, aLibCandidate, aUnit, aBodyStyle ),
330 m_requested_id( aRequestedId ),
331 m_new_id( aNewId ),
332 m_cache_candidate( aCacheCandidate )
333{}
334
335
337 RESCUE_CANDIDATE( wxEmptyString, wxEmptyString, nullptr, 0, 0 ),
339 m_new_id(),
340 m_cache_candidate( nullptr )
341{}
342
343
345 boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
346{
347 std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map;
348
349 // Remember the list of symbols is sorted by LIB_ID.
350 // So a search in libraries is made only once by group
351 LIB_SYMBOL* cache_match = nullptr;
352 LIB_SYMBOL* lib_match = nullptr;
353 LIB_ID old_symbol_id;
354
355 wxString symbolName;
356
357 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
358 {
359 const LIB_ID& symbol_id = eachSymbol->GetLibId();
360
361 if( old_symbol_id != symbol_id )
362 {
363 // A new symbol name is found (a new group starts here).
364 // Search the symbol names candidates only once for this group:
365 old_symbol_id = symbol_id;
366
367 symbolName = symbol_id.Format().wx_str();
368
369 // Get the library symbol from the cache library. It will be a flattened
370 // symbol by default (no inheritance).
371 cache_match = findSymbol( symbolName, PROJECT_SCH::LegacySchLibs( aRescuer.GetPrj() ), true );
372
373 // At some point during V5 development, the LIB_ID delimiter character ':' was
374 // replaced by '_' when writing the symbol cache library so we have to test for
375 // the LIB_NICKNAME_LIB_SYMBOL_NAME case.
376 if( !cache_match )
377 {
378 symbolName.Printf( wxT( "%s-%s" ),
379 symbol_id.GetLibNickname().wx_str(),
380 symbol_id.GetLibItemName().wx_str() );
381 cache_match = findSymbol( symbolName, PROJECT_SCH::LegacySchLibs( aRescuer.GetPrj() ), true );
382 }
383
384 // Get the library symbol from the symbol library table.
385 lib_match = SchGetLibSymbol( symbol_id, PROJECT_SCH::SymbolLibAdapter( aRescuer.GetPrj() ) );
386
387 if( !cache_match && !lib_match )
388 continue;
389
390 std::shared_ptr<LIB_SYMBOL> lib_match_parent;
391
392 // If it's a derived symbol, use the parent symbol to perform the pin test.
393 if( lib_match && lib_match->IsDerived() )
394 {
395 lib_match_parent = lib_match->GetRootSymbol();
396
397 if( !lib_match_parent )
398 lib_match = nullptr;
399 else
400 lib_match = lib_match_parent.get();
401 }
402
403 // Test whether there is a conflict or if the symbol can only be found in the cache.
404 if( LIB_ID::HasIllegalChars( symbol_id.GetLibItemName() ) == -1 )
405 {
406 if( cache_match && lib_match
407 && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
408 {
409 continue;
410 }
411
412 if( !cache_match && lib_match )
413 continue;
414 }
415
416 // Fix illegal LIB_ID name characters.
417 wxString new_name = EscapeString( symbol_id.GetLibItemName(), CTX_LIBID );
418
419 // Differentiate symbol name in the rescue library by appending the original symbol
420 // library table nickname to the symbol name to prevent name clashes in the rescue
421 // library.
422 wxString libNickname = GetRescueLibraryFileName( aRescuer.Schematic() ).GetName();
423
424 LIB_ID new_id( libNickname, wxString::Format( wxT( "%s-%s" ),
425 new_name,
426 symbol_id.GetLibNickname().wx_str() ) );
427
428 RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( symbol_id, new_id, cache_match, lib_match,
429 eachSymbol->GetUnit(),
430 eachSymbol->GetBodyStyle() );
431
432 candidate_map[symbol_id] = candidate;
433 }
434 }
435
436 // Now, dump the map into aCandidates
437 for( const auto& [name, candidate] : candidate_map )
438 aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( candidate ) );
439}
440
441
443{
444 wxString action;
445
447 {
448 action.Printf( _( "Cannot rescue symbol %s which is not available in any library or the cache." ),
449 UnescapeString( m_requested_id.GetLibItemName().wx_str() ) );
450 }
452 {
453 action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
454 UnescapeString( m_requested_id.Format().wx_str() ),
455 UnescapeString( m_new_id.Format().wx_str() ) );
456 }
457 else
458 {
459 action.Printf( _( "Rescue modified symbol %s to %s" ),
460 UnescapeString( m_requested_id.Format().wx_str() ),
461 UnescapeString( m_new_id.Format().wx_str() ) );
462 }
463
464 return action;
465}
466
467
469{
471
472 wxCHECK_MSG( tmp, false, wxS( "Both cache and library symbols undefined." ) );
473
474 std::unique_ptr<LIB_SYMBOL> new_symbol = tmp->Flatten();
475 new_symbol->SetLibId( m_new_id );
476 new_symbol->SetName( m_new_id.GetLibItemName() );
477 aRescuer->AddSymbol( new_symbol.get() );
478
479 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
480 {
481 if( eachSymbol->GetLibId() != m_requested_id )
482 continue;
483
484 eachSymbol->SetLibId( m_new_id );
485 eachSymbol->ClearFlags();
486 aRescuer->LogRescue( eachSymbol, m_requested_id.Format(), m_new_id.Format() );
487 }
488
489 return true;
490}
491
492
493RESCUER::RESCUER( PROJECT& aProject, SCHEMATIC* aSchematic, SCH_SHEET_PATH* aCurrentSheet,
494 EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType )
495{
496 m_schematic = aSchematic ? aSchematic : aCurrentSheet->LastScreen()->Schematic();
497
498 wxASSERT( m_schematic );
499
500 if( m_schematic )
502
503 m_prj = &aProject;
504 m_currentSheet = aCurrentSheet;
505 m_galBackEndType = aGalBackEndType;
506}
507
508
509void RESCUER::LogRescue( SCH_SYMBOL* aSymbol, const wxString &aOldName, const wxString &aNewName )
510{
511 RESCUE_LOG logitem;
512 logitem.symbol = aSymbol;
513 logitem.old_name = aOldName;
514 logitem.new_name = aNewName;
515 m_rescue_log.push_back( logitem );
516}
517
518
520{
521 for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
522 {
523 if( ! each_candidate->PerformAction( this ) )
524 return false;
525 }
526
527 return true;
528}
529
530
532{
533 for( RESCUE_LOG& each_logitem : m_rescue_log )
534 {
535 LIB_ID libId;
536
537 libId.SetLibItemName( each_logitem.old_name );
538 each_logitem.symbol->SetLibId( libId );
539 each_logitem.symbol->ClearFlags();
540 }
541}
542
543
544bool RESCUER::RescueProject( wxWindow* aParent, RESCUER& aRescuer, bool aRunningOnDemand )
545{
546 aRescuer.FindCandidates();
547
548 if( !aRescuer.GetCandidateCount() )
549 {
550 if( aRunningOnDemand )
551 {
552 wxMessageDialog dlg( aParent, _( "This project has nothing to rescue." ),
553 _( "Project Rescue Helper" ) );
554 dlg.ShowModal();
555 }
556
557 return true;
558 }
559
560 aRescuer.RemoveDuplicates();
561 aRescuer.InvokeDialog( aParent, !aRunningOnDemand );
562
563 // If no symbols were rescued, let the user know what's going on. He might
564 // have clicked cancel by mistake, and should have some indication of that.
565 if( !aRescuer.GetChosenCandidateCount() )
566 {
567 wxMessageDialog dlg( aParent, _( "No symbols were rescued." ),
568 _( "Project Rescue Helper" ) );
569 dlg.ShowModal();
570
571 // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
572 // this point, due to the reloading of the symbols, so we'll make the save button active.
573 return true;
574 }
575
576 aRescuer.OpenRescueLibrary();
577
578 if( !aRescuer.DoRescues() )
579 {
580 aRescuer.UndoRescues();
581 return false;
582 }
583
584 aRescuer.WriteRescueLibrary( aParent );
585
586 return true;
587}
588
589
591{
592 std::vector<wxString> names_seen;
593
594 for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
595 it != m_all_candidates.end(); )
596 {
597 bool seen_already = false;
598
599 for( wxString& name_seen : names_seen )
600 {
601 if( name_seen == it->GetRequestedName() )
602 {
603 seen_already = true;
604 break;
605 }
606 }
607
608 if( seen_already )
609 {
610 it = m_all_candidates.erase( it );
611 }
612 else
613 {
614 names_seen.push_back( it->GetRequestedName() );
615 ++it;
616 }
617 }
618}
619
620
626
627
628void LEGACY_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
629{
630 InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
631 m_galBackEndType, aAskShowAgain );
632}
633
634
636{
637 wxFileName fn = GetRescueLibraryFileName( m_schematic );
638
639 std::unique_ptr<LEGACY_SYMBOL_LIB> rescue_lib =
640 std::make_unique<LEGACY_SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA, fn.GetFullPath() );
641
642 m_rescue_lib = std::move( rescue_lib );
643 m_rescue_lib->EnableBuffering();
644
645 // If a rescue library already exists copy the contents of that library so we do not
646 // lose any previous rescues.
647 LEGACY_SYMBOL_LIB* rescueLib = PROJECT_SCH::LegacySchLibs( m_prj )->FindLibrary( fn.GetName() );
648
649 if( rescueLib )
650 {
651 // For items in the rescue library, aliases are the root symbol.
652 std::vector< LIB_SYMBOL* > symbols;
653
654 rescueLib->GetSymbols( symbols );
655
656 for( LIB_SYMBOL* symbol : symbols )
657 {
658 // The LIB_SYMBOL copy constructor flattens derived symbols (formerly known as aliases).
659 m_rescue_lib->AddSymbol( new LIB_SYMBOL( *symbol, m_rescue_lib.get() ) );
660 }
661 }
662}
663
664
665bool LEGACY_RESCUER::WriteRescueLibrary( wxWindow *aParent )
666{
667 try
668 {
669 m_rescue_lib->Save( false );
670 }
671 catch( ... /* IO_ERROR ioe */ )
672 {
673 DisplayError( aParent, wxString::Format( _( "Failed to create symbol library file '%s'." ),
674 m_rescue_lib->GetFullFileName() ) );
675 return false;
676 }
677
678 wxArrayString libNames;
679 wxString libPaths;
680
681 wxString libName = m_rescue_lib->GetName();
683
684 if( !libs )
685 {
686 libs = new LEGACY_SYMBOL_LIBS();
688 }
689
690 try
691 {
692 LEGACY_SYMBOL_LIBS::GetLibNamesAndPaths( m_prj, &libPaths, &libNames );
693
694 // Make sure the library is not already in the list
695 while( libNames.Index( libName ) != wxNOT_FOUND )
696 libNames.Remove( libName );
697
698 // Add the library to the top of the list and save.
699 libNames.Insert( libName, 0 );
700 LEGACY_SYMBOL_LIBS::SetLibNamesAndPaths( m_prj, libPaths, libNames );
701 }
702 catch( const IO_ERROR& )
703 {
704 // Could not get or save the current libraries.
705 return false;
706 }
707
708 // Save the old libraries in case there is a problem after clear(). We'll
709 // put them back in.
710 boost::ptr_vector<LEGACY_SYMBOL_LIB> libsSave;
711 libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
712
713 m_prj->SetElem( PROJECT::ELEM::LEGACY_SYMBOL_LIBS, nullptr );
714
715 libs = new LEGACY_SYMBOL_LIBS();
716
717 try
718 {
719 libs->LoadAllLibraries( m_prj );
720 }
721 catch( const PARSE_ERROR& )
722 {
723 // Some libraries were not found. There's no point in showing the error,
724 // because it was already shown. Just don't do anything.
725 }
726 catch( const IO_ERROR& )
727 {
728 // Restore the old list
729 libs->clear();
730 libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
731 return false;
732 }
733
735
736 // Update the schematic symbol library links since the library list has changed.
737 SCH_SCREENS schematic( m_schematic->Root() );
738 schematic.UpdateSymbolLinks();
739 return true;
740}
741
742
744{
745 wxCHECK_RET( aNewSymbol, wxS( "Invalid LIB_SYMBOL pointer." ) );
746
747 aNewSymbol->SetLib( m_rescue_lib.get() );
748 m_rescue_lib->AddSymbol( aNewSymbol );
749}
750
751
753 SCH_SHEET_PATH* aCurrentSheet,
754 EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType ) :
755 RESCUER( aProject, aSchematic, aCurrentSheet, aGalBackEndType )
756{
757 m_properties = std::make_unique<std::map<std::string, UTF8>>();
758}
759
760
765
766
767void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
768{
769 InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
770 m_galBackEndType, aAskShowAgain );
771}
772
773
775{
776 (*m_properties)[ SCH_IO_KICAD_LEGACY::PropBuffering ] = "";
777
778 wxFileName fn = GetRescueLibraryFileName( m_schematic );
779
782
783 // If a rescue library already exists copy the contents of that library so we do not
784 // lose any previous rescues.
785 if( std::optional<const LIBRARY_TABLE_ROW*> optRow =
786 manager.GetRow( LIBRARY_TABLE_TYPE::SYMBOL, fn.GetName() ) )
787 {
788 const LIBRARY_TABLE_ROW* row = *optRow;
789
790 if( SCH_IO_MGR::EnumFromStr( row->Type() ) == SCH_IO_MGR::SCH_KICAD )
792
793 for( LIB_SYMBOL* symbol : adapter->GetSymbols( fn.GetName() ) )
794 m_rescueLibSymbols.emplace_back( std::make_unique<LIB_SYMBOL>( *symbol ) );
795 }
796}
797
798
800{
802
803 wxFileName fn = GetRescueLibraryFileName( m_schematic );
804
805 std::optional<const LIBRARY_TABLE_ROW*> optRow =
806 manager.GetRow( LIBRARY_TABLE_TYPE::SYMBOL, fn.GetName() );
807
809
810 try
811 {
812 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
813
814 for( const std::unique_ptr<LIB_SYMBOL>& symbol : m_rescueLibSymbols )
815 pi->SaveSymbol( fn.GetFullPath(), new LIB_SYMBOL( *symbol.get() ), m_properties.get() );
816
817 pi->SaveLibrary( fn.GetFullPath() );
818 }
819 catch( const IO_ERROR& ioe )
820 {
821 wxString msg;
822 msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
823 DisplayErrorMessage( aParent, msg, ioe.What() );
824 return false;
825 }
826
827 // If the rescue library already exists in the symbol library table no need save it to add
828 // it to the table.
829 if( !optRow || ( SCH_IO_MGR::EnumFromStr( ( *optRow )->Type() ) == SCH_IO_MGR::SCH_LEGACY ) )
830 {
831 wxString uri = wxS( "${KIPRJMOD}/" ) + fn.GetFullName();
832 wxString libNickname = fn.GetName();
833
834 std::optional<LIBRARY_TABLE*> optTable =
837 wxCHECK( optTable, false );
838 LIBRARY_TABLE* projectTable = *optTable;
839 LIBRARY_TABLE_ROW* row = nullptr;
840
841 if( std::optional<LIBRARY_TABLE_ROW*> oldRow = projectTable->Row( libNickname ); oldRow )
842 row = *oldRow;
843 else
844 row = &projectTable->InsertRow();
845
846 row->SetNickname( libNickname );
847 row->SetURI( uri );
848 row->SetType( wxT( "KiCad" ) );
849
850 bool success = true;
851
852 projectTable->Save().map_error(
853 [&success]( const LIBRARY_ERROR& aError )
854 {
855 success = false;
856 wxMessageBox( wxString::Format( _( "Error saving project-specific library table:\n\n%s" ),
857 aError.message ),
858 _( "File Save Error" ), wxOK | wxICON_ERROR );
859 } );
860
861 if( !success )
862 return false;
863 }
864
865 // Update the schematic symbol library links since the library list has changed.
866 SCH_SCREENS schematic( m_schematic->Root() );
867 schematic.UpdateSymbolLinks();
868 return true;
869}
870
871
873{
874 wxCHECK_RET( aNewSymbol, wxS( "Invalid LIB_SYMBOL pointer." ) );
875
876 m_rescueLibSymbols.emplace_back( std::make_unique<LIB_SYMBOL>( *aNewSymbol ) );
877}
const char * name
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
virtual bool WriteRescueLibrary(wxWindow *aParent) override
Write the rescue library.
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
virtual void AddSymbol(LIB_SYMBOL *aNewSymbol) override
std::unique_ptr< LEGACY_SYMBOL_LIB > m_rescue_lib
virtual void OpenRescueLibrary() override
A collection of #SYMBOL_LIB objects.
void FindLibraryNearEntries(std::vector< LIB_SYMBOL * > &aCandidates, const wxString &aEntryName, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a LIB_SYMBOL using a case insensitive comparison.
static void GetLibNamesAndPaths(PROJECT *aProject, wxString *aPaths, wxArrayString *aNames=nullptr)
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it.
static void SetLibNamesAndPaths(PROJECT *aProject, const wxString &aPaths, const wxArrayString &aNames)
LEGACY_SYMBOL_LIB * FindLibrary(const wxString &aName)
Find a symbol library by aName.
LIB_SYMBOL * FindLibSymbol(const LIB_ID &aLibId, const wxString &aLibraryName=wxEmptyString)
Search all libraries in the list for a symbol.
Object used to load, save, search, and otherwise manipulate symbol library files.
void GetSymbols(std::vector< LIB_SYMBOL * > &aSymbols) const
Load a vector with all the entries in this library.
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
std::optional< LIBRARY_TABLE_ROW * > GetRow(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
const wxString & Type() const
void SetURI(const wxString &aUri)
LIBRARY_RESULT< void > Save()
std::optional< LIBRARY_TABLE_ROW * > Row(const wxString &aNickname)
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:111
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:172
static int HasIllegalChars(const UTF8 &aLibItemName)
Examine aLibItemName for invalid LIB_ID item name characters.
Definition lib_id.cpp:176
UTF8 Format() const
Definition lib_id.cpp:119
const UTF8 & GetLibItemName() const
Definition lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:87
Define a library symbol object.
Definition lib_symbol.h:85
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:155
bool PinsConflictWith(const LIB_SYMBOL &aOtherSymbol, bool aTestNums, bool aTestNames, bool aTestType, bool aTestOrientation, bool aTestLength) const
Return true if this symbol's pins do not match another symbol's pins.
bool IsDerived() const
Definition lib_symbol.h:206
void SetLib(LEGACY_SYMBOL_LIB *aLibrary)
Definition lib_symbol.h:211
std::shared_ptr< LIB_SYMBOL > GetRootSymbol() const
Get the parent symbol that does not have another parent.
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:130
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static LEGACY_SYMBOL_LIBS * LegacySchLibs(PROJECT *aProject)
Returns the list of symbol libraries from a legacy (pre-5.x) design This is only used from the remapp...
Container for project specific data.
Definition project.h:66
@ LEGACY_SYMBOL_LIBS
Definition project.h:75
virtual void AddSymbol(LIB_SYMBOL *aNewSymbol)=0
virtual bool WriteRescueLibrary(wxWindow *aParent)=0
Write the rescue library.
std::vector< RESCUE_LOG > m_rescue_log
SCHEMATIC * m_schematic
PROJECT * m_prj
void UndoRescues()
Reverse the effects of all rescues on the project.
bool DoRescues()
Perform all chosen rescue actions, logging them to be undone if necessary.
std::vector< SCH_SYMBOL * > m_symbols
static bool RescueProject(wxWindow *aParent, RESCUER &aRescuer, bool aRunningOnDemand)
void LogRescue(SCH_SYMBOL *aSymbol, const wxString &aOldName, const wxString &aNewName)
Used by individual RESCUE_CANDIDATE objects to log a rescue for undoing.
SCH_SHEET_PATH * m_currentSheet
std::vector< RESCUE_CANDIDATE * > m_chosen_candidates
std::vector< SCH_SYMBOL * > * GetSymbols()
Get the list of symbols that need rescued.
size_t GetCandidateCount()
Return the number of rescue candidates found.
PROJECT * GetPrj()
Return the #SCH_PROJECT object for access to the symbol libraries.
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain)=0
Display a dialog to allow the user to select rescues.
SCHEMATIC * Schematic()
EDA_DRAW_PANEL_GAL::GAL_TYPE m_galBackEndType
RESCUER(PROJECT &aProject, SCHEMATIC *aSchematic, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackeEndType)
virtual void OpenRescueLibrary()=0
size_t GetChosenCandidateCount()
Get the number of rescue candidates chosen by the user.
boost::ptr_vector< RESCUE_CANDIDATE > m_all_candidates
virtual void FindCandidates()=0
Populate the RESCUER with all possible candidates.
void RemoveDuplicates()
Filter out duplicately named rescue candidates.
LIB_SYMBOL * m_cache_candidate
RESCUE_CACHE_CANDIDATE(const wxString &aRequestedName, const wxString &aNewName, LIB_SYMBOL *aCacheCandidate, LIB_SYMBOL *aLibCandidate, int aUnit=0, int aBodyStyle=0)
Create a RESCUE_CACHE_CANDIDATE.
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CACHE_CANDIDATE objects into a vector.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
RESCUE_CANDIDATE(const wxString &aRequestedName, const wxString &aNewName, LIB_SYMBOL *aLibCandidate, int aUnit, int aBodyStyle)
wxString m_requested_name
LIB_SYMBOL * m_lib_candidate
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CASE_CANDIDATE objects into a vector.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
RESCUE_CASE_CANDIDATE(const wxString &aRequestedName, const wxString &aNewName, LIB_SYMBOL *aLibCandidate, int aUnit=0, int aBodyStyle=0)
Create a RESCUE_CANDIDATE.
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
wxString old_name
wxString new_name
SCH_SYMBOL * symbol
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE(const LIB_ID &aRequestedId, const LIB_ID &aNewId, LIB_SYMBOL *aCacheCandidate, LIB_SYMBOL *aLibCandidate, int aUnit=0, int aBodyStyle=0)
Create RESCUE_CANDIDATE.
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_SYMBOL_LIB_TABLE_CANDIDATE objects into a vector.
Holds all the data relating to one schematic.
Definition schematic.h:88
wxString GetFileName() const
Helper to retrieve the filename from the root sheet screen.
SCH_SHEET & Root() const
Definition schematic.h:125
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
int GetUnit() const
Definition sch_item.h:238
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:728
SCH_SCREEN * GetNext()
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
SCH_SCREEN * GetFirst()
SCHEMATIC * Schematic() const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
Schematic symbol object.
Definition sch_symbol.h:76
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::vector< LIB_SYMBOL * > GetSymbols(const wxString &aNickname, SYMBOL_TYPE aType=SYMBOL_TYPE::ALL_SYMBOLS)
virtual void OpenRescueLibrary() override
virtual bool WriteRescueLibrary(wxWindow *aParent) override
Write the rescue library.
SYMBOL_LIB_TABLE_RESCUER(PROJECT &aProject, SCHEMATIC *aSchematic, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackeEndType)
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
std::unique_ptr< std::map< std::string, UTF8 > > m_properties
Library plugin properties.
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
virtual void AddSymbol(LIB_SYMBOL *aNewSymbol) override
std::vector< std::unique_ptr< LIB_SYMBOL > > m_rescueLibSymbols
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition utf8.h:72
wxString wx_str() const
Definition utf8.cpp:45
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
static bool sort_by_libid(const SYMBOL_CANDIDATE &candidate1, const SYMBOL_CANDIDATE &candidate2)
int InvokeDialogRescueEach(wxWindow *aParent, RESCUER &aRescuer, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType, bool aAskShowAgain)
This dialog asks the user which rescuable, cached parts he wants to rescue.
#define _(s)
static const std::string LegacySymbolLibFileExtension
static const std::string KiCadSymbolLibFileExtension
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
static bool sort_by_libid(const SCH_SYMBOL *ref, SCH_SYMBOL *cmp)
static LIB_SYMBOL * findSymbol(const wxString &aName, LEGACY_SYMBOL_LIBS *aLibs, bool aCached)
Search the libraries for the first symbol with a given name.
static void getSymbols(SCHEMATIC *aSchematic, std::vector< SCH_SYMBOL * > &aSymbols)
Fill a vector with all of the project's symbols, to ease iterating over them.
static wxFileName GetRescueLibraryFileName(SCHEMATIC *aSchematic)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition ptree.cpp:198
LIB_SYMBOL * SchGetLibSymbol(const LIB_ID &aLibId, SYMBOL_LIBRARY_ADAPTER *aLibMgr, LEGACY_SYMBOL_LIB *aCacheLib, wxWindow *aParent, bool aShowErrorMsg)
Load symbol from symbol library table.
wxString UnescapeString(const wxString &aSource)
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
wxString message
A filename or source description, a problem input line, a line number, a byte offset,...
@ SCH_SYMBOL_T
Definition typeinfo.h:176
Definition of file extensions used in Kicad.