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 <project_rescue.h>
32 #include <sch_component.h>
33 #include <sch_sheet.h>
34 #include <sch_edit_frame.h>
35 #include <symbol_lib_table.h>
36 #include <viewlib_frame.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( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
70  {
71  if( item->Type() != SCH_COMPONENT_T )
72  continue;
73 
74  SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
75  aComponents.push_back( component );
76  }
77  }
78 
79  if( aComponents.empty() )
80  return;
81 
82  // sort aComponents by lib part. Components will be grouped by same lib part.
83  std::sort( aComponents.begin(), aComponents.end(), sort_by_libid );
84 }
85 
86 
94 static LIB_PART* find_component( const wxString& aName, PART_LIBS* aLibs, bool aCached )
95 {
96  LIB_PART *part = NULL;
97  wxString new_name = LIB_ID::FixIllegalChars( aName, LIB_ID::ID_SCH );
98 
99  for( PART_LIB& each_lib : *aLibs )
100  {
101  if( aCached && !each_lib.IsCache() )
102  continue;
103 
104  if( !aCached && each_lib.IsCache() )
105  continue;
106 
107  part = each_lib.FindPart( new_name );
108 
109  if( part )
110  break;
111  }
112 
113  return part;
114 }
115 
116 
117 static wxFileName GetRescueLibraryFileName()
118 {
119  wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
120  fn.SetName( fn.GetName() + wxT( "-rescue" ) );
121  fn.SetExt( SchematicLibraryFileExtension );
122  return fn;
123 }
124 
125 
126 RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName,
127  const wxString& aNewName,
128  LIB_PART* aLibCandidate )
129 {
130  m_requested_name = aRequestedName;
131  m_new_name = aNewName;
132  m_lib_candidate = aLibCandidate;
133 }
134 
135 
137  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
138 {
139  typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
140  candidate_map_t candidate_map;
141  // Remember the list of components is sorted by part name.
142  // So a search in libraries is made only once by group
143  LIB_PART* case_sensitive_match = nullptr;
144  std::vector<LIB_PART*> case_insensitive_matches;
145 
146  wxString last_part_name;
147 
148  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
149  {
150  wxString part_name = each_component->GetLibId().GetLibItemName();
151 
152  if( last_part_name != part_name )
153  {
154  // A new part name is found (a new group starts here).
155  // Search the symbol names candidates only once for this group:
156  last_part_name = part_name;
157  case_insensitive_matches.clear();
158 
159  LIB_ID id( wxEmptyString, part_name );
160 
161  case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibPart( id );
162 
163  if( !case_sensitive_match )
164  // the case sensitive match failed. Try a case insensitive match
165  aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
166  part_name );
167  }
168 
169  if( case_sensitive_match || !( case_insensitive_matches.size() ) )
170  continue;
171 
172  RESCUE_CASE_CANDIDATE candidate( part_name, case_insensitive_matches[0]->GetName(),
173  case_insensitive_matches[0] );
174 
175  candidate_map[part_name] = candidate;
176  }
177 
178  // Now, dump the map into aCandidates
179  for( const candidate_map_t::value_type& each_pair : candidate_map )
180  {
181  aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
182  }
183 }
184 
185 
187 {
188  wxString action;
189  action.Printf( _( "Rename to %s" ), m_new_name );
190  return action;
191 }
192 
193 
195 {
196  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
197  {
198  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
199  continue;
200 
201  LIB_ID libId;
202 
203  libId.SetLibItemName( m_new_name, false );
204  each_component->SetLibId( libId );
205  each_component->ClearFlags();
206  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
207  }
208 
209  return true;
210 }
211 
212 
213 RESCUE_CACHE_CANDIDATE::RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName,
214  const wxString& aNewName,
215  LIB_PART* aCacheCandidate,
216  LIB_PART* aLibCandidate )
217 {
218  m_requested_name = aRequestedName;
219  m_new_name = aNewName;
220  m_cache_candidate = aCacheCandidate;
221  m_lib_candidate = aLibCandidate;
222 }
223 
224 
226 {
227  m_cache_candidate = NULL;
228  m_lib_candidate = NULL;
229 }
230 
231 
233  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
234 {
235  typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
236  candidate_map_t candidate_map;
237 
238  // Remember the list of components is sorted by part name.
239  // So a search in libraries is made only once by group
240  LIB_PART* cache_match = nullptr;
241  LIB_PART* lib_match = nullptr;
242  wxString old_part_name;
243 
244  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
245  {
246  wxString part_name = each_component->GetLibId().GetLibItemName();
247 
248  if( old_part_name != part_name )
249  {
250  // A new part name is found (a new group starts here).
251  // Search the symbol names candidates only once for this group:
252  old_part_name = part_name;
253  cache_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), true );
254  lib_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), false );
255 
256  if( !cache_match && !lib_match )
257  continue;
258 
259  // Test whether there is a conflict or if the symbol can only be found in the cache
260  // and the symbol name does not have any illegal characters.
261  if( LIB_ID::HasIllegalChars( part_name, LIB_ID::ID_SCH ) == -1 )
262  {
263  if( cache_match && lib_match &&
264  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
265  continue;
266 
267  if( !cache_match && lib_match )
268  continue;
269  }
270 
271  // Check if the symbol has already been rescued.
272  wxString new_name = LIB_ID::FixIllegalChars( part_name, LIB_ID::ID_SCH );
273 
274  RESCUE_CACHE_CANDIDATE candidate( part_name, new_name, cache_match, lib_match );
275 
276  candidate_map[part_name] = candidate;
277  }
278  }
279 
280  // Now, dump the map into aCandidates
281  for( const candidate_map_t::value_type& each_pair : candidate_map )
282  {
283  aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
284  }
285 }
286 
287 
289 {
290  wxString action;
291 
293  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
294  "the cache." ), m_requested_name );
295  else if( m_cache_candidate && !m_lib_candidate )
296  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
298  else
299  action.Printf( _( "Rescue modified symbol %s to %s" ),
301 
302  return action;
303 }
304 
305 
307 {
309 
310  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
311 
312  LIB_PART new_part( *tmp );
313  new_part.SetName( m_new_name );
314  aRescuer->AddPart( &new_part );
315 
316  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
317  {
318  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
319  continue;
320 
321  LIB_ID libId;
322 
323  libId.SetLibItemName( m_new_name, false );
324  each_component->SetLibId( libId );
325  each_component->ClearFlags();
326  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
327  }
328 
329  return true;
330 }
331 
332 
334  const LIB_ID& aRequestedId,
335  const LIB_ID& aNewId,
336  LIB_PART* aCacheCandidate,
337  LIB_PART* aLibCandidate ) : RESCUE_CANDIDATE()
338 {
339  m_requested_id = aRequestedId;
340  m_requested_name = aRequestedId.Format();
341  m_new_id = aNewId;
342  m_lib_candidate = aLibCandidate;
343  m_cache_candidate = aCacheCandidate;
344 }
345 
346 
348 {
349  m_cache_candidate = NULL;
350  m_lib_candidate = NULL;
351 }
352 
353 
355  RESCUER& aRescuer,
356  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
357 {
358  typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
359 
360  candidate_map_t candidate_map;
361 
362  // Remember the list of components is sorted by LIB_ID.
363  // So a search in libraries is made only once by group
364  LIB_PART* cache_match = nullptr;
365  LIB_PART* lib_match = nullptr;
366  LIB_ID old_part_id;
367 
368  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
369  {
370  const LIB_ID& part_id = each_component->GetLibId();
371 
372  if( old_part_id != part_id )
373  {
374  // A new part name is found (a new group starts here).
375  // Search the symbol names candidates only once for this group:
376  old_part_id = part_id;
377 
378  // Get the library symbol from the cache library. It will be a flattened
379  // symbol by default (no inheritance).
380  cache_match = find_component( part_id.Format().wx_str(), aRescuer.GetPrj()->SchLibs(),
381  true );
382 
383  // Get the library symbol from the symbol library table.
384  lib_match = SchGetLibPart( part_id, aRescuer.GetPrj()->SchSymbolLibTable() );
385 
386  if( !cache_match && !lib_match )
387  continue;
388 
389  PART_SPTR lib_match_parent;
390 
391  // If it's a derive symbol, use the parent symbol to perform the pin test.
392  if( lib_match && lib_match->IsAlias() )
393  {
394  lib_match_parent = lib_match->GetParent().lock();
395 
396  if( !lib_match_parent )
397  {
398  lib_match = nullptr;
399  }
400  else
401  {
402  lib_match = lib_match_parent.get();
403  }
404  }
405 
406  // Test whether there is a conflict or if the symbol can only be found in the cache.
407  if( LIB_ID::HasIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH ) == -1 )
408  {
409  if( cache_match && lib_match &&
410  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
411  continue;
412 
413  if( !cache_match && lib_match )
414  continue;
415  }
416 
417  // Fix illegal LIB_ID name characters.
418  wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH );
419 
420  // Differentiate symbol name in the rescue library by appending the symbol library
421  // table nickname to the symbol name to prevent name clashes in the rescue library.
422  wxString libNickname = GetRescueLibraryFileName().GetName();
423 
424  // Spaces in the file name will break the symbol name because they are not
425  // quoted in the symbol library file format.
426  libNickname.Replace( " ", "-" );
427  LIB_ID new_id( libNickname, new_name + "-" + part_id.GetLibNickname().wx_str() );
428 
429  RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match );
430 
431  candidate_map[part_id] = candidate;
432  }
433  }
434 
435  // Now, dump the map into aCandidates
436  for( const candidate_map_t::value_type& each_pair : candidate_map )
437  {
438  aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
439  }
440 }
441 
442 
444 {
445  wxString action;
446 
448  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
449  "the cache." ), m_requested_id.GetLibItemName().wx_str() );
450  else if( m_cache_candidate && !m_lib_candidate )
451  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
453  else
454  action.Printf( _( "Rescue modified symbol %s to %s" ),
456 
457  return action;
458 }
459 
460 
462 {
464 
465  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
466 
467  LIB_PART new_part( *tmp );
468  new_part.SetLibId( m_new_id );
469  new_part.SetName( m_new_id.GetLibItemName() );
470  aRescuer->AddPart( &new_part );
471 
472  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
473  {
474  if( each_component->GetLibId() != m_requested_id )
475  continue;
476 
477  each_component->SetLibId( m_new_id );
478  each_component->ClearFlags();
479  aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
480  }
481 
482  return true;
483 }
484 
485 
486 RESCUER::RESCUER( PROJECT& aProject, SCH_SHEET_PATH* aCurrentSheet,
487  EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType )
488 {
490  m_prj = &aProject;
491  m_currentSheet = aCurrentSheet;
492  m_galBackEndType = aGalBackEndType;
493 }
494 
495 
496 void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
497  const wxString &aNewName )
498 {
499  RESCUE_LOG logitem;
500  logitem.component = aComponent;
501  logitem.old_name = aOldName;
502  logitem.new_name = aNewName;
503  m_rescue_log.push_back( logitem );
504 }
505 
506 
508 {
509  for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
510  {
511  if( ! each_candidate->PerformAction( this ) )
512  return false;
513  }
514 
515  return true;
516 }
517 
518 
520 {
521  for( RESCUE_LOG& each_logitem : m_rescue_log )
522  {
523  LIB_ID libId;
524 
525  libId.SetLibItemName( each_logitem.old_name, false );
526  each_logitem.component->SetLibId( libId );
527  each_logitem.component->ClearFlags();
528  }
529 }
530 
531 
532 bool SCH_EDIT_FRAME::RescueLegacyProject( bool aRunningOnDemand )
533 {
534  LEGACY_RESCUER rescuer( Prj(), &GetCurrentSheet(), GetCanvas()->GetBackend() );
535 
536  return rescueProject( rescuer, aRunningOnDemand );
537 }
538 
539 
540 bool SCH_EDIT_FRAME::RescueSymbolLibTableProject( bool aRunningOnDemand )
541 {
542  SYMBOL_LIB_TABLE_RESCUER rescuer( Prj(), &GetCurrentSheet(), GetCanvas()->GetBackend() );
543 
544  return rescueProject( rescuer, aRunningOnDemand );
545 }
546 
547 
548 bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
549 {
550  if( !RESCUER::RescueProject( this, aRescuer, aRunningOnDemand ) )
551  return false;
552 
553  if( aRescuer.GetCandidateCount() )
554  {
555  LIB_VIEW_FRAME* viewer = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
556 
557  if( viewer )
558  viewer->ReCreateListLib();
559 
560  if( aRunningOnDemand )
561  {
562  SCH_SCREENS schematic;
563 
564  schematic.UpdateSymbolLinks( true );
567  }
568 
569  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
570  SyncView();
571  GetCanvas()->Refresh();
572  OnModify();
573  }
574 
575  return true;
576 }
577 
578 
579 bool RESCUER::RescueProject( wxWindow* aParent, RESCUER& aRescuer, bool aRunningOnDemand )
580 {
581  aRescuer.FindCandidates();
582 
583  if( !aRescuer.GetCandidateCount() )
584  {
585  if( aRunningOnDemand )
586  {
587  wxMessageDialog dlg( aParent, _( "This project has nothing to rescue." ),
588  _( "Project Rescue Helper" ) );
589  dlg.ShowModal();
590  }
591 
592  return true;
593  }
594 
595  aRescuer.RemoveDuplicates();
596  aRescuer.InvokeDialog( aParent, !aRunningOnDemand );
597 
598  // If no symbols were rescued, let the user know what's going on. He might
599  // have clicked cancel by mistake, and should have some indication of that.
600  if( !aRescuer.GetChosenCandidateCount() )
601  {
602  wxMessageDialog dlg( aParent, _( "No symbols were rescued." ),
603  _( "Project Rescue Helper" ) );
604  dlg.ShowModal();
605 
606  // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
607  // this point, due to the reloading of the symbols, so we'll make the save button active.
608  return true;
609  }
610 
611  aRescuer.OpenRescueLibrary();
612 
613  if( !aRescuer.DoRescues() )
614  {
615  aRescuer.UndoRescues();
616  return false;
617  }
618 
619  aRescuer.WriteRescueLibrary( aParent );
620 
621  return true;
622 }
623 
624 
626 {
627  std::vector<wxString> names_seen;
628 
629  for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
630  it != m_all_candidates.end(); )
631  {
632  bool seen_already = false;
633 
634  for( wxString& name_seen : names_seen )
635  {
636  if( name_seen == it->GetRequestedName() )
637  {
638  seen_already = true;
639  break;
640  }
641  }
642 
643  if( seen_already )
644  {
645  it = m_all_candidates.erase( it );
646  }
647  else
648  {
649  names_seen.push_back( it->GetRequestedName() );
650  ++it;
651  }
652  }
653 }
654 
655 
657 {
660 }
661 
662 
663 void LEGACY_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
664 {
665  InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
666  m_galBackEndType, aAskShowAgain );
667 }
668 
669 
671 {
672  wxFileName fn = GetRescueLibraryFileName();
673 
674  std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
675 
676  m_rescue_lib = std::move( rescue_lib );
677  m_rescue_lib->EnableBuffering();
678 
679  // If a rescue library already exists copy the contents of that library so we do not
680  // lose an previous rescues.
681  PART_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
682 
683  if( rescueLib )
684  {
685  // For items in the rescue library, aliases are the root symbol.
686  std::vector< LIB_PART* > symbols;
687 
688  rescueLib->GetParts( symbols );
689 
690  for( auto symbol : symbols )
691  {
692  // The LIB_PART copy constructor flattens derived symbols (formerly known as aliases).
693  m_rescue_lib->AddPart( new LIB_PART( *symbol, m_rescue_lib.get() ) );
694  }
695  }
696 }
697 
698 
699 bool LEGACY_RESCUER::WriteRescueLibrary( wxWindow *aParent )
700 {
701  try
702  {
703  m_rescue_lib->Save( false );
704  }
705  catch( ... /* IO_ERROR ioe */ )
706  {
707  wxString msg;
708 
709  msg.Printf( _( "Failed to create symbol library file \"%s\"" ),
710  m_rescue_lib->GetFullFileName() );
711  DisplayError( aParent, msg );
712  return false;
713  }
714 
715  wxArrayString libNames;
716  wxString libPaths;
717 
718  wxString libName = m_rescue_lib->GetName();
719  PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
720 
721  if( !libs )
722  {
723  libs = new PART_LIBS();
725  }
726 
727  try
728  {
729  PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
730 
731  // Make sure the library is not already in the list
732  while( libNames.Index( libName ) != wxNOT_FOUND )
733  libNames.Remove( libName );
734 
735  // Add the library to the top of the list and save.
736  libNames.Insert( libName, 0 );
737  PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
738  }
739  catch( const IO_ERROR& )
740  {
741  // Could not get or save the current libraries.
742  return false;
743  }
744 
745  // Save the old libraries in case there is a problem after clear(). We'll
746  // put them back in.
747  boost::ptr_vector<PART_LIB> libsSave;
748  libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
749 
751 
752  libs = new PART_LIBS();
753 
754  try
755  {
756  libs->LoadAllLibraries( m_prj );
757  }
758  catch( const PARSE_ERROR& )
759  {
760  // Some libraries were not found. There's no point in showing the error,
761  // because it was already shown. Just don't do anything.
762  }
763  catch( const IO_ERROR& )
764  {
765  // Restore the old list
766  libs->clear();
767  libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
768  return false;
769  }
770 
772 
773  // Update the schematic symbol library links since the library list has changed.
774  SCH_SCREENS schematic;
775 
776  schematic.UpdateSymbolLinks();
777 
778  return true;
779 }
780 
781 
783 {
784  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
785 
786  aNewPart->SetLib( m_rescue_lib.get() );
787  m_rescue_lib->AddPart( aNewPart );
788 }
789 
790 
792  SCH_SHEET_PATH* aCurrentSheet,
793  EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType ) :
794  RESCUER( aProject, aCurrentSheet, aGalBackEndType )
795 {
796  m_properties = std::make_unique<PROPERTIES>();
797 }
798 
799 
801 {
803 }
804 
805 
806 void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( wxWindow* aParent, bool aAskShowAgain )
807 {
808  InvokeDialogRescueEach( aParent, static_cast< RESCUER& >( *this ), m_currentSheet,
809  m_galBackEndType, aAskShowAgain );
810 }
811 
812 
814 {
815  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
816  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
817 }
818 
819 
821 {
822  wxString msg;
823  wxFileName fn = GetRescueLibraryFileName();
824 
825  // If the rescue library already exists in the symbol library table no need save it to add
826  // it to the table.
827  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
828  {
829  try
830  {
831  m_pi->SaveLibrary( fn.GetFullPath() );
832  }
833  catch( const IO_ERROR& ioe )
834  {
835  msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
836  DisplayErrorMessage( aParent, msg, ioe.What() );
837  return false;
838  }
839 
840  wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
841  wxString libNickname = fn.GetName();
842 
843  // Spaces in the file name will break the symbol name because they are not
844  // quoted in the symbol library file format.
845  libNickname.Replace( " ", "-" );
846 
847  SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri,
848  wxString( "Legacy" ) );
849  m_prj->SchSymbolLibTable()->InsertRow( row );
850 
852 
853  try
854  {
855  m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
856  }
857  catch( const IO_ERROR& ioe )
858  {
859  msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
860  DisplayErrorMessage( aParent, msg, ioe.What() );
861  return false;
862  }
863  }
864 
865  // Relaod the symbol library table.
867 
868  // This can only happen if the symbol library table file was currupted on write.
869  if( !m_prj->SchSymbolLibTable() )
870  return false;
871 
872  // Update the schematic symbol library links since the library list has changed.
873  SCH_SCREENS schematic;
874 
875  schematic.UpdateSymbolLinks( true );
876  return true;
877 }
878 
879 
881 {
882  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
883 
884  wxFileName fn = GetRescueLibraryFileName();
885 
886  try
887  {
888  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
889  m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
890  else
891  m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
892  }
893  catch( ... /* IO_ERROR */ )
894  {
895  }
896 }
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:236
EDA_DRAW_PANEL_GAL::GAL_TYPE m_galBackEndType
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
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:123
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:994
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
Class PROJECT holds project specific data.
Definition: project.h:58
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:249
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.
SCH_ITEM * Next() const
Definition: sch_item.h:153
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:525
VTBL_ENTRY _ELEM * GetElem(ELEM_T aIndex)
Typically wrapped somewhere else in a more meaningful function wrapper.
Definition: project.cpp:205
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:281
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
Symbol library viewer main window.
Definition: viewlib_frame.h:42
LIB_PART * m_lib_candidate
SCH_COMPONENT * component
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:217
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
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:47
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.
Class SCH_SHEET_PATH.
#define _(s)
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.
wxString wx_str() const
Definition: utf8.cpp:51
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:73
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:983
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...
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:597
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
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
Definition: sch_item.h:114
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.