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-2017 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 <class_drawpanel.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 <schframe.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( wxString aName, PART_LIBS* aLibs, bool aCached )
95 {
96  LIB_PART *part = NULL;
97 
98  for( PART_LIB& each_lib : *aLibs )
99  {
100  if( aCached && !each_lib.IsCache() )
101  continue;
102 
103  if( !aCached && each_lib.IsCache() )
104  continue;
105 
106  part = each_lib.FindPart( aName );
107 
108  if( part )
109  break;
110  }
111 
112  return part;
113 }
114 
115 
116 static wxFileName GetRescueLibraryFileName()
117 {
118  wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
119  fn.SetName( fn.GetName() + wxT( "-rescue" ) );
120  fn.SetExt( SchematicLibraryFileExtension );
121  return fn;
122 }
123 
124 
125 RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName,
126  const wxString& aNewName,
127  LIB_PART* aLibCandidate )
128 {
129  m_requested_name = aRequestedName;
130  m_new_name = aNewName;
131  m_lib_candidate = aLibCandidate;
132 }
133 
134 
136  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
137 {
138  typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
139  candidate_map_t candidate_map;
140 
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  wxString part_name_suffix = aRescuer.GetPartNameSuffix();
245 
246  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
247  {
248  wxString part_name = each_component->GetLibId().GetLibItemName();
249 
250  if( old_part_name != part_name )
251  {
252  // A new part name is found (a new group starts here).
253  // Search the symbol names candidates only once for this group:
254  old_part_name = part_name;
255  cache_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), true );
256  lib_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), false );
257 
258  if( !cache_match && !lib_match )
259  continue;
260 
261  // Test whether there is a conflict or if the symbol can only be found in the cache
262  // and the symbol name does not have any illegal characters.
263  if( ( ( cache_match && lib_match
264  && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
265  || (!cache_match && lib_match ) ) && !LIB_ID::HasIllegalChars( part_name ) )
266  continue;
267 
268  // Check if the symbol has already been rescued.
269  wxString new_name = LIB_ID::FixIllegalChars( part_name );
270 
271  if( new_name.Find( part_name_suffix ) == wxNOT_FOUND )
272  new_name += part_name_suffix;
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  action.Printf( _( "Rescue %s as %s" ), m_requested_name, m_new_name );
292  return action;
293 }
294 
295 
297 {
298  LIB_PART new_part( *m_cache_candidate );
299  new_part.SetName( m_new_name );
300  new_part.RemoveAllAliases();
301  aRescuer->AddPart( &new_part );
302 
303  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
304  {
305  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
306  continue;
307 
308  LIB_ID libId;
309 
310  libId.SetLibItemName( m_new_name, false );
311  each_component->SetLibId( libId );
312  each_component->ClearFlags();
313  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
314  }
315 
316  return true;
317 }
318 
319 
321  const LIB_ID& aRequestedId,
322  const LIB_ID& aNewId,
323  LIB_PART* aCacheCandidate,
324  LIB_PART* aLibCandidate ) : RESCUE_CANDIDATE()
325 {
326  m_requested_id = aRequestedId;
327  m_requested_name = aRequestedId.GetLibItemName();
328  m_new_id = aNewId;
329  m_lib_candidate = aLibCandidate;
330  m_cache_candidate = aCacheCandidate;
331 }
332 
333 
335 {
336  m_cache_candidate = NULL;
337  m_lib_candidate = NULL;
338 }
339 
340 
342  RESCUER& aRescuer,
343  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
344 {
345  typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
346 
347  candidate_map_t candidate_map;
348 
349  // Remember the list of components is sorted by LIB_ID.
350  // So a search in libraries is made only once by group
351  LIB_PART* cache_match = nullptr;
352  LIB_PART* lib_match = nullptr;
353  LIB_ID old_part_id;
354 
355  wxString part_name_suffix = aRescuer.GetPartNameSuffix();
356 
357  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
358  {
359  LIB_ID part_id = each_component->GetLibId();
360 
361  if( old_part_id != part_id )
362  {
363  // A new part name is found (a new group starts here).
364  // Search the symbol names candidates only once for this group:
365  old_part_id = part_id;
366  cache_match = find_component( part_id.GetLibItemName(), aRescuer.GetPrj()->SchLibs(),
367  true );
368 
369  lib_match = aRescuer.GetFrame()->GetLibPart( part_id );
370 
371  if( !cache_match && !lib_match )
372  continue;
373 
374  // Test whether there is a conflict or if the symbol can only be found in the cache.
375  if( ( ( cache_match && lib_match
376  && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
377  || (!cache_match && lib_match ) )
378  && !LIB_ID::HasIllegalChars( part_id.GetLibItemName() ) )
379  continue;
380 
381  // May have been rescued already.
382  wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName() );
383 
384  if( new_name.Find( part_name_suffix ) == wxNOT_FOUND )
385  new_name += part_name_suffix;
386 
387  LIB_ID new_id( GetRescueLibraryFileName().GetName(), new_name );
388 
389  RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match );
390 
391  candidate_map[part_id] = candidate;
392  }
393  }
394 
395  // Now, dump the map into aCandidates
396  for( const candidate_map_t::value_type& each_pair : candidate_map )
397  {
398  aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
399  }
400 }
401 
402 
404 {
405  wxString action;
406  action.Printf( _( "Rescue to %s" ), m_new_id.Format().wx_str() );
407  return action;
408 }
409 
410 
412 {
413  LIB_PART new_part( *m_cache_candidate );
414  new_part.SetName( m_new_id.GetLibItemName() );
415  new_part.RemoveAllAliases();
416  aRescuer->AddPart( &new_part );
417 
418  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
419  {
420  if( each_component->GetLibId() != m_requested_id )
421  continue;
422 
423  each_component->SetLibId( m_new_id );
424  each_component->ClearFlags();
425  aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
426  }
427 
428  return true;
429 }
430 
431 
432 RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject )
433 {
435  m_prj = &aProject;
436  m_edit_frame = &aEditFrame;
437 }
438 
439 
440 void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
441  const wxString &aNewName )
442 {
443  RESCUE_LOG logitem;
444  logitem.component = aComponent;
445  logitem.old_name = aOldName;
446  logitem.new_name = aNewName;
447  m_rescue_log.push_back( logitem );
448 }
449 
450 
452 {
453  for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
454  {
455  if( ! each_candidate->PerformAction( this ) )
456  return false;
457  }
458 
459  return true;
460 }
461 
462 
464 {
465  for( RESCUE_LOG& each_logitem : m_rescue_log )
466  {
467  LIB_ID libId;
468 
469  libId.SetLibItemName( each_logitem.old_name, false );
470  each_logitem.component->SetLibId( libId );
471  each_logitem.component->ClearFlags();
472  }
473 }
474 
475 
477 {
478  wxString suffix = wxT( "-RESCUE-" );
479  wxString pname = GetPrj()->GetProjectName();
480 
481  for( size_t i = 0; i < pname.Len(); ++i )
482  {
483  if( isspace( pname[i].GetValue() ) )
484  suffix.Append( '_' );
485  else
486  suffix.Append( pname[i] );
487  }
488 
489  return suffix;
490 }
491 
492 
493 bool SCH_EDIT_FRAME::RescueLegacyProject( bool aRunningOnDemand )
494 {
495  LEGACY_RESCUER rescuer( *this, Prj() );
496 
497  return rescueProject( rescuer, aRunningOnDemand );
498 }
499 
500 
501 bool SCH_EDIT_FRAME::RescueSymbolLibTableProject( bool aRunningOnDemand )
502 {
503  SYMBOL_LIB_TABLE_RESCUER rescuer( *this, Prj() );
504 
505  return rescueProject( rescuer, aRunningOnDemand );
506 }
507 
508 
509 bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
510 {
511  aRescuer.FindCandidates();
512 
513  if( ! aRescuer.GetCandidateCount() )
514  {
515  if( aRunningOnDemand )
516  {
517  wxMessageDialog dlg( this, _( "This project has nothing to rescue." ),
518  _( "Project Rescue Helper" ) );
519  dlg.ShowModal();
520  }
521 
522  return true;
523  }
524 
525  aRescuer.RemoveDuplicates();
526 
527  aRescuer.InvokeDialog( !aRunningOnDemand );
528 
529  // If no symbols were rescued, let the user know what's going on. He might
530  // have clicked cancel by mistake, and should have some indication of that.
531  if( !aRescuer.GetChosenCandidateCount() )
532  {
533  wxMessageDialog dlg( this, _( "No symbols were rescued." ),
534  _( "Project Rescue Helper" ) );
535  dlg.ShowModal();
536 
537  // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
538  // this point, due to the reloading of the symbols, so we'll make the save button active.
539  OnModify();
540  return true;
541  }
542 
543  aRescuer.OpenRescueLibrary();
544 
545  if( !aRescuer.DoRescues() )
546  {
547  aRescuer.UndoRescues();
548  return false;
549  }
550 
551  aRescuer.WriteRescueLibrary( this );
552 
553  LIB_VIEW_FRAME* viewer = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
554 
555  if( viewer )
556  viewer->ReCreateListLib();
557 
558  // Clean up wire ends
560  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
561  m_canvas->Refresh( true );
562  OnModify();
563 
564  return true;
565 }
566 
567 
569 {
570  std::vector<wxString> names_seen;
571 
572  for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
573  it != m_all_candidates.end(); )
574  {
575  bool seen_already = false;
576 
577  for( wxString& name_seen : names_seen )
578  {
579  if( name_seen == it->GetRequestedName() )
580  {
581  seen_already = true;
582  break;
583  }
584  }
585 
586  if( seen_already )
587  {
588  it = m_all_candidates.erase( it );
589  }
590  else
591  {
592  names_seen.push_back( it->GetRequestedName() );
593  ++it;
594  }
595  }
596 }
597 
598 
600 {
603 }
604 
605 
606 void LEGACY_RESCUER::InvokeDialog( bool aAskShowAgain )
607 {
608  InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
609 }
610 
611 
613 {
614  wxFileName fn = GetRescueLibraryFileName();
615 
616  std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
617 
618  m_rescue_lib = std::move( rescue_lib );
619  m_rescue_lib->EnableBuffering();
620 
621  // If a rescue library already exists copy the contents of that library so we do not
622  // lose an previous rescues.
623  PART_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
624 
625  if( rescueLib )
626  {
627  // For items in the rescue library, aliases are the root symbol.
628  std::vector< LIB_ALIAS* > aliases;
629 
630  rescueLib->GetAliases( aliases );
631 
632  for( auto alias : aliases )
633  {
634  LIB_PART* part = alias->GetPart();
635 
636  wxCHECK2( part, continue );
637 
638  m_rescue_lib->AddPart( new LIB_PART( *part, m_rescue_lib.get() ) );
639  }
640  }
641 }
642 
643 
645 {
646  try
647  {
648  m_rescue_lib->Save( false );
649  }
650  catch( ... /* IO_ERROR ioe */ )
651  {
652  wxString msg;
653 
654  msg.Printf( _( "Failed to create symbol library file \"%s\"" ),
655  m_rescue_lib->GetFullFileName() );
656  DisplayError( aEditFrame, msg );
657  return false;
658  }
659 
660  wxArrayString libNames;
661  wxString libPaths;
662 
663  wxString libName = m_rescue_lib->GetName();
664  PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
665 
666  if( !libs )
667  {
668  libs = new PART_LIBS();
670  }
671 
672  try
673  {
674  PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
675 
676  // Make sure the library is not already in the list
677  while( libNames.Index( libName ) != wxNOT_FOUND )
678  libNames.Remove( libName );
679 
680  // Add the library to the top of the list and save.
681  libNames.Insert( libName, 0 );
682  PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
683  }
684  catch( const IO_ERROR& )
685  {
686  // Could not get or save the current libraries.
687  return false;
688  }
689 
690  // Save the old libraries in case there is a problem after clear(). We'll
691  // put them back in.
692  boost::ptr_vector<PART_LIB> libsSave;
693  libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
694 
696 
697  libs = new PART_LIBS();
698 
699  try
700  {
701  libs->LoadAllLibraries( m_prj );
702  }
703  catch( const PARSE_ERROR& )
704  {
705  // Some libraries were not found. There's no point in showing the error,
706  // because it was already shown. Just don't do anything.
707  }
708  catch( const IO_ERROR& )
709  {
710  // Restore the old list
711  libs->clear();
712  libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
713  return false;
714  }
715 
717 
718  // Update the schematic symbol library links since the library list has changed.
719  SCH_SCREENS schematic;
720 
721  schematic.UpdateSymbolLinks();
722 
723  return true;
724 }
725 
726 
728 {
729  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
730 
731  aNewPart->SetLib( m_rescue_lib.get() );
732  m_rescue_lib->AddPart( aNewPart );
733 }
734 
735 
737  PROJECT& aProject ) :
738  RESCUER( aEditFrame, aProject )
739 {
740  m_properties = std::make_unique<PROPERTIES>();
741 }
742 
743 
745 {
747 }
748 
749 
750 void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( bool aAskShowAgain )
751 {
752  InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
753 }
754 
755 
757 {
758  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
759  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
760 }
761 
762 
764 {
765  wxString msg;
766  wxFileName fn = GetRescueLibraryFileName();
767 
768  // If the rescue library already exists in the symbol library table no need save it to add
769  // it to the table.
770  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
771  {
772  try
773  {
774  m_pi->SaveLibrary( fn.GetFullPath() );
775  }
776  catch( const IO_ERROR& ioe )
777  {
778  msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
779  DisplayErrorMessage( aEditFrame, msg, ioe.What() );
780  return false;
781  }
782 
783  wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
784  SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( fn.GetName(), uri,
785  wxString( "Legacy" ) );
786  m_prj->SchSymbolLibTable()->InsertRow( row );
787 
789 
790  try
791  {
792  m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
793  }
794  catch( const IO_ERROR& ioe )
795  {
796  msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
797  DisplayErrorMessage( aEditFrame, msg, ioe.What() );
798  return false;
799  }
800  }
801 
802  // Relaod the symbol library table.
804 
805  // This can only happen if the symbol library table file was currupted on write.
806  if( !m_prj->SchSymbolLibTable() )
807  return false;
808 
809  // Update the schematic symbol library links since the library list has changed.
810  SCH_SCREENS schematic;
811 
812  schematic.UpdateSymbolLinks( true );
813  return true;
814 }
815 
816 
818 {
819  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
820 
821  wxFileName fn = GetRescueLibraryFileName();
822 
823  try
824  {
825  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
826  m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
827  else
828  m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
829  }
830  catch( ... /* IO_ERROR */ )
831  {
832  }
833 }
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's pins do not match another part's pins.
virtual wxString GetActionDescription() const override
Get a description of the action proposed, for displaying in the UI.
Part library alias object definition.
bool SchematicCleanUp(bool aAppend=false)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
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...
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_player.h:60
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:56
PROJECT * GetPrj()
Return the #SCH_PROJECT object for access to the symbol libraries.
void LoadAllLibraries(PROJECT *aProject, bool aShowProgress=true)
Load all of the project's libraries into this container, which should be cleared before calling it...
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Update the board display after modifying it bu a python script (note: it is automatically called by a...
Definition: draw_panel.cpp:332
This file is part of the common library.
void OnModify()
Must be called after a schematic change in order to set the "modify" flag of the current screen* and ...
Definition: schframe.cpp:773
static UTF8 FixIllegalChars(const UTF8 &aLibItemName)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition: lib_id.cpp:384
SCH_EDIT_FRAME * GetFrame()
virtual bool WriteRescueLibrary(SCH_EDIT_FRAME *aEditFrame) override
Writes out the rescue library.
const wxString & GetFileName() const
virtual void OpenRescueLibrary() override
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's symbols, to ease iterating over them.
Schematic editor (Eeschema) main window.
Definition: schframe.h:118
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
void set(SCH_PLUGIN *aPlugin)
Definition: sch_io_mgr.h:551
VTBL_ENTRY _ELEM * GetElem(ELEM_T aIndex)
Typically wrapped somewhere else in a more meaningful function wrapper.
Definition: project.cpp:207
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
static LIB_PART * find_component(wxString aName, PART_LIBS *aLibs, bool aCached)
Search the libraries for the first component with a given name.
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:49
LIB_PART * m_lib_candidate
SCH_COMPONENT * component
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:219
boost::ptr_vector< RESCUE_CANDIDATE > m_all_candidates
void RemoveDuplicates()
Filter out duplicately named rescue candidates.
SCH_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
Definition: schframe.cpp:532
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
wxString wx_str() const
Definition: utf8.cpp:48
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:87
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, KIWAY_PLAYER *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:302
a helper to handle the real device context used in KiCad
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:55
static void FindRescues(RESCUER &aRescuer, boost::ptr_vector< RESCUE_CANDIDATE > &aCandidates)
Grab all possible RESCUE_CACHE_CANDIDATE objectss into a vector.
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi
const UTF8 & GetLibItemName() const
Definition: lib_id.h:115
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
std::vector< SCH_COMPONENT * > m_components
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:232
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.
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:93
wxString GetPartNameSuffix()
Return the suffix to add to rescued parts.
virtual void SaveLibrary(const wxString &aFileName, const PROPERTIES *aProperties=NULL)
Definition: sch_plugin.cpp:44
Definition the SCH_COMPONENT class for Eeschema.
std::vector< RESCUE_CANDIDATE * > m_chosen_candidates
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's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
static wxFileName GetRescueLibraryFileName()
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
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 bool HasIllegalChars(const UTF8 &aLibItemName)
Examine aLibItemName for invalid LIB_ID item name characters.
Definition: lib_id.cpp:362
static const char * PropBuffering
const char* PropBuffering
bool RescueSymbolLibTableProject(bool aRunningOnDemand)
std::vector< SCH_COMPONENT * > * GetComponents()
Get the list of symbols that need rescued.
std::vector< RESCUE_LOG > m_rescue_log
SCH_EDIT_FRAME * m_edit_frame
UTF8 Format() const
Definition: lib_id.cpp:263
void LogRescue(SCH_COMPONENT *aComponent, const wxString &aOldName, const wxString &aNewName)
Used by individual RESCUE_CANDIDATE objects to log a rescue for undoing.
wxString m_requested_name
virtual void 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.
virtual void ClearUndoORRedoList(UNDO_REDO_CONTAINER &aList, int aItemCount=-1) override
Free the undo or redo list from aList element.
Definition: sch_screen.cpp:552
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)
bool ReCreateListLib()
Creates or recreates a sorted list of currently loaded libraries.
const wxString SchematicLibraryFileExtension
Object used to load, save, search, and otherwise manipulate symbol library files. ...
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:73
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
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.
VTBL_ENTRY const wxString GetProjectName() const
Function GetProjectName returns the short name of the project.
Definition: project.cpp:108
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...