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