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-2023 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 last_symbol_name;
148
149 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
150 {
151 symbol_name = eachSymbol->GetLibId().GetLibItemName();
152
153 if( last_symbol_name != symbol_name )
154 {
155 // A new symbol name is found (a new group starts here).
156 // Search the symbol names candidates only once for this group:
157 last_symbol_name = symbol_name;
158 case_insensitive_matches.clear();
159
160 LIB_ID id( wxEmptyString, symbol_name );
161
162 case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibSymbol( id );
163
164 if( case_sensitive_match )
165 continue;
166
167 // If the case sensitive match failed, try a case insensitive match.
168 aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
169 symbol_name );
170
171 // If there are not case insensitive matches either, the symbol cannot be rescued.
172 if( !case_insensitive_matches.size() )
173 continue;
174
175 RESCUE_CASE_CANDIDATE candidate( symbol_name, case_insensitive_matches[0]->GetName(),
176 case_insensitive_matches[0],
177 eachSymbol->GetUnit(),
178 eachSymbol->GetConvert() );
179
180 candidate_map[symbol_name] = candidate;
181 }
182 }
183
184 // Now, dump the map into aCandidates
185 for( const candidate_map_t::value_type& each_pair : candidate_map )
186 {
187 aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
188 }
189}
190
191
193{
194 wxString action;
195 action.Printf( _( "Rename %s to %s" ), m_requested_name, m_new_name );
196 return action;
197}
198
199
201{
202 wxCHECK( m_lib_candidate, true );
203
204 std::unique_ptr<LIB_SYMBOL> new_symbol = m_lib_candidate->Flatten();
205 new_symbol->SetName( m_new_name );
206 aRescuer->AddSymbol( new_symbol.get() );
207
208 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
209 {
210 if( eachSymbol->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
211 continue;
212
213 LIB_ID libId;
214
215 libId.SetLibItemName( m_new_name );
216 eachSymbol->SetLibId( libId );
217 eachSymbol->ClearFlags();
218 aRescuer->LogRescue( eachSymbol, m_requested_name, m_new_name );
219 }
220
221 return true;
222}
223
224
226 const wxString& aNewName,
227 LIB_SYMBOL* aCacheCandidate,
228 LIB_SYMBOL* aLibCandidate,
229 int aUnit,
230 int aConvert )
231{
232 m_requested_name = aRequestedName;
233 m_new_name = aNewName;
234 m_cache_candidate = aCacheCandidate;
235 m_lib_candidate = aLibCandidate;
236 m_unit = aUnit;
237 m_convert = aConvert;
238}
239
240
242{
243 m_cache_candidate = nullptr;
244 m_lib_candidate = nullptr;
245}
246
247
249 boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
250{
251 typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
252 candidate_map_t candidate_map;
253
254 // Remember the list of symbols is sorted by symbol name.
255 // So a search in libraries is made only once by group
256 LIB_SYMBOL* cache_match = nullptr;
257 LIB_SYMBOL* lib_match = nullptr;
258 wxString symbol_name;
259 wxString old_symbol_name;
260
261 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
262 {
263 symbol_name = eachSymbol->GetLibId().GetUniStringLibItemName();
264
265 if( old_symbol_name != symbol_name )
266 {
267 // A new symbol name is found (a new group starts here).
268 // Search the symbol names candidates only once for this group:
269 old_symbol_name = symbol_name;
270 cache_match = findSymbol( symbol_name, aRescuer.GetPrj()->SchLibs(), true );
271 lib_match = findSymbol( symbol_name, aRescuer.GetPrj()->SchLibs(), false );
272
273 // At some point during V5 development, the LIB_ID delimiter character ':' was
274 // replaced by '_' when writing the symbol cache library so we have to test for
275 // the LIB_NICKNAME_LIB_SYMBOL_NAME case.
276 if( !cache_match && eachSymbol->GetLibId().IsValid() )
277 {
278 wxString tmp;
279
280 tmp = eachSymbol->GetLibId().GetLibNickname().wx_str() + wxT( "_" ) +
281 eachSymbol->GetLibId().GetLibItemName().wx_str();
282 cache_match = findSymbol( tmp, aRescuer.GetPrj()->SchLibs(), true );
283 }
284
285 // Test whether there is a conflict or if the symbol can only be found in the cache
286 // and the symbol name does not have any illegal characters.
287 if( cache_match && lib_match &&
288 !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
289 continue;
290
291 if( !cache_match && lib_match )
292 continue;
293
294 // Check if the symbol has already been rescued.
295 RESCUE_CACHE_CANDIDATE candidate( symbol_name, symbol_name, cache_match, lib_match,
296 eachSymbol->GetUnit(),
297 eachSymbol->GetConvert() );
298
299 candidate_map[symbol_name] = candidate;
300 }
301 }
302
303 // Now, dump the map into aCandidates
304 for( const candidate_map_t::value_type& each_pair : candidate_map )
305 {
306 aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
307 }
308}
309
310
312{
313 wxString action;
314
316 action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
317 "the cache." ), m_requested_name );
319 action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
321 else
322 action.Printf( _( "Rescue modified symbol %s to %s" ),
324
325 return action;
326}
327
328
330{
332
333 // A symbol that cannot be rescued is a valid condition so just bail out here.
334 if( !tmp )
335 return true;
336
337 std::unique_ptr<LIB_SYMBOL> new_symbol = tmp->Flatten();
338 new_symbol->SetName( m_new_name );
339 aRescuer->AddSymbol( new_symbol.get() );
340
341 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
342 {
343 if( eachSymbol->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
344 continue;
345
346 LIB_ID libId;
347
348 libId.SetLibItemName( m_new_name );
349 eachSymbol->SetLibId( libId );
350 eachSymbol->ClearFlags();
351 aRescuer->LogRescue( eachSymbol, m_requested_name, m_new_name );
352 }
353
354 return true;
355}
356
357
359 const LIB_ID& aRequestedId,
360 const LIB_ID& aNewId,
361 LIB_SYMBOL* aCacheCandidate,
362 LIB_SYMBOL* aLibCandidate,
363 int aUnit,
364 int aConvert ) : RESCUE_CANDIDATE()
365{
366 m_requested_id = aRequestedId;
367 m_requested_name = aRequestedId.Format();
368 m_new_id = aNewId;
369 m_lib_candidate = aLibCandidate;
370 m_cache_candidate = aCacheCandidate;
371 m_unit = aUnit;
372 m_convert = aConvert;
373}
374
375
377{
378 m_cache_candidate = nullptr;
379 m_lib_candidate = nullptr;
380}
381
382
384 RESCUER& aRescuer,
385 boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
386{
387 typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
388
389 candidate_map_t candidate_map;
390
391 // Remember the list of symbols is sorted by LIB_ID.
392 // So a search in libraries is made only once by group
393 LIB_SYMBOL* cache_match = nullptr;
394 LIB_SYMBOL* lib_match = nullptr;
395 LIB_ID old_symbol_id;
396
397 wxString symbolName;
398
399 for( SCH_SYMBOL* eachSymbol : *( aRescuer.GetSymbols() ) )
400 {
401 const LIB_ID& symbol_id = eachSymbol->GetLibId();
402
403 if( old_symbol_id != symbol_id )
404 {
405 // A new symbol name is found (a new group starts here).
406 // Search the symbol names candidates only once for this group:
407 old_symbol_id = symbol_id;
408
409 symbolName = symbol_id.Format().wx_str();
410
411 // Get the library symbol from the cache library. It will be a flattened
412 // symbol by default (no inheritance).
413 cache_match = findSymbol( symbolName, aRescuer.GetPrj()->SchLibs(), true );
414
415 // At some point during V5 development, the LIB_ID delimiter character ':' was
416 // replaced by '_' when writing the symbol cache library so we have to test for
417 // the LIB_NICKNAME_LIB_SYMBOL_NAME case.
418 if( !cache_match )
419 {
420 symbolName = symbol_id.GetLibNickname().wx_str() + wxT( "_" ) +
421 symbol_id.GetLibItemName().wx_str();
422 cache_match = findSymbol( symbolName, aRescuer.GetPrj()->SchLibs(), true );
423 }
424
425 // Get the library symbol from the symbol library table.
426 lib_match = SchGetLibSymbol( symbol_id, aRescuer.GetPrj()->SchSymbolLibTable() );
427
428 if( !cache_match && !lib_match )
429 continue;
430
431 LIB_SYMBOL_SPTR lib_match_parent;
432
433 // If it's a derive symbol, use the parent symbol to perform the pin test.
434 if( lib_match && lib_match->IsAlias() )
435 {
436 lib_match_parent = lib_match->GetParent().lock();
437
438 if( !lib_match_parent )
439 lib_match = nullptr;
440 else
441 lib_match = lib_match_parent.get();
442 }
443
444 // Test whether there is a conflict or if the symbol can only be found in the cache.
445 if( LIB_ID::HasIllegalChars( symbol_id.GetLibItemName() ) == -1 )
446 {
447 if( cache_match && lib_match &&
448 !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
449 {
450 continue;
451 }
452
453 if( !cache_match && lib_match )
454 continue;
455 }
456
457 // Fix illegal LIB_ID name characters.
458 wxString new_name = EscapeString( symbol_id.GetLibItemName(), CTX_LIBID );
459
460 // Differentiate symbol name in the rescue library by appending the original symbol
461 // library table nickname to the symbol name to prevent name clashes in the rescue
462 // library.
463 wxString libNickname = GetRescueLibraryFileName( aRescuer.Schematic() ).GetName();
464
465 LIB_ID new_id( libNickname, new_name + wxS( "-" ) + symbol_id.GetLibNickname().wx_str() );
466
467 RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( symbol_id, new_id, cache_match, lib_match,
468 eachSymbol->GetUnit(),
469 eachSymbol->GetConvert() );
470
471 candidate_map[symbol_id] = candidate;
472 }
473 }
474
475 // Now, dump the map into aCandidates
476 for( const candidate_map_t::value_type& each_pair : candidate_map )
477 {
478 aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
479 }
480}
481
482
484{
485 wxString action;
486
488 {
489 action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
490 "the cache." ),
492 }
494 {
495 action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
498 }
499 else
500 {
501 action.Printf( _( "Rescue modified symbol %s to %s" ),
504 }
505
506 return action;
507}
508
509
511{
513
514 wxCHECK_MSG( tmp, false, wxS( "Both cache and library symbols undefined." ) );
515
516 std::unique_ptr<LIB_SYMBOL> new_symbol = tmp->Flatten();
517 new_symbol->SetLibId( m_new_id );
518 new_symbol->SetName( m_new_id.GetLibItemName() );
519 aRescuer->AddSymbol( new_symbol.get() );
520
521 for( SCH_SYMBOL* eachSymbol : *aRescuer->GetSymbols() )
522 {
523 if( eachSymbol->GetLibId() != m_requested_id )
524 continue;
525
526 eachSymbol->SetLibId( m_new_id );
527 eachSymbol->ClearFlags();
528 aRescuer->LogRescue( eachSymbol, m_requested_id.Format(), m_new_id.Format() );
529 }
530
531 return true;
532}
533
534
535RESCUER::RESCUER( PROJECT& aProject, SCHEMATIC* aSchematic, SCH_SHEET_PATH* aCurrentSheet,
536 EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType )
537{
538 m_schematic = aSchematic ? aSchematic : aCurrentSheet->LastScreen()->Schematic();
539
540 wxASSERT( m_schematic );
541
542 if( m_schematic )
544
545 m_prj = &aProject;
546 m_currentSheet = aCurrentSheet;
547 m_galBackEndType = aGalBackEndType;
548}
549
550
551void RESCUER::LogRescue( SCH_SYMBOL* aSymbol, const wxString &aOldName,
552 const wxString &aNewName )
553{
554 RESCUE_LOG logitem;
555 logitem.symbol = aSymbol;
556 logitem.old_name = aOldName;
557 logitem.new_name = aNewName;
558 m_rescue_log.push_back( logitem );
559}
560
561
563{
564 for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
565 {
566 if( ! each_candidate->PerformAction( this ) )
567 return false;
568 }
569
570 return true;
571}
572
573
575{
576 for( RESCUE_LOG& each_logitem : m_rescue_log )
577 {
578 LIB_ID libId;
579
580 libId.SetLibItemName( each_logitem.old_name );
581 each_logitem.symbol->SetLibId( libId );
582 each_logitem.symbol->ClearFlags();
583 }
584}
585
586
587bool RESCUER::RescueProject( wxWindow* aParent, RESCUER& aRescuer, bool aRunningOnDemand )
588{
589 aRescuer.FindCandidates();
590
591 if( !aRescuer.GetCandidateCount() )
592 {
593 if( aRunningOnDemand )
594 {
595 wxMessageDialog dlg( aParent, _( "This project has nothing to rescue." ),
596 _( "Project Rescue Helper" ) );
597 dlg.ShowModal();
598 }
599
600 return true;
601 }
602
603 aRescuer.RemoveDuplicates();
604 aRescuer.InvokeDialog( aParent, !aRunningOnDemand );
605
606 // If no symbols were rescued, let the user know what's going on. He might
607 // have clicked cancel by mistake, and should have some indication of that.
608 if( !aRescuer.GetChosenCandidateCount() )
609 {
610 wxMessageDialog dlg( aParent, _( "No symbols were rescued." ),
611 _( "Project Rescue Helper" ) );
612 dlg.ShowModal();
613
614 // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
615 // this point, due to the reloading of the symbols, so we'll make the save button active.
616 return true;
617 }
618
619 aRescuer.OpenRescueLibrary();
620
621 if( !aRescuer.DoRescues() )
622 {
623 aRescuer.UndoRescues();
624 return false;
625 }
626
627 aRescuer.WriteRescueLibrary( aParent );
628
629 return true;
630}
631
632
634{
635 std::vector<wxString> names_seen;
636
637 for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
638 it != m_all_candidates.end(); )
639 {
640 bool seen_already = false;
641
642 for( wxString& name_seen : names_seen )
643 {
644 if( name_seen == it->GetRequestedName() )
645 {
646 seen_already = true;
647 break;
648 }
649 }
650
651 if( seen_already )
652 {
653 it = m_all_candidates.erase( it );
654 }
655 else
656 {
657 names_seen.push_back( it->GetRequestedName() );
658 ++it;
659 }
660 }
661}
662
663
665{
668}
669
670
671void LEGACY_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
672{
673 InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
674 m_galBackEndType, aAskShowAgain );
675}
676
677
679{
680 wxFileName fn = GetRescueLibraryFileName( m_schematic );
681
682 std::unique_ptr<SYMBOL_LIB> rescue_lib = std::make_unique<SYMBOL_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
683 fn.GetFullPath() );
684
685 m_rescue_lib = std::move( rescue_lib );
686 m_rescue_lib->EnableBuffering();
687
688 // If a rescue library already exists copy the contents of that library so we do not
689 // lose any previous rescues.
690 SYMBOL_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
691
692 if( rescueLib )
693 {
694 // For items in the rescue library, aliases are the root symbol.
695 std::vector< LIB_SYMBOL* > symbols;
696
697 rescueLib->GetSymbols( symbols );
698
699 for( LIB_SYMBOL* symbol : symbols )
700 {
701 // The LIB_SYMBOL copy constructor flattens derived symbols (formerly known as aliases).
702 m_rescue_lib->AddSymbol( new LIB_SYMBOL( *symbol, m_rescue_lib.get() ) );
703 }
704 }
705}
706
707
708bool LEGACY_RESCUER::WriteRescueLibrary( wxWindow *aParent )
709{
710 try
711 {
712 m_rescue_lib->Save( false );
713 }
714 catch( ... /* IO_ERROR ioe */ )
715 {
716 wxString msg;
717
718 msg.Printf( _( "Failed to create symbol library file '%s'." ),
719 m_rescue_lib->GetFullFileName() );
720 DisplayError( aParent, msg );
721 return false;
722 }
723
724 wxArrayString libNames;
725 wxString libPaths;
726
727 wxString libName = m_rescue_lib->GetName();
729
730 if( !libs )
731 {
732 libs = new SYMBOL_LIBS();
734 }
735
736 try
737 {
738 SYMBOL_LIBS::GetLibNamesAndPaths( m_prj, &libPaths, &libNames );
739
740 // Make sure the library is not already in the list
741 while( libNames.Index( libName ) != wxNOT_FOUND )
742 libNames.Remove( libName );
743
744 // Add the library to the top of the list and save.
745 libNames.Insert( libName, 0 );
746 SYMBOL_LIBS::SetLibNamesAndPaths( m_prj, libPaths, libNames );
747 }
748 catch( const IO_ERROR& )
749 {
750 // Could not get or save the current libraries.
751 return false;
752 }
753
754 // Save the old libraries in case there is a problem after clear(). We'll
755 // put them back in.
756 boost::ptr_vector<SYMBOL_LIB> libsSave;
757 libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
758
760
761 libs = new SYMBOL_LIBS();
762
763 try
764 {
765 libs->LoadAllLibraries( m_prj );
766 }
767 catch( const PARSE_ERROR& )
768 {
769 // Some libraries were not found. There's no point in showing the error,
770 // because it was already shown. Just don't do anything.
771 }
772 catch( const IO_ERROR& )
773 {
774 // Restore the old list
775 libs->clear();
776 libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
777 return false;
778 }
779
781
782 // Update the schematic symbol library links since the library list has changed.
783 SCH_SCREENS schematic( m_schematic->Root() );
784 schematic.UpdateSymbolLinks();
785 return true;
786}
787
788
790{
791 wxCHECK_RET( aNewSymbol, wxS( "Invalid LIB_SYMBOL pointer." ) );
792
793 aNewSymbol->SetLib( m_rescue_lib.get() );
794 m_rescue_lib->AddSymbol( aNewSymbol );
795}
796
797
799 SCH_SHEET_PATH* aCurrentSheet,
800 EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType ) :
801 RESCUER( aProject, aSchematic, aCurrentSheet, aGalBackEndType )
802{
803 m_properties = std::make_unique<STRING_UTF8_MAP>();
804}
805
806
808{
810}
811
812
813void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
814{
815 InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
816 m_galBackEndType, aAskShowAgain );
817}
818
819
821{
822 (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
823
824 wxFileName fn = GetRescueLibraryFileName( m_schematic );
825
826 SYMBOL_LIB_TABLE_ROW* row = m_prj->SchSymbolLibTable()->FindRow( fn.GetName() );
827
828 // If a rescue library already exists copy the contents of that library so we do not
829 // lose any previous rescues.
830 if( row )
831 {
832 if( SCH_IO_MGR::EnumFromStr( row->GetType() ) == SCH_IO_MGR::SCH_KICAD )
833 fn.SetExt( KiCadSymbolLibFileExtension );
834
835 std::vector<LIB_SYMBOL*> symbols;
836
837 try
838 {
839 m_prj->SchSymbolLibTable()->LoadSymbolLib( symbols, fn.GetName() );
840 }
841 catch( ... /* IO_ERROR */ )
842 {
843 return;
844 }
845
846 for( LIB_SYMBOL* symbol : symbols )
847 m_rescueLibSymbols.emplace_back( std::make_unique<LIB_SYMBOL>( *symbol ) );
848 }
849}
850
851
853{
854 wxString msg;
855 wxFileName fn = GetRescueLibraryFileName( m_schematic );
856 SYMBOL_LIB_TABLE_ROW* row = m_prj->SchSymbolLibTable()->FindRow( fn.GetName() );
857
858 fn.SetExt( KiCadSymbolLibFileExtension );
859
860 try
861 {
862 SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
863
864 for( const std::unique_ptr<LIB_SYMBOL>& symbol : m_rescueLibSymbols )
865 pi->SaveSymbol( fn.GetFullPath(), new LIB_SYMBOL( *symbol.get() ), m_properties.get() );
866
867 pi->SaveLibrary( fn.GetFullPath() );
868 }
869 catch( const IO_ERROR& ioe )
870 {
871 msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
872 DisplayErrorMessage( aParent, msg, ioe.What() );
873 return false;
874 }
875
876 // If the rescue library already exists in the symbol library table no need save it to add
877 // it to the table.
878 if( !row || ( SCH_IO_MGR::EnumFromStr( row->GetType() ) == SCH_IO_MGR::SCH_LEGACY ) )
879 {
880 wxString uri = wxS( "${KIPRJMOD}/" ) + fn.GetFullName();
881 wxString libNickname = fn.GetName();
882
883 row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri, wxT( "KiCad" ) );
884 m_prj->SchSymbolLibTable()->InsertRow( row, true );
885
887
888 try
889 {
890 m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
891 }
892 catch( const IO_ERROR& ioe )
893 {
894 msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
895 DisplayErrorMessage( aParent, msg, ioe.What() );
896 return false;
897 }
898 }
899
901
902 // This can only happen if the symbol library table file was corrupted on write.
903 if( !m_prj->SchSymbolLibTable() )
904 return false;
905
906 // Update the schematic symbol library links since the library list has changed.
907 SCH_SCREENS schematic( m_schematic->Root() );
908 schematic.UpdateSymbolLinks();
909 return true;
910}
911
912
914{
915 wxCHECK_RET( aNewSymbol, wxS( "Invalid LIB_SYMBOL pointer." ) );
916
917 m_rescueLibSymbols.emplace_back( std::make_unique<LIB_SYMBOL>( *aNewSymbol ) );
918}
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:172
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:112
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:99
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:886
bool IsAlias() const
Definition: lib_symbol.h:188
LIB_ID GetLibId() const override
Definition: lib_symbol.h:141
void SetLib(SYMBOL_LIB *aLibrary)
Definition: lib_symbol.h:193
std::unique_ptr< LIB_SYMBOL > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:453
LIB_SYMBOL_REF & GetParent()
Definition: lib_symbol.h:127
Container for project specific data.
Definition: project.h:64
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:211
@ ELEM_SCH_SYMBOL_LIBS
Definition: project.h:208
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:199
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:662
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:92
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:81
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:175
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:300
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:325
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:45
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.