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