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