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