KiCad PCB EDA Suite
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 (C) 2015-2022 KiCad Developers, see change_log.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>
26#include <symbol_library.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 <sch_symbol.h>
34#include <sch_sheet.h>
35#include <sch_edit_frame.h>
36#include <schematic.h>
37#include <string_utils.h>
38#include <symbol_lib_table.h>
40
41#include <cctype>
42#include <map>
43
44
45typedef std::pair<SCH_SYMBOL*, wxString> SYMBOL_NAME_PAIR;
46
47
48// Helper sort function, used in getSymbols, to sort a symbol list by lib_id
49static bool sort_by_libid( const SCH_SYMBOL* ref, SCH_SYMBOL* cmp )
50{
51 return ref->GetLibId() < cmp->GetLibId();
52}
53
54
64static void getSymbols( SCHEMATIC* aSchematic, std::vector<SCH_SYMBOL*>& aSymbols )
65{
66 SCH_SCREENS screens( aSchematic->Root() );
67
68 // Get the full list
69 for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
70 {
71 for( EDA_ITEM* aItem : screen->Items().OfType( SCH_SYMBOL_T ) )
72 aSymbols.push_back( static_cast<SCH_SYMBOL*>( aItem ) );
73 }
74
75 if( aSymbols.empty() )
76 return;
77
78 // sort aSymbols by lib symbol. symbols will be grouped by same lib symbol.
79 std::sort( aSymbols.begin(), aSymbols.end(), sort_by_libid );
80}
81
82
90static LIB_SYMBOL* findSymbol( const wxString& aName, SYMBOL_LIBS* aLibs, bool aCached )
91{
92 LIB_SYMBOL *symbol = nullptr;
93
94 for( SYMBOL_LIB& each_lib : *aLibs )
95 {
96 if( aCached && !each_lib.IsCache() )
97 continue;
98
99 if( !aCached && each_lib.IsCache() )
100 continue;
101
102 symbol = each_lib.FindSymbol( aName );
103
104 if( symbol )
105 break;
106 }
107
108 return symbol;
109}
110
111
112static wxFileName GetRescueLibraryFileName( SCHEMATIC* aSchematic )
113{
114 wxFileName fn = aSchematic->GetFileName();
115 fn.SetName( fn.GetName() + wxT( "-rescue" ) );
116 fn.SetExt( LegacySymbolLibFileExtension );
117 return fn;
118}
119
120
121RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName,
122 const wxString& aNewName,
123 LIB_SYMBOL* aLibCandidate,
124 int aUnit,
125 int aConvert )
126{
127 m_requested_name = aRequestedName;
128 m_new_name = aNewName;
129 m_lib_candidate = aLibCandidate;
130 m_unit = aUnit;
131 m_convert = aConvert;
132}
133
134
136 boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
137{
138 typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
139 candidate_map_t candidate_map;
140
141 // Remember the list of symbols is sorted by symbol name.
142 // So a search in libraries is made only once by group
143 LIB_SYMBOL* case_sensitive_match = nullptr;
144 std::vector<LIB_SYMBOL*> case_insensitive_matches;
145
146 wxString symbol_name;
147 wxString search_name;
148 wxString last_symbol_name;
149
150 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
151 {
152 symbol_name = eachSymbol->GetLibId().GetLibItemName();
153
154 if( last_symbol_name != symbol_name )
155 {
156 // A new symbol name is found (a new group starts here).
157 // Search the symbol names candidates only once for this group:
158 last_symbol_name = symbol_name;
159 case_insensitive_matches.clear();
160
161 LIB_ID id( wxEmptyString, symbol_name );
162
163 case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibSymbol( id );
164
165 if( case_sensitive_match )
166 continue;
167
168 // If the case sensitive match failed, try a case insensitive match.
169 aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
170 search_name );
171
172 // If there are not case insensitive matches either, the symbol cannot be rescued.
173 if( !case_insensitive_matches.size() )
174 continue;
175
176 RESCUE_CASE_CANDIDATE candidate( symbol_name, case_insensitive_matches[0]->GetName(),
177 case_insensitive_matches[0],
178 eachSymbol->GetUnit(),
179 eachSymbol->GetConvert() );
180
181 candidate_map[symbol_name] = candidate;
182 }
183 }
184
185 // Now, dump the map into aCandidates
186 for( const candidate_map_t::value_type& each_pair : candidate_map )
187 {
188 aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
189 }
190}
191
192
194{
195 wxString action;
196 action.Printf( _( "Rename %s to %s" ), m_requested_name, m_new_name );
197 return action;
198}
199
200
202{
203 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
204 {
205 if( eachSymbol->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
206 continue;
207
208 LIB_ID libId;
209
210 libId.SetLibItemName( m_new_name );
211 eachSymbol->SetLibId( libId );
212 eachSymbol->ClearFlags();
213 aRescuer->LogRescue( eachSymbol, m_requested_name, m_new_name );
214 }
215
216 return true;
217}
218
219
221 const wxString& aNewName,
222 LIB_SYMBOL* aCacheCandidate,
223 LIB_SYMBOL* aLibCandidate,
224 int aUnit,
225 int aConvert )
226{
227 m_requested_name = aRequestedName;
228 m_new_name = aNewName;
229 m_cache_candidate = aCacheCandidate;
230 m_lib_candidate = aLibCandidate;
231 m_unit = aUnit;
232 m_convert = aConvert;
233}
234
235
237{
238 m_cache_candidate = nullptr;
239 m_lib_candidate = nullptr;
240}
241
242
244 boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
245{
246 typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
247 candidate_map_t candidate_map;
248
249 // Remember the list of symbols is sorted by symbol name.
250 // So a search in libraries is made only once by group
251 LIB_SYMBOL* cache_match = nullptr;
252 LIB_SYMBOL* lib_match = nullptr;
253 wxString symbol_name;
254 wxString old_symbol_name;
255
256 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
257 {
258 symbol_name = eachSymbol->GetLibId().GetUniStringLibItemName();
259
260 if( old_symbol_name != symbol_name )
261 {
262 // A new symbol name is found (a new group starts here).
263 // Search the symbol names candidates only once for this group:
264 old_symbol_name = symbol_name;
265 cache_match = findSymbol( symbol_name, aRescuer.GetPrj()->SchLibs(), true );
266 lib_match = findSymbol( symbol_name, aRescuer.GetPrj()->SchLibs(), false );
267
268 // At some point during V5 development, the LIB_ID delimiter character ':' was
269 // replaced by '_' when writing the symbol cache library so we have to test for
270 // the LIB_NICKNAME_LIB_SYMBOL_NAME case.
271 if( !cache_match && eachSymbol->GetLibId().IsValid() )
272 {
273 wxString tmp;
274
275 tmp = eachSymbol->GetLibId().GetLibNickname().wx_str() + wxT( "_" ) +
276 eachSymbol->GetLibId().GetLibItemName().wx_str();
277 cache_match = findSymbol( tmp, aRescuer.GetPrj()->SchLibs(), true );
278 }
279
280 // Test whether there is a conflict or if the symbol can only be found in the cache
281 // and the symbol name does not have any illegal characters.
282 if( cache_match && lib_match &&
283 !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
284 continue;
285
286 if( !cache_match && lib_match )
287 continue;
288
289 // Check if the symbol has already been rescued.
290 RESCUE_CACHE_CANDIDATE candidate( symbol_name, symbol_name, cache_match, lib_match,
291 eachSymbol->GetUnit(),
292 eachSymbol->GetConvert() );
293
294 candidate_map[symbol_name] = candidate;
295 }
296 }
297
298 // Now, dump the map into aCandidates
299 for( const candidate_map_t::value_type& each_pair : candidate_map )
300 {
301 aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
302 }
303}
304
305
307{
308 wxString action;
309
311 action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
312 "the cache." ), m_requested_name );
314 action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
316 else
317 action.Printf( _( "Rescue modified symbol %s to %s" ),
319
320 return action;
321}
322
323
325{
327
328 wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
329
330 std::unique_ptr<LIB_SYMBOL> new_symbol = tmp->Flatten();
331 new_symbol->SetName( m_new_name );
332 aRescuer->AddSymbol( new_symbol.get() );
333
334 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
335 {
336 if( eachSymbol->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
337 continue;
338
339 LIB_ID libId;
340
341 libId.SetLibItemName( m_new_name );
342 eachSymbol->SetLibId( libId );
343 eachSymbol->ClearFlags();
344 aRescuer->LogRescue( eachSymbol, m_requested_name, m_new_name );
345 }
346
347 return true;
348}
349
350
352 const LIB_ID& aRequestedId,
353 const LIB_ID& aNewId,
354 LIB_SYMBOL* aCacheCandidate,
355 LIB_SYMBOL* aLibCandidate,
356 int aUnit,
357 int aConvert ) : RESCUE_CANDIDATE()
358{
359 m_requested_id = aRequestedId;
360 m_requested_name = aRequestedId.Format();
361 m_new_id = aNewId;
362 m_lib_candidate = aLibCandidate;
363 m_cache_candidate = aCacheCandidate;
364 m_unit = aUnit;
365 m_convert = aConvert;
366}
367
368
370{
371 m_cache_candidate = nullptr;
372 m_lib_candidate = nullptr;
373}
374
375
377 RESCUER& aRescuer,
378 boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
379{
380 typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
381
382 candidate_map_t candidate_map;
383
384 // Remember the list of symbols is sorted by LIB_ID.
385 // So a search in libraries is made only once by group
386 LIB_SYMBOL* cache_match = nullptr;
387 LIB_SYMBOL* lib_match = nullptr;
388 LIB_ID old_symbol_id;
389
390 wxString symbolName;
391
392 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
393 {
394 const LIB_ID& symbol_id = eachSymbol->GetLibId();
395
396 if( old_symbol_id != symbol_id )
397 {
398 // A new symbol name is found (a new group starts here).
399 // Search the symbol names candidates only once for this group:
400 old_symbol_id = symbol_id;
401
402 symbolName = symbol_id.Format().wx_str();
403
404 // Get the library symbol from the cache library. It will be a flattened
405 // symbol by default (no inheritance).
406 cache_match = findSymbol( symbolName, aRescuer.GetPrj()->SchLibs(), true );
407
408 // At some point during V5 development, the LIB_ID delimiter character ':' was
409 // replaced by '_' when writing the symbol cache library so we have to test for
410 // the LIB_NICKNAME_LIB_SYMBOL_NAME case.
411 if( !cache_match )
412 {
413 symbolName = symbol_id.GetLibNickname().wx_str() + wxT( "_" ) +
414 symbol_id.GetLibItemName().wx_str();
415 cache_match = findSymbol( symbolName, aRescuer.GetPrj()->SchLibs(), true );
416 }
417
418 // Get the library symbol from the symbol library table.
419 lib_match = SchGetLibSymbol( symbol_id, aRescuer.GetPrj()->SchSymbolLibTable() );
420
421 if( !cache_match && !lib_match )
422 continue;
423
424 LIB_SYMBOL_SPTR lib_match_parent;
425
426 // If it's a derive symbol, use the parent symbol to perform the pin test.
427 if( lib_match && lib_match->IsAlias() )
428 {
429 lib_match_parent = lib_match->GetParent().lock();
430
431 if( !lib_match_parent )
432 lib_match = nullptr;
433 else
434 lib_match = lib_match_parent.get();
435 }
436
437 // Test whether there is a conflict or if the symbol can only be found in the cache.
438 if( LIB_ID::HasIllegalChars( symbol_id.GetLibItemName() ) == -1 )
439 {
440 if( cache_match && lib_match &&
441 !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
442 {
443 continue;
444 }
445
446 if( !cache_match && lib_match )
447 continue;
448 }
449
450 // Fix illegal LIB_ID name characters.
451 wxString new_name = EscapeString( symbol_id.GetLibItemName(), CTX_LIBID );
452
453 // Differentiate symbol name in the rescue library by appending the original symbol
454 // library table nickname to the symbol name to prevent name clashes in the rescue
455 // library.
456 wxString libNickname = GetRescueLibraryFileName( aRescuer.Schematic() ).GetName();
457
458 LIB_ID new_id( libNickname, new_name + "-" + symbol_id.GetLibNickname().wx_str() );
459
460 RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( symbol_id, new_id, cache_match, lib_match,
461 eachSymbol->GetUnit(),
462 eachSymbol->GetConvert() );
463
464 candidate_map[symbol_id] = candidate;
465 }
466 }
467
468 // Now, dump the map into aCandidates
469 for( const candidate_map_t::value_type& each_pair : candidate_map )
470 {
471 aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
472 }
473}
474
475
477{
478 wxString action;
479
481 {
482 action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
483 "the cache." ),
485 }
487 {
488 action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
491 }
492 else
493 {
494 action.Printf( _( "Rescue modified symbol %s to %s" ),
497 }
498
499 return action;
500}
501
502
504{
506
507 wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
508
509 std::unique_ptr<LIB_SYMBOL> new_symbol = tmp->Flatten();
510 new_symbol->SetLibId( m_new_id );
511 new_symbol->SetName( m_new_id.GetLibItemName() );
512 aRescuer->AddSymbol( new_symbol.get() );
513
514 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
515 {
516 if( eachSymbol->GetLibId() != m_requested_id )
517 continue;
518
519 eachSymbol->SetLibId( m_new_id );
520 eachSymbol->ClearFlags();
521 aRescuer->LogRescue( eachSymbol, m_requested_id.Format(), m_new_id.Format() );
522 }
523
524 return true;
525}
526
527
528RESCUER::RESCUER( PROJECT& aProject, SCHEMATIC* aSchematic, SCH_SHEET_PATH* aCurrentSheet,
529 EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType )
530{
531 m_schematic = aSchematic ? aSchematic : aCurrentSheet->LastScreen()->Schematic();
532
533 wxASSERT( m_schematic );
534
535 if( m_schematic )
537
538 m_prj = &aProject;
539 m_currentSheet = aCurrentSheet;
540 m_galBackEndType = aGalBackEndType;
541}
542
543
544void RESCUER::LogRescue( SCH_SYMBOL* aSymbol, const wxString &aOldName,
545 const wxString &aNewName )
546{
547 RESCUE_LOG logitem;
548 logitem.symbol = aSymbol;
549 logitem.old_name = aOldName;
550 logitem.new_name = aNewName;
551 m_rescue_log.push_back( logitem );
552}
553
554
556{
557 for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
558 {
559 if( ! each_candidate->PerformAction( this ) )
560 return false;
561 }
562
563 return true;
564}
565
566
568{
569 for( RESCUE_LOG& each_logitem : m_rescue_log )
570 {
571 LIB_ID libId;
572
573 libId.SetLibItemName( each_logitem.old_name );
574 each_logitem.symbol->SetLibId( libId );
575 each_logitem.symbol->ClearFlags();
576 }
577}
578
579
580bool RESCUER::RescueProject( wxWindow* aParent, RESCUER& aRescuer, bool aRunningOnDemand )
581{
582 aRescuer.FindCandidates();
583
584 if( !aRescuer.GetCandidateCount() )
585 {
586 if( aRunningOnDemand )
587 {
588 wxMessageDialog dlg( aParent, _( "This project has nothing to rescue." ),
589 _( "Project Rescue Helper" ) );
590 dlg.ShowModal();
591 }
592
593 return true;
594 }
595
596 aRescuer.RemoveDuplicates();
597 aRescuer.InvokeDialog( aParent, !aRunningOnDemand );
598
599 // If no symbols were rescued, let the user know what's going on. He might
600 // have clicked cancel by mistake, and should have some indication of that.
601 if( !aRescuer.GetChosenCandidateCount() )
602 {
603 wxMessageDialog dlg( aParent, _( "No symbols were rescued." ),
604 _( "Project Rescue Helper" ) );
605 dlg.ShowModal();
606
607 // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
608 // this point, due to the reloading of the symbols, so we'll make the save button active.
609 return true;
610 }
611
612 aRescuer.OpenRescueLibrary();
613
614 if( !aRescuer.DoRescues() )
615 {
616 aRescuer.UndoRescues();
617 return false;
618 }
619
620 aRescuer.WriteRescueLibrary( aParent );
621
622 return true;
623}
624
625
627{
628 std::vector<wxString> names_seen;
629
630 for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
631 it != m_all_candidates.end(); )
632 {
633 bool seen_already = false;
634
635 for( wxString& name_seen : names_seen )
636 {
637 if( name_seen == it->GetRequestedName() )
638 {
639 seen_already = true;
640 break;
641 }
642 }
643
644 if( seen_already )
645 {
646 it = m_all_candidates.erase( it );
647 }
648 else
649 {
650 names_seen.push_back( it->GetRequestedName() );
651 ++it;
652 }
653 }
654}
655
656
658{
661}
662
663
664void LEGACY_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
665{
666 InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
667 m_galBackEndType, aAskShowAgain );
668}
669
670
672{
673 wxFileName fn = GetRescueLibraryFileName( m_schematic );
674
675 std::unique_ptr<SYMBOL_LIB> rescue_lib = std::make_unique<SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
676 fn.GetFullPath() );
677
678 m_rescue_lib = std::move( rescue_lib );
679 m_rescue_lib->EnableBuffering();
680
681 // If a rescue library already exists copy the contents of that library so we do not
682 // lose any previous rescues.
683 SYMBOL_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
684
685 if( rescueLib )
686 {
687 // For items in the rescue library, aliases are the root symbol.
688 std::vector< LIB_SYMBOL* > symbols;
689
690 rescueLib->GetSymbols( symbols );
691
692 for( LIB_SYMBOL* symbol : symbols )
693 {
694 // The LIB_SYMBOL copy constructor flattens derived symbols (formerly known as aliases).
695 m_rescue_lib->AddSymbol( new LIB_SYMBOL( *symbol, m_rescue_lib.get() ) );
696 }
697 }
698}
699
700
701bool LEGACY_RESCUER::WriteRescueLibrary( wxWindow *aParent )
702{
703 try
704 {
705 m_rescue_lib->Save( false );
706 }
707 catch( ... /* IO_ERROR ioe */ )
708 {
709 wxString msg;
710
711 msg.Printf( _( "Failed to create symbol library file '%s'." ),
712 m_rescue_lib->GetFullFileName() );
713 DisplayError( aParent, msg );
714 return false;
715 }
716
717 wxArrayString libNames;
718 wxString libPaths;
719
720 wxString libName = m_rescue_lib->GetName();
722
723 if( !libs )
724 {
725 libs = new SYMBOL_LIBS();
727 }
728
729 try
730 {
731 SYMBOL_LIBS::GetLibNamesAndPaths( m_prj, &libPaths, &libNames );
732
733 // Make sure the library is not already in the list
734 while( libNames.Index( libName ) != wxNOT_FOUND )
735 libNames.Remove( libName );
736
737 // Add the library to the top of the list and save.
738 libNames.Insert( libName, 0 );
739 SYMBOL_LIBS::SetLibNamesAndPaths( m_prj, libPaths, libNames );
740 }
741 catch( const IO_ERROR& )
742 {
743 // Could not get or save the current libraries.
744 return false;
745 }
746
747 // Save the old libraries in case there is a problem after clear(). We'll
748 // put them back in.
749 boost::ptr_vector<SYMBOL_LIB> libsSave;
750 libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
751
753
754 libs = new SYMBOL_LIBS();
755
756 try
757 {
758 libs->LoadAllLibraries( m_prj );
759 }
760 catch( const PARSE_ERROR& )
761 {
762 // Some libraries were not found. There's no point in showing the error,
763 // because it was already shown. Just don't do anything.
764 }
765 catch( const IO_ERROR& )
766 {
767 // Restore the old list
768 libs->clear();
769 libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
770 return false;
771 }
772
774
775 // Update the schematic symbol library links since the library list has changed.
776 SCH_SCREENS schematic( m_schematic->Root() );
777 schematic.UpdateSymbolLinks();
778 return true;
779}
780
781
783{
784 wxCHECK_RET( aNewSymbol, "Invalid LIB_SYMBOL pointer." );
785
786 aNewSymbol->SetLib( m_rescue_lib.get() );
787 m_rescue_lib->AddSymbol( aNewSymbol );
788}
789
790
792 SCH_SHEET_PATH* aCurrentSheet,
793 EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType ) :
794 RESCUER( aProject, aSchematic, aCurrentSheet, aGalBackEndType )
795{
796 m_properties = std::make_unique<STRING_UTF8_MAP>();
797}
798
799
801{
803}
804
805
806void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
807{
808 InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
809 m_galBackEndType, aAskShowAgain );
810}
811
812
814{
815 (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
816
817 wxFileName fn = GetRescueLibraryFileName( m_schematic );
818
819 SYMBOL_LIB_TABLE_ROW* row = m_prj->SchSymbolLibTable()->FindRow( fn.GetName() );
820
821 // If a rescue library already exists copy the contents of that library so we do not
822 // lose any previous rescues.
823 if( row )
824 {
825 if( SCH_IO_MGR::EnumFromStr( row->GetType() ) == SCH_IO_MGR::SCH_KICAD )
826 fn.SetExt( KiCadSymbolLibFileExtension );
827
828 std::vector<LIB_SYMBOL*> symbols;
829
830 try
831 {
832 m_prj->SchSymbolLibTable()->LoadSymbolLib( symbols, fn.GetName() );
833 }
834 catch( ... /* IO_ERROR */ )
835 {
836 return;
837 }
838
839 for( LIB_SYMBOL* symbol : symbols )
840 m_rescueLibSymbols.emplace_back( std::make_unique<LIB_SYMBOL>( *symbol ) );
841 }
842}
843
844
846{
847 wxString msg;
848 wxFileName fn = GetRescueLibraryFileName( m_schematic );
849 SYMBOL_LIB_TABLE_ROW* row = m_prj->SchSymbolLibTable()->FindRow( fn.GetName() );
850
851 fn.SetExt( KiCadSymbolLibFileExtension );
852
853 try
854 {
855 SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
856
857 for( const std::unique_ptr<LIB_SYMBOL>& symbol : m_rescueLibSymbols )
858 pi->SaveSymbol( fn.GetFullPath(), new LIB_SYMBOL( *symbol.get() ), m_properties.get() );
859
860 pi->SaveLibrary( fn.GetFullPath() );
861 }
862 catch( const IO_ERROR& ioe )
863 {
864 msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
865 DisplayErrorMessage( aParent, msg, ioe.What() );
866 return false;
867 }
868
869 // If the rescue library already exists in the symbol library table no need save it to add
870 // it to the table.
871 if( !row || ( SCH_IO_MGR::EnumFromStr( row->GetType() ) == SCH_IO_MGR::SCH_LEGACY ) )
872 {
873 wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
874 wxString libNickname = fn.GetName();
875
876 row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri, wxT( "KiCad" ) );
877 m_prj->SchSymbolLibTable()->InsertRow( row, true );
878
880
881 try
882 {
883 m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
884 }
885 catch( const IO_ERROR& ioe )
886 {
887 msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
888 DisplayErrorMessage( aParent, msg, ioe.What() );
889 return false;
890 }
891 }
892
894
895 // This can only happen if the symbol library table file was corrupted on write.
896 if( !m_prj->SchSymbolLibTable() )
897 return false;
898
899 // Update the schematic symbol library links since the library list has changed.
900 SCH_SCREENS schematic( m_schematic->Root() );
901 schematic.UpdateSymbolLinks();
902 return true;
903}
904
905
907{
908 wxCHECK_RET( aNewSymbol, "Invalid LIB_SYMBOL pointer." );
909
910 m_rescueLibSymbols.emplace_back( std::make_unique<LIB_SYMBOL>( *aNewSymbol ) );
911}
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
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< SYMBOL_LIB > m_rescue_lib
virtual void OpenRescueLibrary() override
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:109
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:165
static int HasIllegalChars(const UTF8 &aLibItemName)
Examine aLibItemName for invalid LIB_ID item name characters.
Definition: lib_id.cpp:174
UTF8 Format() const
Definition: lib_id.cpp:117
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition: lib_id.h:111
const UTF8 & GetLibItemName() const
Definition: lib_id.h:101
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:98
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.
Definition: lib_symbol.cpp:901
bool IsAlias() const
Definition: lib_symbol.h:183
LIB_ID GetLibId() const override
Definition: lib_symbol.h:139
void SetLib(SYMBOL_LIB *aLibrary)
Definition: lib_symbol.h:188
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:460
LIB_SYMBOL_REF & GetParent()
Definition: lib_symbol.h:125
Container for project specific data.
Definition: project.h:63
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:126
virtual _ELEM * GetElem(ELEM_T aIndex)
Get and set the elements for this project.
Definition: project.cpp:284
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:294
@ ELEM_SYMBOL_LIB_TABLE
Definition: project.h:210
@ ELEM_SCH_SYMBOL_LIBS
Definition: project.h:207
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
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.
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.
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.
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:61
wxString GetFileName() const override
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:166
SCH_SHEET & Root() const
Definition: schematic.h:91
static SCH_FILE_T EnumFromStr(const wxString &aFileType)
Return the #SCH_FILE_T from the corresponding plugin type name: "kicad", "legacy",...
Definition: sch_io_mgr.cpp:101
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:535
virtual void SaveSymbol(const wxString &aLibraryPath, const LIB_SYMBOL *aSymbol, const STRING_UTF8_MAP *aProperties=nullptr)
Write aSymbol to an existing library located at aLibraryPath.
Definition: sch_plugin.cpp:94
virtual void SaveLibrary(const wxString &aFileName, const STRING_UTF8_MAP *aProperties=nullptr)
Definition: sch_plugin.cpp:45
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:608
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
Definition: sch_screen.cpp:88
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:80
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:172
A collection of SYMBOL_LIB objects.
static void SetLibNamesAndPaths(PROJECT *aProject, const wxString &aPaths, const wxArrayString &aNames)
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 GetLibNamesAndPaths(PROJECT *aProject, wxString *aPaths, wxArrayString *aNames=nullptr)
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.
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
virtual void AddSymbol(LIB_SYMBOL *aNewSymbol) override
std::unique_ptr< STRING_UTF8_MAP > m_properties
Library plugin properties.
std::vector< std::unique_ptr< LIB_SYMBOL > > m_rescueLibSymbols
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
const wxString GetType() const override
Return the type of symbol library table represented by this row.
static const wxString & GetSymbolLibTableFileName()
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.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:71
void clear()
Definition: utf8.h:108
wxString wx_str() const
Definition: utf8.cpp:46
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:280
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:299
This file is part of the common library.
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)
const std::string KiCadSymbolLibFileExtension
const std::string LegacySymbolLibFileExtension
std::shared_ptr< LIB_SYMBOL > LIB_SYMBOL_SPTR
shared pointer to LIB_SYMBOL
Definition: lib_symbol.h:44
static bool sort_by_libid(const SCH_SYMBOL *ref, SCH_SYMBOL *cmp)
static LIB_SYMBOL * findSymbol(const wxString &aName, 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)
std::pair< SCH_SYMBOL *, wxString > SYMBOL_NAME_PAIR
LIB_SYMBOL * SchGetLibSymbol(const LIB_ID &aLibId, SYMBOL_LIB_TABLE *aLibTable, 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
Definition: string_utils.h:55
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:119
Definition for symbol library class.
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
Definition of file extensions used in Kicad.