KiCad PCB EDA Suite
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 <pavlina.chris@gmail.com>
5  * Copyright (C) 2015-2021 KiCad Developers, see change_log.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <sch_draw_panel.h>
26 #include <class_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 <sch_symbol.h>
34 #include <sch_sheet.h>
35 #include <sch_edit_frame.h>
36 #include <schematic.h>
37 #include <symbol_lib_table.h>
39 
40 #include <cctype>
41 #include <map>
42 
43 
44 typedef std::pair<SCH_COMPONENT*, wxString> COMPONENT_NAME_PAIR;
45 
46 
47 // Helper sort function, used in get_components, to sort a component list by lib_id
48 static bool sort_by_libid( const SCH_COMPONENT* ref, SCH_COMPONENT* cmp )
49 {
50  return ref->GetLibId() < cmp->GetLibId();
51 }
52 
53 
63 static void get_components( SCHEMATIC* aSchematic, std::vector<SCH_COMPONENT*>& aComponents )
64 {
65  SCH_SCREENS screens( aSchematic->Root() );
66 
67  // Get the full list
68  for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
69  {
70  for( auto aItem : screen->Items().OfType( SCH_COMPONENT_T ) )
71  aComponents.push_back( static_cast<SCH_COMPONENT*>( aItem ) );
72  }
73 
74  if( aComponents.empty() )
75  return;
76 
77  // sort aComponents by lib part. Components will be grouped by same lib part.
78  std::sort( aComponents.begin(), aComponents.end(), sort_by_libid );
79 }
80 
81 
89 static LIB_PART* find_component( const wxString& aName, PART_LIBS* aLibs, bool aCached )
90 {
91  LIB_PART *part = NULL;
92  wxString new_name = LIB_ID::FixIllegalChars( aName );
93 
94  for( PART_LIB& each_lib : *aLibs )
95  {
96  if( aCached && !each_lib.IsCache() )
97  continue;
98 
99  if( !aCached && each_lib.IsCache() )
100  continue;
101 
102  part = each_lib.FindPart( new_name );
103 
104  if( part )
105  break;
106  }
107 
108  return part;
109 }
110 
111 
112 static wxFileName GetRescueLibraryFileName( SCHEMATIC* aSchematic )
113 {
114  wxFileName fn = aSchematic->GetFileName();
115  fn.SetName( fn.GetName() + wxT( "-rescue" ) );
116  fn.SetExt( LegacySymbolLibFileExtension );
117  return fn;
118 }
119 
120 
121 RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName,
122  const wxString& aNewName,
123  LIB_PART* aLibCandidate,
124  int aUnit,
125  int aConvert )
126 {
127  m_requested_name = aRequestedName;
128  m_new_name = aNewName;
129  m_lib_candidate = aLibCandidate;
130  m_unit = aUnit;
131  m_convert = aConvert;
132 }
133 
134 
136  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
137 {
138  typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
139  candidate_map_t candidate_map;
140  // Remember the list of components is sorted by part name.
141  // So a search in libraries is made only once by group
142  LIB_PART* case_sensitive_match = nullptr;
143  std::vector<LIB_PART*> case_insensitive_matches;
144 
145  wxString part_name;
146  wxString search_name;
147  wxString last_part_name;
148 
149  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
150  {
151  part_name = each_component->GetLibId().GetLibItemName();
152  search_name = LIB_ID::FixIllegalChars( part_name );
153 
154  if( last_part_name != part_name )
155  {
156  // A new part name is found (a new group starts here).
157  // Search the symbol names candidates only once for this group:
158  last_part_name = part_name;
159  case_insensitive_matches.clear();
160 
161  LIB_ID id( wxEmptyString, search_name );
162 
163  case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibPart( id );
164 
165  // If the case sensitive match failed, try a case insensitive match.
166  if( !case_sensitive_match )
167  aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
168  search_name );
169  }
170 
171  if( case_sensitive_match || !( case_insensitive_matches.size() ) )
172  continue;
173 
174  RESCUE_CASE_CANDIDATE candidate( part_name, case_insensitive_matches[0]->GetName(),
175  case_insensitive_matches[0],
176  each_component->GetUnit(),
177  each_component->GetConvert() );
178 
179  candidate_map[part_name] = candidate;
180  }
181 
182  // Now, dump the map into aCandidates
183  for( const candidate_map_t::value_type& each_pair : candidate_map )
184  {
185  aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
186  }
187 }
188 
189 
191 {
192  wxString action;
193  action.Printf( _( "Rename %s to %s" ), m_requested_name, m_new_name );
194  return action;
195 }
196 
197 
199 {
200  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
201  {
202  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
203  continue;
204 
205  LIB_ID libId;
206 
207  libId.SetLibItemName( m_new_name, false );
208  each_component->SetLibId( libId );
209  each_component->ClearFlags();
210  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
211  }
212 
213  return true;
214 }
215 
216 
217 RESCUE_CACHE_CANDIDATE::RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName,
218  const wxString& aNewName,
219  LIB_PART* aCacheCandidate,
220  LIB_PART* aLibCandidate,
221  int aUnit,
222  int aConvert )
223 {
224  m_requested_name = aRequestedName;
225  m_new_name = aNewName;
226  m_cache_candidate = aCacheCandidate;
227  m_lib_candidate = aLibCandidate;
228  m_unit = aUnit;
229  m_convert = aConvert;
230 }
231 
232 
234 {
237 }
238 
239 
241  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
242 {
243  typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
244  candidate_map_t candidate_map;
245 
246  // Remember the list of components is sorted by part name.
247  // So a search in libraries is made only once by group
248  LIB_PART* cache_match = nullptr;
249  LIB_PART* lib_match = nullptr;
250  wxString part_name;
251  wxString search_name;
252  wxString old_part_name;
253 
254  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
255  {
256  part_name = each_component->GetLibId().GetLibItemName();
257  search_name = LIB_ID::FixIllegalChars( part_name );
258 
259  if( old_part_name != part_name )
260  {
261  // A new part name is found (a new group starts here).
262  // Search the symbol names candidates only once for this group:
263  old_part_name = part_name;
264  cache_match = find_component( search_name, aRescuer.GetPrj()->SchLibs(), true );
265  lib_match = find_component( search_name, aRescuer.GetPrj()->SchLibs(), false );
266 
267  if( !cache_match && !lib_match )
268  continue;
269 
270  // Test whether there is a conflict or if the symbol can only be found in the cache
271  // and the symbol name does not have any illegal characters.
272  if( cache_match && lib_match &&
273  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
274  continue;
275 
276  if( !cache_match && lib_match )
277  continue;
278 
279  // Check if the symbol has already been rescued.
280  RESCUE_CACHE_CANDIDATE candidate( part_name, search_name, cache_match, lib_match,
281  each_component->GetUnit(),
282  each_component->GetConvert() );
283 
284  candidate_map[part_name] = candidate;
285  }
286  }
287 
288  // Now, dump the map into aCandidates
289  for( const candidate_map_t::value_type& each_pair : candidate_map )
290  {
291  aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
292  }
293 }
294 
295 
297 {
298  wxString action;
299 
301  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
302  "the cache." ), m_requested_name );
303  else if( m_cache_candidate && !m_lib_candidate )
304  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
306  else
307  action.Printf( _( "Rescue modified symbol %s to %s" ),
309 
310  return action;
311 }
312 
313 
315 {
317 
318  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
319 
320  std::unique_ptr<LIB_PART> new_part = tmp->Flatten();
321  new_part->SetName( m_new_name );
322  aRescuer->AddPart( new_part.get() );
323 
324  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
325  {
326  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
327  continue;
328 
329  LIB_ID libId;
330 
331  libId.SetLibItemName( m_new_name, false );
332  each_component->SetLibId( libId );
333  each_component->ClearFlags();
334  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
335  }
336 
337  return true;
338 }
339 
340 
342  const LIB_ID& aRequestedId,
343  const LIB_ID& aNewId,
344  LIB_PART* aCacheCandidate,
345  LIB_PART* aLibCandidate,
346  int aUnit,
347  int aConvert ) : RESCUE_CANDIDATE()
348 {
349  m_requested_id = aRequestedId;
350  m_requested_name = aRequestedId.Format();
351  m_new_id = aNewId;
352  m_lib_candidate = aLibCandidate;
353  m_cache_candidate = aCacheCandidate;
354  m_unit = aUnit;
355  m_convert = aConvert;
356 }
357 
358 
360 {
363 }
364 
365 
367  RESCUER& aRescuer,
368  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
369 {
370  typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
371 
372  candidate_map_t candidate_map;
373 
374  // Remember the list of components is sorted by LIB_ID.
375  // So a search in libraries is made only once by group
376  LIB_PART* cache_match = nullptr;
377  LIB_PART* lib_match = nullptr;
378  LIB_ID old_part_id;
379 
380  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
381  {
382  const LIB_ID& part_id = each_component->GetLibId();
383 
384  if( old_part_id != part_id )
385  {
386  // A new part name is found (a new group starts here).
387  // Search the symbol names candidates only once for this group:
388  old_part_id = part_id;
389 
390  // Get the library symbol from the cache library. It will be a flattened
391  // symbol by default (no inheritance).
392  cache_match = find_component( part_id.Format().wx_str(), aRescuer.GetPrj()->SchLibs(),
393  true );
394 
395  // Get the library symbol from the symbol library table.
396  lib_match = SchGetLibPart( part_id, aRescuer.GetPrj()->SchSymbolLibTable() );
397 
398  if( !cache_match && !lib_match )
399  continue;
400 
401  PART_SPTR lib_match_parent;
402 
403  // If it's a derive symbol, use the parent symbol to perform the pin test.
404  if( lib_match && lib_match->IsAlias() )
405  {
406  lib_match_parent = lib_match->GetParent().lock();
407 
408  if( !lib_match_parent )
409  {
410  lib_match = nullptr;
411  }
412  else
413  {
414  lib_match = lib_match_parent.get();
415  }
416  }
417 
418  // Test whether there is a conflict or if the symbol can only be found in the cache.
419  if( LIB_ID::HasIllegalChars( part_id.GetLibItemName() ) == -1 )
420  {
421  if( cache_match && lib_match &&
422  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
423  continue;
424 
425  if( !cache_match && lib_match )
426  continue;
427  }
428 
429  // Fix illegal LIB_ID name characters.
430  wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName() );
431 
432  // Differentiate symbol name in the rescue library by appending the symbol library
433  // table nickname to the symbol name to prevent name clashes in the rescue library.
434  wxString libNickname = GetRescueLibraryFileName( aRescuer.Schematic() ).GetName();
435 
436  // Spaces in the file name will break the symbol name because they are not
437  // quoted in the symbol library file format.
438  libNickname.Replace( " ", "-" );
439  LIB_ID new_id( libNickname, new_name + "-" + part_id.GetLibNickname().wx_str() );
440 
441  RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match,
442  each_component->GetUnit(),
443  each_component->GetConvert() );
444 
445  candidate_map[part_id] = candidate;
446  }
447  }
448 
449  // Now, dump the map into aCandidates
450  for( const candidate_map_t::value_type& each_pair : candidate_map )
451  {
452  aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
453  }
454 }
455 
456 
458 {
459  wxString action;
460 
462  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
463  "the cache." ), m_requested_id.GetLibItemName().wx_str() );
464  else if( m_cache_candidate && !m_lib_candidate )
465  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
467  else
468  action.Printf( _( "Rescue modified symbol %s to %s" ),
470 
471  return action;
472 }
473 
474 
476 {
478 
479  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
480 
481  std::unique_ptr<LIB_PART> new_part = tmp->Flatten();
482  new_part->SetLibId( m_new_id );
483  new_part->SetName( m_new_id.GetLibItemName() );
484  aRescuer->AddPart( new_part.get() );
485 
486  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
487  {
488  if( each_component->GetLibId() != m_requested_id )
489  continue;
490 
491  each_component->SetLibId( m_new_id );
492  each_component->ClearFlags();
493  aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
494  }
495 
496  return true;
497 }
498 
499 
500 RESCUER::RESCUER( PROJECT& aProject, SCHEMATIC* aSchematic, SCH_SHEET_PATH* aCurrentSheet,
501  EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType )
502 {
503  m_schematic = aSchematic ? aSchematic : aCurrentSheet->LastScreen()->Schematic();
504 
505  wxASSERT( m_schematic );
506 
507  if( m_schematic )
509 
510  m_prj = &aProject;
511  m_currentSheet = aCurrentSheet;
512  m_galBackEndType = aGalBackEndType;
513 }
514 
515 
516 void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
517  const wxString &aNewName )
518 {
519  RESCUE_LOG logitem;
520  logitem.component = aComponent;
521  logitem.old_name = aOldName;
522  logitem.new_name = aNewName;
523  m_rescue_log.push_back( logitem );
524 }
525 
526 
528 {
529  for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
530  {
531  if( ! each_candidate->PerformAction( this ) )
532  return false;
533  }
534 
535  return true;
536 }
537 
538 
540 {
541  for( RESCUE_LOG& each_logitem : m_rescue_log )
542  {
543  LIB_ID libId;
544 
545  libId.SetLibItemName( each_logitem.old_name, false );
546  each_logitem.component->SetLibId( libId );
547  each_logitem.component->ClearFlags();
548  }
549 }
550 
551 
552 bool RESCUER::RescueProject( wxWindow* aParent, RESCUER& aRescuer, bool aRunningOnDemand )
553 {
554  aRescuer.FindCandidates();
555 
556  if( !aRescuer.GetCandidateCount() )
557  {
558  if( aRunningOnDemand )
559  {
560  wxMessageDialog dlg( aParent, _( "This project has nothing to rescue." ),
561  _( "Project Rescue Helper" ) );
562  dlg.ShowModal();
563  }
564 
565  return true;
566  }
567 
568  aRescuer.RemoveDuplicates();
569  aRescuer.InvokeDialog( aParent, !aRunningOnDemand );
570 
571  // If no symbols were rescued, let the user know what's going on. He might
572  // have clicked cancel by mistake, and should have some indication of that.
573  if( !aRescuer.GetChosenCandidateCount() )
574  {
575  wxMessageDialog dlg( aParent, _( "No symbols were rescued." ),
576  _( "Project Rescue Helper" ) );
577  dlg.ShowModal();
578 
579  // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
580  // this point, due to the reloading of the symbols, so we'll make the save button active.
581  return true;
582  }
583 
584  aRescuer.OpenRescueLibrary();
585 
586  if( !aRescuer.DoRescues() )
587  {
588  aRescuer.UndoRescues();
589  return false;
590  }
591 
592  aRescuer.WriteRescueLibrary( aParent );
593 
594  return true;
595 }
596 
597 
599 {
600  std::vector<wxString> names_seen;
601 
602  for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
603  it != m_all_candidates.end(); )
604  {
605  bool seen_already = false;
606 
607  for( wxString& name_seen : names_seen )
608  {
609  if( name_seen == it->GetRequestedName() )
610  {
611  seen_already = true;
612  break;
613  }
614  }
615 
616  if( seen_already )
617  {
618  it = m_all_candidates.erase( it );
619  }
620  else
621  {
622  names_seen.push_back( it->GetRequestedName() );
623  ++it;
624  }
625  }
626 }
627 
628 
630 {
633 }
634 
635 
636 void LEGACY_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
637 {
638  InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
639  m_galBackEndType, aAskShowAgain );
640 }
641 
642 
644 {
645  wxFileName fn = GetRescueLibraryFileName( m_schematic );
646 
647  std::unique_ptr<PART_LIB> rescue_lib = std::make_unique<PART_LIB>( SCH_LIB_TYPE::LT_EESCHEMA,
648  fn.GetFullPath() );
649 
650  m_rescue_lib = std::move( rescue_lib );
651  m_rescue_lib->EnableBuffering();
652 
653  // If a rescue library already exists copy the contents of that library so we do not
654  // lose an previous rescues.
655  PART_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
656 
657  if( rescueLib )
658  {
659  // For items in the rescue library, aliases are the root symbol.
660  std::vector< LIB_PART* > symbols;
661 
662  rescueLib->GetParts( symbols );
663 
664  for( auto symbol : symbols )
665  {
666  // The LIB_PART copy constructor flattens derived symbols (formerly known as aliases).
667  m_rescue_lib->AddPart( new LIB_PART( *symbol, m_rescue_lib.get() ) );
668  }
669  }
670 }
671 
672 
673 bool LEGACY_RESCUER::WriteRescueLibrary( wxWindow *aParent )
674 {
675  try
676  {
677  m_rescue_lib->Save( false );
678  }
679  catch( ... /* IO_ERROR ioe */ )
680  {
681  wxString msg;
682 
683  msg.Printf( _( "Failed to create symbol library file \"%s\"" ),
684  m_rescue_lib->GetFullFileName() );
685  DisplayError( aParent, msg );
686  return false;
687  }
688 
689  wxArrayString libNames;
690  wxString libPaths;
691 
692  wxString libName = m_rescue_lib->GetName();
693  PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
694 
695  if( !libs )
696  {
697  libs = new PART_LIBS();
699  }
700 
701  try
702  {
703  PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
704 
705  // Make sure the library is not already in the list
706  while( libNames.Index( libName ) != wxNOT_FOUND )
707  libNames.Remove( libName );
708 
709  // Add the library to the top of the list and save.
710  libNames.Insert( libName, 0 );
711  PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
712  }
713  catch( const IO_ERROR& )
714  {
715  // Could not get or save the current libraries.
716  return false;
717  }
718 
719  // Save the old libraries in case there is a problem after clear(). We'll
720  // put them back in.
721  boost::ptr_vector<PART_LIB> libsSave;
722  libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
723 
725 
726  libs = new PART_LIBS();
727 
728  try
729  {
730  libs->LoadAllLibraries( m_prj );
731  }
732  catch( const PARSE_ERROR& )
733  {
734  // Some libraries were not found. There's no point in showing the error,
735  // because it was already shown. Just don't do anything.
736  }
737  catch( const IO_ERROR& )
738  {
739  // Restore the old list
740  libs->clear();
741  libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
742  return false;
743  }
744 
746 
747  // Update the schematic symbol library links since the library list has changed.
748  SCH_SCREENS schematic( m_schematic->Root() );
749  schematic.UpdateSymbolLinks();
750  return true;
751 }
752 
753 
755 {
756  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
757 
758  aNewPart->SetLib( m_rescue_lib.get() );
759  m_rescue_lib->AddPart( aNewPart );
760 }
761 
762 
764  SCH_SHEET_PATH* aCurrentSheet,
765  EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType ) :
766  RESCUER( aProject, aSchematic, aCurrentSheet, aGalBackEndType )
767 {
768  m_properties = std::make_unique<PROPERTIES>();
769 }
770 
771 
773 {
775 }
776 
777 
778 void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
779 {
780  InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
781  m_galBackEndType, aAskShowAgain );
782 }
783 
784 
786 {
787  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
788  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
789 }
790 
791 
793 {
794  wxString msg;
795  wxFileName fn = GetRescueLibraryFileName( m_schematic );
796 
797  // If the rescue library already exists in the symbol library table no need save it to add
798  // it to the table.
799  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
800  {
801  try
802  {
803  m_pi->SaveLibrary( fn.GetFullPath() );
804  }
805  catch( const IO_ERROR& ioe )
806  {
807  msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
808  DisplayErrorMessage( aParent, msg, ioe.What() );
809  return false;
810  }
811 
812  wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
813  wxString libNickname = fn.GetName();
814 
815  // Spaces in the file name will break the symbol name because they are not
816  // quoted in the symbol library file format.
817  libNickname.Replace( " ", "-" );
818 
819  SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri,
820  wxString( "Legacy" ) );
821  m_prj->SchSymbolLibTable()->InsertRow( row );
822 
824 
825  try
826  {
827  m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
828  }
829  catch( const IO_ERROR& ioe )
830  {
831  msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
832  DisplayErrorMessage( aParent, msg, ioe.What() );
833  return false;
834  }
835  }
836 
837  // Relaod the symbol library table.
839 
840  // This can only happen if the symbol library table file was currupted on write.
841  if( !m_prj->SchSymbolLibTable() )
842  return false;
843 
844  // Update the schematic symbol library links since the library list has changed.
845  SCH_SCREENS schematic( m_schematic->Root() );
846  schematic.UpdateSymbolLinks();
847  return true;
848 }
849 
850 
852 {
853  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
854 
855  wxFileName fn = GetRescueLibraryFileName( m_schematic );
856 
857  try
858  {
859  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
860  m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
861  else
862  m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
863  }
864  catch( ... /* IO_ERROR */ )
865  {
866  }
867 }
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:253
EDA_DRAW_PANEL_GAL::GAL_TYPE m_galBackEndType
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition: utf8.h:70
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
void SetLib(PART_LIB *aLibrary)
Definition: lib_symbol.h:173
static const wxString & GetSymbolLibTableFileName()
bool PinsConflictWith(LIB_PART &aOtherPart, bool aTestNums, bool aTestNames, bool aTestType, bool aTestOrientation, bool aTestLength)
Return true if this part's pins do not match another part's pins.
Definition: lib_symbol.cpp:727
virtual bool WriteRescueLibrary(wxWindow *aParent)=0
Writes out the rescue library.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
SCHEMATIC * Schematic()
virtual void FindCandidates()=0
Populate the RESCUER with all possible candidates.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:106
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib=false)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:347
size_t GetChosenCandidateCount()
Get the number of resuce candidates chosen by the user.
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
static void LibNamesAndPaths(PROJECT *aProject, bool doSave, wxString *aPaths, wxArrayString *aNames=NULL)
Save or load the names of the currently configured part libraries (without paths).
LIB_ID GetLibId() const override
Definition: lib_symbol.h:131
Container for project specific data.
Definition: project.h:62
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:266
PROJECT * GetPrj()
Return the #SCH_PROJECT object for access to the symbol libraries.
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it.
Holds all the data relating to one schematic A schematic may consist of one or more sheets (and one r...
Definition: schematic.h:58
RESCUER(PROJECT &aProject, SCHEMATIC *aSchematic, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackeEndType)
This file is part of the common library.
const std::string LegacySymbolLibFileExtension
static wxFileName GetRescueLibraryFileName(SCHEMATIC *aSchematic)
virtual void OpenRescueLibrary() override
static bool sort_by_libid(const SCH_COMPONENT *ref, SCH_COMPONENT *cmp)
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain)=0
Display a dialog to allow the user to select rescues.
std::shared_ptr< LIB_PART > PART_SPTR
shared pointer to LIB_PART
Definition: lib_symbol.h:42
void set(SCH_PLUGIN *aPlugin)
Definition: sch_io_mgr.h:498
virtual _ELEM * GetElem(ELEM_T aIndex)
Get and set the elements for this project.
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.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
virtual const wxString GetProjectPath() const
Return the full path of the project.
SYMBOL_LIB_TABLE_RESCUER(PROJECT &aProject, SCHEMATIC *aSchematic, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackeEndType)
LIB_PART * m_lib_candidate
SCH_COMPONENT * component
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
boost::ptr_vector< RESCUE_CANDIDATE > m_all_candidates
void RemoveDuplicates()
Filter out duplicately named rescue candidates.
static bool RescueProject(wxWindow *aParent, RESCUER &aRescuer, bool aRunningOnDemand)
SCH_SHEET_PATH * m_currentSheet
#define NULL
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CACHE_CANDIDATE objectss into a vector.
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi
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.
size_t GetCandidateCount()
Returen the number of rescue candidates found.
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_SYMBOL_LIB_TABLE_CANDIDATE objects into a vector.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
PART_REF & GetParent()
Definition: lib_symbol.h:120
std::unique_ptr< PROPERTIES > m_properties
Library plugin properties.
Define a library symbol object.
Definition: lib_symbol.h:93
Definition of file extensions used in Kicad.
PROJECT * m_prj
std::pair< SCH_COMPONENT *, wxString > COMPONENT_NAME_PAIR
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:92
std::vector< SCH_COMPONENT * > m_components
static LIB_PART * find_component(const wxString &aName, PART_LIBS *aLibs, bool aCached)
Search the libraries for the first component with a given name.
wxString GetFileName() const override
Helper to retrieve the filename from the root sheet screen.
Definition: schematic.cpp:119
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
std::unique_ptr< LIB_PART > Flatten() const
Return a flattened symbol inheritance to the caller.
Definition: lib_symbol.cpp:327
UTF8 Format() const
Definition: lib_id.cpp:233
int SetLibItemName(const UTF8 &aLibItemName, bool aTestForRev=true)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:204
virtual void OpenRescueLibrary()=0
void GetParts(std::vector< LIB_PART * > &aPart) const
Load a vector with all the entries in this library.
A collection of PART_LIB objects.
std::vector< RESCUE_CANDIDATE * > m_chosen_candidates
SCH_SHEET & Root() const
Definition: schematic.h:116
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:118
virtual bool WriteRescueLibrary(wxWindow *aParent) override
Writes out the rescue library.
std::unique_ptr< PART_LIB > m_rescue_lib
virtual void OpenRescueLibrary() override
static int HasIllegalChars(const UTF8 &aLibItemName)
Examine aLibItemName for invalid LIB_ID item name characters.
Definition: lib_id.cpp:331
SCH_SCREEN * LastScreen()
bool DoRescues()
Perform all chosen rescue actions, logging them to be undone if necessary.
#define _(s)
Definition: 3d_actions.cpp:33
SCHEMATIC * Schematic() const
Definition: sch_screen.cpp:87
SCHEMATIC * m_schematic
wxString wx_str() const
Definition: utf8.cpp:51
Schematic symbol object.
Definition: sch_symbol.h:79
virtual void AddPart(LIB_PART *aNewPart)=0
static const char * PropBuffering
The property used internally by the plugin to enable cache buffering which prevents the library file ...
virtual bool WriteRescueLibrary(wxWindow *aParent) override
Writes out the rescue library.
std::vector< SCH_COMPONENT * > * GetComponents()
Get the list of symbols that need rescued.
std::vector< RESCUE_LOG > m_rescue_log
void LogRescue(SCH_COMPONENT *aComponent, const wxString &aOldName, const wxString &aNewName)
Used by individual RESCUE_CANDIDATE objects to log a rescue for undoing.
wxString m_requested_name
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
virtual void AddPart(LIB_PART *aNewPart) override
wxString old_name
LIB_PART * SchGetLibPart(const LIB_ID &aLibId, SYMBOL_LIB_TABLE *aLibTable, PART_LIB *aCacheLib, wxWindow *aParent, bool aShowErrorMsg)
Load symbol from symbol library table.
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CASE_CANDIDATE objects into a vector.
Definition for part library class.
virtual void AddPart(LIB_PART *aNewPart) override
void UndoRescues()
Reverse the effects of all rescues on the project.
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_PART reference for each SCH_COMPONENT found in the full schematic.
const LIB_ID & GetLibId() const
Definition: sch_symbol.h:189
Object used to load, save, search, and otherwise manipulate symbol library files.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
wxString new_name
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:534
static void get_components(SCHEMATIC *aSchematic, std::vector< SCH_COMPONENT * > &aComponents)
Fill a vector with all of the project's symbols, to ease iterating over them.
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.