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-2019 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 <lib_view_frame.h>
32 #include <project_rescue.h>
33 #include <sch_component.h>
34 #include <sch_sheet.h>
35 #include <sch_edit_frame.h>
36 #include <symbol_lib_table.h>
38 
39 #include <cctype>
40 #include <map>
41 
42 
43 typedef std::pair<SCH_COMPONENT*, wxString> COMPONENT_NAME_PAIR;
44 
45 
46 // Helper sort function, used in get_components, to sort a component list by lib_id
47 static bool sort_by_libid( const SCH_COMPONENT* ref, SCH_COMPONENT* cmp )
48 {
49  return ref->GetLibId() < cmp->GetLibId();
50 }
51 
52 
62 static void get_components( std::vector<SCH_COMPONENT*>& aComponents )
63 {
64  SCH_SCREENS screens;
65 
66  // Get the full list
67  for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
68  {
69  for( auto aItem : screen->Items().OfType( SCH_COMPONENT_T ) )
70  aComponents.push_back( static_cast<SCH_COMPONENT*>( aItem ) );
71  }
72 
73  if( aComponents.empty() )
74  return;
75 
76  // sort aComponents by lib part. Components will be grouped by same lib part.
77  std::sort( aComponents.begin(), aComponents.end(), sort_by_libid );
78 }
79 
80 
88 static LIB_PART* find_component( const wxString& aName, PART_LIBS* aLibs, bool aCached )
89 {
90  LIB_PART *part = NULL;
91  wxString new_name = LIB_ID::FixIllegalChars( aName, LIB_ID::ID_SCH );
92 
93  for( PART_LIB& each_lib : *aLibs )
94  {
95  if( aCached && !each_lib.IsCache() )
96  continue;
97 
98  if( !aCached && each_lib.IsCache() )
99  continue;
100 
101  part = each_lib.FindPart( new_name );
102 
103  if( part )
104  break;
105  }
106 
107  return part;
108 }
109 
110 
111 static wxFileName GetRescueLibraryFileName()
112 {
113  wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
114  fn.SetName( fn.GetName() + wxT( "-rescue" ) );
115  fn.SetExt( SchematicLibraryFileExtension );
116  return fn;
117 }
118 
119 
120 RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName,
121  const wxString& aNewName,
122  LIB_PART* aLibCandidate )
123 {
124  m_requested_name = aRequestedName;
125  m_new_name = aNewName;
126  m_lib_candidate = aLibCandidate;
127 }
128 
129 
131  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
132 {
133  typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
134  candidate_map_t candidate_map;
135  // Remember the list of components is sorted by part name.
136  // So a search in libraries is made only once by group
137  LIB_PART* case_sensitive_match = nullptr;
138  std::vector<LIB_PART*> case_insensitive_matches;
139 
140  wxString last_part_name;
141 
142  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
143  {
144  wxString part_name = each_component->GetLibId().GetLibItemName();
145 
146  if( last_part_name != part_name )
147  {
148  // A new part name is found (a new group starts here).
149  // Search the symbol names candidates only once for this group:
150  last_part_name = part_name;
151  case_insensitive_matches.clear();
152 
153  LIB_ID id( wxEmptyString, part_name );
154 
155  case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibPart( id );
156 
157  if( !case_sensitive_match )
158  // the case sensitive match failed. Try a case insensitive match
159  aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
160  part_name );
161  }
162 
163  if( case_sensitive_match || !( case_insensitive_matches.size() ) )
164  continue;
165 
166  RESCUE_CASE_CANDIDATE candidate( part_name, case_insensitive_matches[0]->GetName(),
167  case_insensitive_matches[0] );
168 
169  candidate_map[part_name] = candidate;
170  }
171 
172  // Now, dump the map into aCandidates
173  for( const candidate_map_t::value_type& each_pair : candidate_map )
174  {
175  aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
176  }
177 }
178 
179 
181 {
182  wxString action;
183  action.Printf( _( "Rename to %s" ), m_new_name );
184  return action;
185 }
186 
187 
189 {
190  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
191  {
192  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
193  continue;
194 
195  LIB_ID libId;
196 
197  libId.SetLibItemName( m_new_name, false );
198  each_component->SetLibId( libId );
199  each_component->ClearFlags();
200  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
201  }
202 
203  return true;
204 }
205 
206 
207 RESCUE_CACHE_CANDIDATE::RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName,
208  const wxString& aNewName,
209  LIB_PART* aCacheCandidate,
210  LIB_PART* aLibCandidate )
211 {
212  m_requested_name = aRequestedName;
213  m_new_name = aNewName;
214  m_cache_candidate = aCacheCandidate;
215  m_lib_candidate = aLibCandidate;
216 }
217 
218 
220 {
223 }
224 
225 
227  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
228 {
229  typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
230  candidate_map_t candidate_map;
231 
232  // Remember the list of components is sorted by part name.
233  // So a search in libraries is made only once by group
234  LIB_PART* cache_match = nullptr;
235  LIB_PART* lib_match = nullptr;
236  wxString old_part_name;
237 
238  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
239  {
240  wxString part_name = each_component->GetLibId().GetLibItemName();
241 
242  if( old_part_name != part_name )
243  {
244  // A new part name is found (a new group starts here).
245  // Search the symbol names candidates only once for this group:
246  old_part_name = part_name;
247  cache_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), true );
248  lib_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), false );
249 
250  if( !cache_match && !lib_match )
251  continue;
252 
253  // Test whether there is a conflict or if the symbol can only be found in the cache
254  // and the symbol name does not have any illegal characters.
255  if( LIB_ID::HasIllegalChars( part_name, LIB_ID::ID_SCH ) == -1 )
256  {
257  if( cache_match && lib_match &&
258  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
259  continue;
260 
261  if( !cache_match && lib_match )
262  continue;
263  }
264 
265  // Check if the symbol has already been rescued.
266  wxString new_name = LIB_ID::FixIllegalChars( part_name, LIB_ID::ID_SCH );
267 
268  RESCUE_CACHE_CANDIDATE candidate( part_name, new_name, cache_match, lib_match );
269 
270  candidate_map[part_name] = candidate;
271  }
272  }
273 
274  // Now, dump the map into aCandidates
275  for( const candidate_map_t::value_type& each_pair : candidate_map )
276  {
277  aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
278  }
279 }
280 
281 
283 {
284  wxString action;
285 
287  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
288  "the cache." ), m_requested_name );
289  else if( m_cache_candidate && !m_lib_candidate )
290  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
292  else
293  action.Printf( _( "Rescue modified symbol %s to %s" ),
295 
296  return action;
297 }
298 
299 
301 {
303 
304  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
305 
306  LIB_PART new_part( *tmp );
307  new_part.SetName( m_new_name );
308  aRescuer->AddPart( &new_part );
309 
310  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
311  {
312  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
313  continue;
314 
315  LIB_ID libId;
316 
317  libId.SetLibItemName( m_new_name, false );
318  each_component->SetLibId( libId );
319  each_component->ClearFlags();
320  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
321  }
322 
323  return true;
324 }
325 
326 
328  const LIB_ID& aRequestedId,
329  const LIB_ID& aNewId,
330  LIB_PART* aCacheCandidate,
331  LIB_PART* aLibCandidate ) : RESCUE_CANDIDATE()
332 {
333  m_requested_id = aRequestedId;
334  m_requested_name = aRequestedId.Format();
335  m_new_id = aNewId;
336  m_lib_candidate = aLibCandidate;
337  m_cache_candidate = aCacheCandidate;
338 }
339 
340 
342 {
345 }
346 
347 
349  RESCUER& aRescuer,
350  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
351 {
352  typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
353 
354  candidate_map_t candidate_map;
355 
356  // Remember the list of components is sorted by LIB_ID.
357  // So a search in libraries is made only once by group
358  LIB_PART* cache_match = nullptr;
359  LIB_PART* lib_match = nullptr;
360  LIB_ID old_part_id;
361 
362  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
363  {
364  const LIB_ID& part_id = each_component->GetLibId();
365 
366  if( old_part_id != part_id )
367  {
368  // A new part name is found (a new group starts here).
369  // Search the symbol names candidates only once for this group:
370  old_part_id = part_id;
371 
372  // Get the library symbol from the cache library. It will be a flattened
373  // symbol by default (no inheritance).
374  cache_match = find_component( part_id.Format().wx_str(), aRescuer.GetPrj()->SchLibs(),
375  true );
376 
377  // Get the library symbol from the symbol library table.
378  lib_match = SchGetLibPart( part_id, aRescuer.GetPrj()->SchSymbolLibTable() );
379 
380  if( !cache_match && !lib_match )
381  continue;
382 
383  PART_SPTR lib_match_parent;
384 
385  // If it's a derive symbol, use the parent symbol to perform the pin test.
386  if( lib_match && lib_match->IsAlias() )
387  {
388  lib_match_parent = lib_match->GetParent().lock();
389 
390  if( !lib_match_parent )
391  {
392  lib_match = nullptr;
393  }
394  else
395  {
396  lib_match = lib_match_parent.get();
397  }
398  }
399 
400  // Test whether there is a conflict or if the symbol can only be found in the cache.
401  if( LIB_ID::HasIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH ) == -1 )
402  {
403  if( cache_match && lib_match &&
404  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
405  continue;
406 
407  if( !cache_match && lib_match )
408  continue;
409  }
410 
411  // Fix illegal LIB_ID name characters.
412  wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH );
413 
414  // Differentiate symbol name in the rescue library by appending the symbol library
415  // table nickname to the symbol name to prevent name clashes in the rescue library.
416  wxString libNickname = GetRescueLibraryFileName().GetName();
417 
418  // Spaces in the file name will break the symbol name because they are not
419  // quoted in the symbol library file format.
420  libNickname.Replace( " ", "-" );
421  LIB_ID new_id( libNickname, new_name + "-" + part_id.GetLibNickname().wx_str() );
422 
423  RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match );
424 
425  candidate_map[part_id] = candidate;
426  }
427  }
428 
429  // Now, dump the map into aCandidates
430  for( const candidate_map_t::value_type& each_pair : candidate_map )
431  {
432  aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
433  }
434 }
435 
436 
438 {
439  wxString action;
440 
442  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
443  "the cache." ), m_requested_id.GetLibItemName().wx_str() );
444  else if( m_cache_candidate && !m_lib_candidate )
445  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
447  else
448  action.Printf( _( "Rescue modified symbol %s to %s" ),
450 
451  return action;
452 }
453 
454 
456 {
458 
459  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
460 
461  LIB_PART new_part( *tmp );
462  new_part.SetLibId( m_new_id );
463  new_part.SetName( m_new_id.GetLibItemName() );
464  aRescuer->AddPart( &new_part );
465 
466  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
467  {
468  if( each_component->GetLibId() != m_requested_id )
469  continue;
470 
471  each_component->SetLibId( m_new_id );
472  each_component->ClearFlags();
473  aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
474  }
475 
476  return true;
477 }
478 
479 
480 RESCUER::RESCUER( PROJECT& aProject, SCH_SHEET_PATH* aCurrentSheet,
481  EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType )
482 {
484  m_prj = &aProject;
485  m_currentSheet = aCurrentSheet;
486  m_galBackEndType = aGalBackEndType;
487 }
488 
489 
490 void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
491  const wxString &aNewName )
492 {
493  RESCUE_LOG logitem;
494  logitem.component = aComponent;
495  logitem.old_name = aOldName;
496  logitem.new_name = aNewName;
497  m_rescue_log.push_back( logitem );
498 }
499 
500 
502 {
503  for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
504  {
505  if( ! each_candidate->PerformAction( this ) )
506  return false;
507  }
508 
509  return true;
510 }
511 
512 
514 {
515  for( RESCUE_LOG& each_logitem : m_rescue_log )
516  {
517  LIB_ID libId;
518 
519  libId.SetLibItemName( each_logitem.old_name, false );
520  each_logitem.component->SetLibId( libId );
521  each_logitem.component->ClearFlags();
522  }
523 }
524 
525 
526 bool SCH_EDIT_FRAME::RescueLegacyProject( bool aRunningOnDemand )
527 {
528  LEGACY_RESCUER rescuer( Prj(), &GetCurrentSheet(), GetCanvas()->GetBackend() );
529 
530  return rescueProject( rescuer, aRunningOnDemand );
531 }
532 
533 
534 bool SCH_EDIT_FRAME::RescueSymbolLibTableProject( bool aRunningOnDemand )
535 {
536  SYMBOL_LIB_TABLE_RESCUER rescuer( Prj(), &GetCurrentSheet(), GetCanvas()->GetBackend() );
537 
538  return rescueProject( rescuer, aRunningOnDemand );
539 }
540 
541 
542 bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
543 {
544  if( !RESCUER::RescueProject( this, aRescuer, aRunningOnDemand ) )
545  return false;
546 
547  if( aRescuer.GetCandidateCount() )
548  {
549  LIB_VIEW_FRAME* viewer = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
550 
551  if( viewer )
552  viewer->ReCreateListLib();
553 
554  if( aRunningOnDemand )
555  {
556  SCH_SCREENS schematic;
557 
558  schematic.UpdateSymbolLinks( true );
561  }
562 
563  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
564  SyncView();
565  GetCanvas()->Refresh();
566  OnModify();
567  }
568 
569  return true;
570 }
571 
572 
573 bool RESCUER::RescueProject( wxWindow* aParent, RESCUER& aRescuer, bool aRunningOnDemand )
574 {
575  aRescuer.FindCandidates();
576 
577  if( !aRescuer.GetCandidateCount() )
578  {
579  if( aRunningOnDemand )
580  {
581  wxMessageDialog dlg( aParent, _( "This project has nothing to rescue." ),
582  _( "Project Rescue Helper" ) );
583  dlg.ShowModal();
584  }
585 
586  return true;
587  }
588 
589  aRescuer.RemoveDuplicates();
590  aRescuer.InvokeDialog( aParent, !aRunningOnDemand );
591 
592  // If no symbols were rescued, let the user know what's going on. He might
593  // have clicked cancel by mistake, and should have some indication of that.
594  if( !aRescuer.GetChosenCandidateCount() )
595  {
596  wxMessageDialog dlg( aParent, _( "No symbols were rescued." ),
597  _( "Project Rescue Helper" ) );
598  dlg.ShowModal();
599 
600  // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
601  // this point, due to the reloading of the symbols, so we'll make the save button active.
602  return true;
603  }
604 
605  aRescuer.OpenRescueLibrary();
606 
607  if( !aRescuer.DoRescues() )
608  {
609  aRescuer.UndoRescues();
610  return false;
611  }
612 
613  aRescuer.WriteRescueLibrary( aParent );
614 
615  return true;
616 }
617 
618 
620 {
621  std::vector<wxString> names_seen;
622 
623  for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
624  it != m_all_candidates.end(); )
625  {
626  bool seen_already = false;
627 
628  for( wxString& name_seen : names_seen )
629  {
630  if( name_seen == it->GetRequestedName() )
631  {
632  seen_already = true;
633  break;
634  }
635  }
636 
637  if( seen_already )
638  {
639  it = m_all_candidates.erase( it );
640  }
641  else
642  {
643  names_seen.push_back( it->GetRequestedName() );
644  ++it;
645  }
646  }
647 }
648 
649 
651 {
654 }
655 
656 
657 void LEGACY_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
658 {
659  InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
660  m_galBackEndType, aAskShowAgain );
661 }
662 
663 
665 {
666  wxFileName fn = GetRescueLibraryFileName();
667 
668  std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
669 
670  m_rescue_lib = std::move( rescue_lib );
671  m_rescue_lib->EnableBuffering();
672 
673  // If a rescue library already exists copy the contents of that library so we do not
674  // lose an previous rescues.
675  PART_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
676 
677  if( rescueLib )
678  {
679  // For items in the rescue library, aliases are the root symbol.
680  std::vector< LIB_PART* > symbols;
681 
682  rescueLib->GetParts( symbols );
683 
684  for( auto symbol : symbols )
685  {
686  // The LIB_PART copy constructor flattens derived symbols (formerly known as aliases).
687  m_rescue_lib->AddPart( new LIB_PART( *symbol, m_rescue_lib.get() ) );
688  }
689  }
690 }
691 
692 
693 bool LEGACY_RESCUER::WriteRescueLibrary( wxWindow *aParent )
694 {
695  try
696  {
697  m_rescue_lib->Save( false );
698  }
699  catch( ... /* IO_ERROR ioe */ )
700  {
701  wxString msg;
702 
703  msg.Printf( _( "Failed to create symbol library file \"%s\"" ),
704  m_rescue_lib->GetFullFileName() );
705  DisplayError( aParent, msg );
706  return false;
707  }
708 
709  wxArrayString libNames;
710  wxString libPaths;
711 
712  wxString libName = m_rescue_lib->GetName();
713  PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
714 
715  if( !libs )
716  {
717  libs = new PART_LIBS();
719  }
720 
721  try
722  {
723  PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
724 
725  // Make sure the library is not already in the list
726  while( libNames.Index( libName ) != wxNOT_FOUND )
727  libNames.Remove( libName );
728 
729  // Add the library to the top of the list and save.
730  libNames.Insert( libName, 0 );
731  PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
732  }
733  catch( const IO_ERROR& )
734  {
735  // Could not get or save the current libraries.
736  return false;
737  }
738 
739  // Save the old libraries in case there is a problem after clear(). We'll
740  // put them back in.
741  boost::ptr_vector<PART_LIB> libsSave;
742  libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
743 
745 
746  libs = new PART_LIBS();
747 
748  try
749  {
750  libs->LoadAllLibraries( m_prj );
751  }
752  catch( const PARSE_ERROR& )
753  {
754  // Some libraries were not found. There's no point in showing the error,
755  // because it was already shown. Just don't do anything.
756  }
757  catch( const IO_ERROR& )
758  {
759  // Restore the old list
760  libs->clear();
761  libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
762  return false;
763  }
764 
766 
767  // Update the schematic symbol library links since the library list has changed.
768  SCH_SCREENS schematic;
769 
770  schematic.UpdateSymbolLinks();
771 
772  return true;
773 }
774 
775 
777 {
778  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
779 
780  aNewPart->SetLib( m_rescue_lib.get() );
781  m_rescue_lib->AddPart( aNewPart );
782 }
783 
784 
786  SCH_SHEET_PATH* aCurrentSheet,
787  EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType ) :
788  RESCUER( aProject, aCurrentSheet, aGalBackEndType )
789 {
790  m_properties = std::make_unique<PROPERTIES>();
791 }
792 
793 
795 {
797 }
798 
799 
800 void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
801 {
802  InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
803  m_galBackEndType, aAskShowAgain );
804 }
805 
806 
808 {
809  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
810  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
811 }
812 
813 
815 {
816  wxString msg;
817  wxFileName fn = GetRescueLibraryFileName();
818 
819  // If the rescue library already exists in the symbol library table no need save it to add
820  // it to the table.
821  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
822  {
823  try
824  {
825  m_pi->SaveLibrary( fn.GetFullPath() );
826  }
827  catch( const IO_ERROR& ioe )
828  {
829  msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
830  DisplayErrorMessage( aParent, msg, ioe.What() );
831  return false;
832  }
833 
834  wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
835  wxString libNickname = fn.GetName();
836 
837  // Spaces in the file name will break the symbol name because they are not
838  // quoted in the symbol library file format.
839  libNickname.Replace( " ", "-" );
840 
841  SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri,
842  wxString( "Legacy" ) );
843  m_prj->SchSymbolLibTable()->InsertRow( row );
844 
846 
847  try
848  {
849  m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
850  }
851  catch( const IO_ERROR& ioe )
852  {
853  msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
854  DisplayErrorMessage( aParent, msg, ioe.What() );
855  return false;
856  }
857  }
858 
859  // Relaod the symbol library table.
861 
862  // This can only happen if the symbol library table file was currupted on write.
863  if( !m_prj->SchSymbolLibTable() )
864  return false;
865 
866  // Update the schematic symbol library links since the library list has changed.
867  SCH_SCREENS schematic;
868 
869  schematic.UpdateSymbolLinks( true );
870  return true;
871 }
872 
873 
875 {
876  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
877 
878  wxFileName fn = GetRescueLibraryFileName();
879 
880  try
881  {
882  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
883  m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
884  else
885  m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
886  }
887  catch( ... /* IO_ERROR */ )
888  {
889  }
890 }
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:239
EDA_DRAW_PANEL_GAL::GAL_TYPE m_galBackEndType
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
void SetLib(PART_LIB *aLibrary)
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.
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.
const wxString & GetFileName() const
Definition: sch_screen.h:157
virtual void FindCandidates()=0
Populate the RESCUER with all possible candidates.
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
RESCUER(PROJECT &aProject, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackeEndType)
SCH_SCREEN * GetNext()
Definition: sch_screen.cpp:970
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...
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
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
PROJECT holds project specific data.
Definition: project.h:59
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
PROJECT * GetPrj()
Return the #SCH_PROJECT object for access to the symbol libraries.
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generates the connection data for the entire schematic hierarchy.
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it.
This file is part of the common library.
virtual void OpenRescueLibrary() override
static int HasIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType)
Examine aLibItemName for invalid LIB_ID item name characters.
Definition: lib_id.cpp:336
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.
static void get_components(std::vector< SCH_COMPONENT * > &aComponents)
Fill a vector with all of the project's symbols, to ease iterating over them.
void set(SCH_PLUGIN *aPlugin)
Definition: sch_io_mgr.h:544
VTBL_ENTRY _ELEM * GetElem(ELEM_T aIndex)
Typically wrapped somewhere else in a more meaningful function wrapper.
Definition: project.cpp:232
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
CONNECTION_GRAPH * g_ConnectionGraph
This also wants to live in the eventual SCHEMATIC object.
SCH_SCREEN * GetScreen()
Definition: sch_sheet.h:282
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
Symbol library viewer main window.
LIB_PART * m_lib_candidate
SCH_COMPONENT * component
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:244
boost::ptr_vector< RESCUE_CANDIDATE > m_all_candidates
void RemoveDuplicates()
Filter out duplicately named rescue candidates.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
static bool RescueProject(wxWindow *aParent, RESCUER &aRescuer, bool aRunningOnDemand)
SCH_SHEET_PATH * m_currentSheet
#define NULL
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:341
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CACHE_CANDIDATE objectss into a vector.
void SyncView()
Mark all items for refresh.
const std::string SchematicLibraryFileExtension
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
std::shared_ptr< LIB_PART > PART_SPTR
shared pointer to LIB_PART
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
SCH_SHEET_PATH & GetCurrentSheet()
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()
std::unique_ptr< PROPERTIES > m_properties
Library plugin properties.
Define a library symbol object.
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:97
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.
SCH_SHEET_PATH.
UTF8 Format() const
Definition: lib_id.cpp:237
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=NULL) override
Update the board display after modifying it by a python script (note: it is automatically called by a...
int SetLibItemName(const UTF8 &aLibItemName, bool aTestForRev=true)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition: lib_id.cpp:206
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
Struct PARSE_ERROR contains a filename or source description, a problem input line,...
Definition: ki_exception.h:123
static wxFileName GetRescueLibraryFileName()
virtual bool WriteRescueLibrary(wxWindow *aParent) override
Writes out the rescue library.
std::unique_ptr< PART_LIB > m_rescue_lib
void UpdateSymbolLinks(bool aForce=false)
Initialize or reinitialize the weak reference to the LIB_PART for each SCH_COMPONENT found in the ful...
virtual void OpenRescueLibrary() override
bool DoRescues()
Perform all chosen rescue actions, logging them to be undone if necessary.
#define _(s)
Definition: 3d_actions.cpp:33
wxString wx_str() const
Definition: utf8.cpp:51
SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:99
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.
bool RescueSymbolLibTableProject(bool aRunningOnDemand)
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.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType, bool aLib=false)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:352
wxString m_requested_name
virtual void InvokeDialog(wxWindow *aParent, bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
virtual void SetName(const wxString &aName)
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.
SCH_SCREEN * GetFirst()
Definition: sch_screen.cpp:959
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
SCH_SHEET * g_RootSheet
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CASE_CANDIDATE objects into a vector.
virtual void ClearUndoORRedoList(UNDO_REDO_CONTAINER &aList, int aItemCount=-1) override
Free the undo or redo list from aList element.
Definition: sch_screen.cpp:627
Definition for part library class.
virtual void AddPart(LIB_PART *aNewPart) override
void UndoRescues()
Reverse the effects of all rescues on the project.
bool RescueLegacyProject(bool aRunningOnDemand)
void clear()
Definition: utf8.h:113
bool ReCreateListLib()
Creates or recreates a sorted list of currently loaded libraries.
const LIB_ID & GetLibId() const
Object used to load, save, search, and otherwise manipulate symbol library files.
void SetLibId(const LIB_ID &aLibId)
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
SYMBOL_LIB_TABLE_RESCUER(PROJECT &aProject, SCH_SHEET_PATH *aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackeEndType)
wxString new_name
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:491
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
bool rescueProject(RESCUER &aRescuer, bool aRunningOnDemand)
Perform rescue operations to recover old projects from before certain changes were made.