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-2018 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 <invoke_sch_dialog.h>
29 #include <kicad_device_context.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_ALIAS* case_sensitive_match = nullptr;
144  std::vector<LIB_ALIAS*> 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()->FindLibraryAlias( 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]->GetPart() );
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 
292  if( !m_cache_candidate && !m_lib_candidate )
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 {
308  LIB_PART* tmp = ( m_cache_candidate ) ? m_cache_candidate : m_lib_candidate;
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  new_part.RemoveAllAliases();
315  aRescuer->AddPart( &new_part );
316 
317  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
318  {
319  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
320  continue;
321 
322  LIB_ID libId;
323 
324  libId.SetLibItemName( m_new_name, false );
325  each_component->SetLibId( libId );
326  each_component->ClearFlags();
327  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
328  }
329 
330  return true;
331 }
332 
333 
335  const LIB_ID& aRequestedId,
336  const LIB_ID& aNewId,
337  LIB_PART* aCacheCandidate,
338  LIB_PART* aLibCandidate ) : RESCUE_CANDIDATE()
339 {
340  m_requested_id = aRequestedId;
341  m_requested_name = aRequestedId.Format();
342  m_new_id = aNewId;
343  m_lib_candidate = aLibCandidate;
344  m_cache_candidate = aCacheCandidate;
345 }
346 
347 
349 {
350  m_cache_candidate = NULL;
351  m_lib_candidate = NULL;
352 }
353 
354 
356  RESCUER& aRescuer,
357  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
358 {
359  typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
360 
361  candidate_map_t candidate_map;
362 
363  // Remember the list of components is sorted by LIB_ID.
364  // So a search in libraries is made only once by group
365  LIB_PART* cache_match = nullptr;
366  LIB_PART* lib_match = nullptr;
367  LIB_ID old_part_id;
368 
369  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
370  {
371  LIB_ID part_id = each_component->GetLibId();
372 
373  if( old_part_id != part_id )
374  {
375  // A new part name is found (a new group starts here).
376  // Search the symbol names candidates only once for this group:
377  old_part_id = part_id;
378  cache_match = find_component( part_id.Format().wx_str(), aRescuer.GetPrj()->SchLibs(),
379  true );
380 
381  lib_match = aRescuer.GetFrame()->GetLibPart( part_id );
382 
383  if( !cache_match && !lib_match )
384  continue;
385 
386  // Test whether there is a conflict or if the symbol can only be found in the cache.
387  if( LIB_ID::HasIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH ) == -1 )
388  {
389  if( cache_match && lib_match &&
390  !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
391  continue;
392 
393  if( !cache_match && lib_match )
394  continue;
395  }
396 
397  // Fix illegal LIB_ID name characters.
398  wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH );
399 
400  // Differentiate symbol name in the rescue library by appending the symbol library
401  // table nickname to the symbol name to prevent name clashes in the rescue library.
402  wxString libNickname = GetRescueLibraryFileName().GetName();
403 
404  // Spaces in the file name will break the symbol name because they are not
405  // quoted in the symbol library file format.
406  libNickname.Replace( " ", "-" );
407  LIB_ID new_id( libNickname, new_name + "-" + part_id.GetLibNickname().wx_str() );
408 
409  RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match );
410 
411  candidate_map[part_id] = candidate;
412  }
413  }
414 
415  // Now, dump the map into aCandidates
416  for( const candidate_map_t::value_type& each_pair : candidate_map )
417  {
418  aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
419  }
420 }
421 
422 
424 {
425  wxString action;
426 
428  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
429  "the cache." ), m_requested_id.GetLibItemName().wx_str() );
430  else if( m_cache_candidate && !m_lib_candidate )
431  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
433  else
434  action.Printf( _( "Rescue modified symbol %s to %s" ),
436 
437  return action;
438 }
439 
440 
442 {
444 
445  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
446 
447  LIB_PART new_part( *tmp );
448  new_part.SetLibId( m_new_id );
449  new_part.SetName( m_new_id.GetLibItemName() );
450  new_part.RemoveAllAliases();
451  aRescuer->AddPart( &new_part );
452 
453  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
454  {
455  if( each_component->GetLibId() != m_requested_id )
456  continue;
457 
458  each_component->SetLibId( m_new_id );
459  each_component->ClearFlags();
460  aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
461  }
462 
463  return true;
464 }
465 
466 
467 RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject )
468 {
469  get_components( m_components );
470  m_prj = &aProject;
471  m_edit_frame = &aEditFrame;
472 }
473 
474 
475 void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
476  const wxString &aNewName )
477 {
478  RESCUE_LOG logitem;
479  logitem.component = aComponent;
480  logitem.old_name = aOldName;
481  logitem.new_name = aNewName;
482  m_rescue_log.push_back( logitem );
483 }
484 
485 
487 {
488  for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
489  {
490  if( ! each_candidate->PerformAction( this ) )
491  return false;
492  }
493 
494  return true;
495 }
496 
497 
499 {
500  for( RESCUE_LOG& each_logitem : m_rescue_log )
501  {
502  LIB_ID libId;
503 
504  libId.SetLibItemName( each_logitem.old_name, false );
505  each_logitem.component->SetLibId( libId );
506  each_logitem.component->ClearFlags();
507  }
508 }
509 
510 
511 bool SCH_EDIT_FRAME::RescueLegacyProject( bool aRunningOnDemand )
512 {
513  LEGACY_RESCUER rescuer( *this, Prj() );
514 
515  return rescueProject( rescuer, aRunningOnDemand );
516 }
517 
518 
519 bool SCH_EDIT_FRAME::RescueSymbolLibTableProject( bool aRunningOnDemand )
520 {
521  SYMBOL_LIB_TABLE_RESCUER rescuer( *this, Prj() );
522 
523  return rescueProject( rescuer, aRunningOnDemand );
524 }
525 
526 
527 bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
528 {
529  aRescuer.FindCandidates();
530 
531  if( ! aRescuer.GetCandidateCount() )
532  {
533  if( aRunningOnDemand )
534  {
535  wxMessageDialog dlg( this, _( "This project has nothing to rescue." ),
536  _( "Project Rescue Helper" ) );
537  dlg.ShowModal();
538  }
539 
540  return true;
541  }
542 
543  aRescuer.RemoveDuplicates();
544 
545  aRescuer.InvokeDialog( !aRunningOnDemand );
546 
547  // If no symbols were rescued, let the user know what's going on. He might
548  // have clicked cancel by mistake, and should have some indication of that.
549  if( !aRescuer.GetChosenCandidateCount() )
550  {
551  wxMessageDialog dlg( this, _( "No symbols were rescued." ),
552  _( "Project Rescue Helper" ) );
553  dlg.ShowModal();
554 
555  // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
556  // this point, due to the reloading of the symbols, so we'll make the save button active.
557  OnModify();
558  return true;
559  }
560 
561  aRescuer.OpenRescueLibrary();
562 
563  if( !aRescuer.DoRescues() )
564  {
565  aRescuer.UndoRescues();
566  return false;
567  }
568 
569  aRescuer.WriteRescueLibrary( this );
570 
571  LIB_VIEW_FRAME* viewer = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
572 
573  if( viewer )
574  viewer->ReCreateListLib();
575 
576  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
577  SyncView();
578  GetCanvas()->Refresh();
579  OnModify();
580 
581  return true;
582 }
583 
584 
586 {
587  std::vector<wxString> names_seen;
588 
589  for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
590  it != m_all_candidates.end(); )
591  {
592  bool seen_already = false;
593 
594  for( wxString& name_seen : names_seen )
595  {
596  if( name_seen == it->GetRequestedName() )
597  {
598  seen_already = true;
599  break;
600  }
601  }
602 
603  if( seen_already )
604  {
605  it = m_all_candidates.erase( it );
606  }
607  else
608  {
609  names_seen.push_back( it->GetRequestedName() );
610  ++it;
611  }
612  }
613 }
614 
615 
617 {
618  RESCUE_CASE_CANDIDATE::FindRescues( *this, m_all_candidates );
619  RESCUE_CACHE_CANDIDATE::FindRescues( *this, m_all_candidates );
620 }
621 
622 
623 void LEGACY_RESCUER::InvokeDialog( bool aAskShowAgain )
624 {
625  InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
626 }
627 
628 
630 {
631  wxFileName fn = GetRescueLibraryFileName();
632 
633  std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
634 
635  m_rescue_lib = std::move( rescue_lib );
636  m_rescue_lib->EnableBuffering();
637 
638  // If a rescue library already exists copy the contents of that library so we do not
639  // lose an previous rescues.
640  PART_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
641 
642  if( rescueLib )
643  {
644  // For items in the rescue library, aliases are the root symbol.
645  std::vector< LIB_ALIAS* > aliases;
646 
647  rescueLib->GetAliases( aliases );
648 
649  for( auto alias : aliases )
650  {
651  LIB_PART* part = alias->GetPart();
652 
653  wxCHECK2( part, continue );
654 
655  m_rescue_lib->AddPart( new LIB_PART( *part, m_rescue_lib.get() ) );
656  }
657  }
658 }
659 
660 
662 {
663  try
664  {
665  m_rescue_lib->Save( false );
666  }
667  catch( ... /* IO_ERROR ioe */ )
668  {
669  wxString msg;
670 
671  msg.Printf( _( "Failed to create symbol library file \"%s\"" ),
672  m_rescue_lib->GetFullFileName() );
673  DisplayError( aEditFrame, msg );
674  return false;
675  }
676 
677  wxArrayString libNames;
678  wxString libPaths;
679 
680  wxString libName = m_rescue_lib->GetName();
681  PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
682 
683  if( !libs )
684  {
685  libs = new PART_LIBS();
686  m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
687  }
688 
689  try
690  {
691  PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
692 
693  // Make sure the library is not already in the list
694  while( libNames.Index( libName ) != wxNOT_FOUND )
695  libNames.Remove( libName );
696 
697  // Add the library to the top of the list and save.
698  libNames.Insert( libName, 0 );
699  PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
700  }
701  catch( const IO_ERROR& )
702  {
703  // Could not get or save the current libraries.
704  return false;
705  }
706 
707  // Save the old libraries in case there is a problem after clear(). We'll
708  // put them back in.
709  boost::ptr_vector<PART_LIB> libsSave;
710  libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
711 
712  m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
713 
714  libs = new PART_LIBS();
715 
716  try
717  {
718  libs->LoadAllLibraries( m_prj );
719  }
720  catch( const PARSE_ERROR& )
721  {
722  // Some libraries were not found. There's no point in showing the error,
723  // because it was already shown. Just don't do anything.
724  }
725  catch( const IO_ERROR& )
726  {
727  // Restore the old list
728  libs->clear();
729  libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
730  return false;
731  }
732 
733  m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
734 
735  // Update the schematic symbol library links since the library list has changed.
736  SCH_SCREENS schematic;
737 
738  schematic.UpdateSymbolLinks();
739 
740  return true;
741 }
742 
743 
745 {
746  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
747 
748  aNewPart->SetLib( m_rescue_lib.get() );
749  m_rescue_lib->AddPart( aNewPart );
750 }
751 
752 
754  PROJECT& aProject ) :
755  RESCUER( aEditFrame, aProject )
756 {
757  m_properties = std::make_unique<PROPERTIES>();
758 }
759 
760 
762 {
764 }
765 
766 
767 void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( bool aAskShowAgain )
768 {
769  InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
770 }
771 
772 
774 {
775  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
776  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
777 }
778 
779 
781 {
782  wxString msg;
783  wxFileName fn = GetRescueLibraryFileName();
784 
785  // If the rescue library already exists in the symbol library table no need save it to add
786  // it to the table.
787  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
788  {
789  try
790  {
791  m_pi->SaveLibrary( fn.GetFullPath() );
792  }
793  catch( const IO_ERROR& ioe )
794  {
795  msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
796  DisplayErrorMessage( aEditFrame, msg, ioe.What() );
797  return false;
798  }
799 
800  wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
801  wxString libNickname = fn.GetName();
802 
803  // Spaces in the file name will break the symbol name because they are not
804  // quoted in the symbol library file format.
805  libNickname.Replace( " ", "-" );
806 
807  SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri,
808  wxString( "Legacy" ) );
809  m_prj->SchSymbolLibTable()->InsertRow( row );
810 
812 
813  try
814  {
815  m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
816  }
817  catch( const IO_ERROR& ioe )
818  {
819  msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
820  DisplayErrorMessage( aEditFrame, msg, ioe.What() );
821  return false;
822  }
823  }
824 
825  // Relaod the symbol library table.
827 
828  // This can only happen if the symbol library table file was currupted on write.
829  if( !m_prj->SchSymbolLibTable() )
830  return false;
831 
832  // Update the schematic symbol library links since the library list has changed.
833  SCH_SCREENS schematic;
834 
835  schematic.UpdateSymbolLinks( true );
836  return true;
837 }
838 
839 
841 {
842  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
843 
844  wxFileName fn = GetRescueLibraryFileName();
845 
846  try
847  {
848  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
849  m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
850  else
851  m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
852  }
853  catch( ... /* IO_ERROR */ )
854  {
855  }
856 }
Definition of the SCH_SHEET class for Eeschema.
RESCUER(SCH_EDIT_FRAME &aEditFrame, PROJECT &aProject)
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
virtual bool WriteRescueLibrary(SCH_EDIT_FRAME *aEditFrame) override
Writes out the rescue library.
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&#39;s pins do not match another part&#39;s pins.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
Part library alias object definition.
virtual void FindCandidates()=0
Populate the RESCUER with all possible candidates.
SCH_SCREEN * GetNext()
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...
virtual void InvokeDialog(bool aAskShowAgain)=0
Display a dialog to allow the user to select rescues.
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).
Class PROJECT holds project specific data.
Definition: project.h:57
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:259
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&#39;s libraries into this container, which should be cleared before calling it...
This file is part of the common library.
LIB_ID GetLibId() const override
SCH_EDIT_FRAME * GetFrame()
PROJECT & Prj()
Definition: kicad.cpp:292
virtual bool WriteRescueLibrary(SCH_EDIT_FRAME *aEditFrame) override
Writes out the rescue library.
const wxString & GetFileName() const
Definition: sch_screen.h:131
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
const LIB_ID & GetLibId() const
static bool sort_by_libid(const SCH_COMPONENT *ref, SCH_COMPONENT *cmp)
int InvokeDialogRescueEach(SCH_EDIT_FRAME *aCaller, RESCUER &aRescuer, bool aAskShowAgain)
Function InvokeDialogRescueEach This dialog asks the user which rescuable, cached parts he wants to r...
static void get_components(std::vector< SCH_COMPONENT * > &aComponents)
Fill a vector with all of the project&#39;s symbols, to ease iterating over them.
Schematic editor (Eeschema) main window.
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
void set(SCH_PLUGIN *aPlugin)
Definition: sch_io_mgr.h:551
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
SYMBOL_LIB_TABLE_RESCUER(SCH_EDIT_FRAME &aEditFrame, PROJECT &aProject)
SCH_SCREEN * GetScreen()
Definition: sch_sheet.h:279
SCH_ITEM * Next() const
Symbol library viewer main window.
Definition: viewlib_frame.h:44
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.
wxString wx_str() const
Definition: utf8.cpp:51
a helper to handle the real device context used in KiCad
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:56
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:300
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CACHE_CANDIDATE objectss into a vector.
const std::string SchematicLibraryFileExtension
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
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.
std::unique_ptr< PROPERTIES > m_properties
Library plugin properties.
Define a library symbol object.
The common library.
PROJECT * m_prj
std::pair< SCH_COMPONENT *, wxString > COMPONENT_NAME_PAIR
static LIB_PART * find_component(const wxString &aName, PART_LIBS *aLibs, bool aCached)
Search the libraries for the first component with a given name.
virtual bool WriteRescueLibrary(SCH_EDIT_FRAME *aEditFrame)=0
Writes out the rescue library.
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
virtual void InvokeDialog(bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
A collection of PART_LIB objects.
virtual void SaveLibrary(const wxString &aFileName, const PROPERTIES *aProperties=NULL)
Definition: sch_plugin.cpp:44
Definition the SCH_COMPONENT class for Eeschema.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller&#39;s report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:123
static wxFileName GetRescueLibraryFileName()
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
void RemoveAllAliases()
bool DoRescues()
Perform all chosen rescue actions, logging them to be undone if necessary.
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
const LIB_ID & GetLibId() const
void GetAliases(std::vector< LIB_ALIAS * > &aAliases) const
Load a vector with all the entries in this library.
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
virtual void AddPart(LIB_PART *aNewPart)=0
static const char * PropBuffering
const char* PropBuffering
bool RescueSymbolLibTableProject(bool aRunningOnDemand)
std::vector< SCH_COMPONENT * > * GetComponents()
Get the list of symbols that need rescued.
SCH_EDIT_FRAME * m_edit_frame
UTF8 Format() const
Definition: lib_id.cpp:237
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 &#39;_&#39;.
Definition: lib_id.cpp:352
wxString m_requested_name
virtual void SetName(const wxString &aName)
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
virtual void SaveSymbol(const wxString &aLibraryPath, const LIB_PART *aSymbol, const PROPERTIES *aProperties=NULL)
Write aSymbol to an existing library located at aLibraryPath.
Definition: sch_plugin.cpp:102
virtual void AddPart(LIB_PART *aNewPart) override
wxString old_name
SCH_SCREEN * GetFirst()
virtual bool PerformAction(RESCUER *aRescuer) override
Perform the actual rescue action.
virtual void InvokeDialog(bool aAskShowAgain) override
Display a dialog to allow the user to select rescues.
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.
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:97
bool RescueLegacyProject(bool aRunningOnDemand)
void clear()
Definition: utf8.h:113
bool ReCreateListLib()
Creates or recreates a sorted list of currently loaded libraries.
Object used to load, save, search, and otherwise manipulate symbol library files. ...
void SetLibId(const LIB_ID &aLibId)
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
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...
wxString new_name
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:523
virtual void FindCandidates() override
Populate the RESCUER with all possible candidates.
KIWAY Kiway
bool rescueProject(RESCUER &aRescuer, bool aRunningOnDemand)
Perform rescue operations to recover old projects from before certain changes were made...