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