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 <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 <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 
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  // Remember the list of components is sorted by part name.
141  // So a search in libraries is made only once by group
142  LIB_ALIAS* case_sensitive_match = nullptr;
143  std::vector<LIB_ALIAS*> case_insensitive_matches;
144 
145  wxString last_part_name;
146 
147  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
148  {
149  wxString part_name = each_component->GetLibId().GetLibItemName();
150 
151  if( last_part_name != part_name )
152  {
153  // A new part name is found (a new group starts here).
154  // Search the symbol names candidates only once for this group:
155  last_part_name = part_name;
156  case_insensitive_matches.clear();
157 
158  LIB_ID id( wxEmptyString, part_name );
159 
160  case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibraryAlias( id );
161 
162  if( !case_sensitive_match )
163  // the case sensitive match failed. Try a case insensitive match
164  aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
165  part_name );
166  }
167 
168  if( case_sensitive_match || !( case_insensitive_matches.size() ) )
169  continue;
170 
171  RESCUE_CASE_CANDIDATE candidate( part_name, case_insensitive_matches[0]->GetName(),
172  case_insensitive_matches[0]->GetPart() );
173 
174  candidate_map[part_name] = candidate;
175  }
176 
177  // Now, dump the map into aCandidates
178  for( const candidate_map_t::value_type& each_pair : candidate_map )
179  {
180  aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
181  }
182 }
183 
184 
186 {
187  wxString action;
188  action.Printf( _( "Rename to %s" ), m_new_name );
189  return action;
190 }
191 
192 
194 {
195  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
196  {
197  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
198  continue;
199 
200  LIB_ID libId;
201 
202  libId.SetLibItemName( m_new_name, false );
203  each_component->SetLibId( libId );
204  each_component->ClearFlags();
205  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
206  }
207 
208  return true;
209 }
210 
211 
212 RESCUE_CACHE_CANDIDATE::RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName,
213  const wxString& aNewName,
214  LIB_PART* aCacheCandidate,
215  LIB_PART* aLibCandidate )
216 {
217  m_requested_name = aRequestedName;
218  m_new_name = aNewName;
219  m_cache_candidate = aCacheCandidate;
220  m_lib_candidate = aLibCandidate;
221 }
222 
223 
225 {
226  m_cache_candidate = NULL;
227  m_lib_candidate = NULL;
228 }
229 
230 
232  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
233 {
234  typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
235  candidate_map_t candidate_map;
236 
237  // Remember the list of components is sorted by part name.
238  // So a search in libraries is made only once by group
239  LIB_PART* cache_match = nullptr;
240  LIB_PART* lib_match = nullptr;
241  wxString old_part_name;
242 
243  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
244  {
245  wxString part_name = each_component->GetLibId().GetLibItemName();
246 
247  if( old_part_name != part_name )
248  {
249  // A new part name is found (a new group starts here).
250  // Search the symbol names candidates only once for this group:
251  old_part_name = part_name;
252  cache_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), true );
253  lib_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), false );
254 
255  if( !cache_match && !lib_match )
256  continue;
257 
258  // Test whether there is a conflict or if the symbol can only be found in the cache
259  // and the symbol name does not have any illegal characters.
260  if( ( ( cache_match && lib_match
261  && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
262  || (!cache_match && lib_match ) ) && !LIB_ID::HasIllegalChars( part_name, LIB_ID::ID_SCH ) )
263  continue;
264 
265  // Check if the symbol has already been rescued.
266  wxString new_name = LIB_ID::FixIllegalChars( part_name, LIB_ID::ID_SCH );
267 
268  RESCUE_CACHE_CANDIDATE candidate( part_name, new_name, cache_match, lib_match );
269 
270  candidate_map[part_name] = candidate;
271  }
272  }
273 
274  // Now, dump the map into aCandidates
275  for( const candidate_map_t::value_type& each_pair : candidate_map )
276  {
277  aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
278  }
279 }
280 
281 
283 {
284  wxString action;
285 
286  if( !m_cache_candidate && !m_lib_candidate )
287  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
288  "the cache." ), m_requested_name );
289  else if( m_cache_candidate && !m_lib_candidate )
290  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
292  else
293  action.Printf( _( "Rescue modified symbol %s to %s" ),
295 
296  return action;
297 }
298 
299 
301 {
302  LIB_PART* tmp = ( m_cache_candidate ) ? m_cache_candidate : m_lib_candidate;
303 
304  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
305 
306  LIB_PART new_part( *tmp );
307  new_part.SetName( m_new_name );
308  new_part.RemoveAllAliases();
309  aRescuer->AddPart( &new_part );
310 
311  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
312  {
313  if( each_component->GetLibId().GetLibItemName() != UTF8( m_requested_name ) )
314  continue;
315 
316  LIB_ID libId;
317 
318  libId.SetLibItemName( m_new_name, false );
319  each_component->SetLibId( libId );
320  each_component->ClearFlags();
321  aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
322  }
323 
324  return true;
325 }
326 
327 
329  const LIB_ID& aRequestedId,
330  const LIB_ID& aNewId,
331  LIB_PART* aCacheCandidate,
332  LIB_PART* aLibCandidate ) : RESCUE_CANDIDATE()
333 {
334  m_requested_id = aRequestedId;
335  m_requested_name = aRequestedId.GetLibItemName();
336  m_new_id = aNewId;
337  m_lib_candidate = aLibCandidate;
338  m_cache_candidate = aCacheCandidate;
339 }
340 
341 
343 {
344  m_cache_candidate = NULL;
345  m_lib_candidate = NULL;
346 }
347 
348 
350  RESCUER& aRescuer,
351  boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
352 {
353  typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
354 
355  candidate_map_t candidate_map;
356 
357  // Remember the list of components is sorted by LIB_ID.
358  // So a search in libraries is made only once by group
359  LIB_PART* cache_match = nullptr;
360  LIB_PART* lib_match = nullptr;
361  LIB_ID old_part_id;
362 
363  for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
364  {
365  LIB_ID part_id = each_component->GetLibId();
366 
367  if( old_part_id != part_id )
368  {
369  // A new part name is found (a new group starts here).
370  // Search the symbol names candidates only once for this group:
371  old_part_id = part_id;
372  cache_match = find_component( part_id.Format().wx_str(), aRescuer.GetPrj()->SchLibs(),
373  true );
374 
375  lib_match = aRescuer.GetFrame()->GetLibPart( part_id );
376 
377  if( !cache_match && !lib_match )
378  continue;
379 
380  // Test whether there is a conflict or if the symbol can only be found in the cache.
381  if( ( ( cache_match && lib_match
382  && !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
383  || (!cache_match && lib_match ) )
385  {
386  continue;
387  }
388 
389  // Fix illegal LIB_ID name characters.
390  wxString new_name = LIB_ID::FixIllegalChars( part_id.GetLibItemName(), LIB_ID::ID_SCH );
391 
392  // Differentiate symbol name in the rescue library by appending the symbol library
393  // table nickname to the symbol name to prevent name clashes in the rescue library.
394  wxString libNickname = GetRescueLibraryFileName().GetName();
395 
396  // Spaces in the file name will break the symbol name because they are not
397  // quoted in the symbol library file format.
398  libNickname.Replace( " ", "-" );
399  LIB_ID new_id( libNickname, new_name + "-" + part_id.GetLibNickname().wx_str() );
400 
401  RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match );
402 
403  candidate_map[part_id] = candidate;
404  }
405  }
406 
407  // Now, dump the map into aCandidates
408  for( const candidate_map_t::value_type& each_pair : candidate_map )
409  {
410  aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
411  }
412 }
413 
414 
416 {
417  wxString action;
418 
420  action.Printf( _( "Cannot rescue symbol %s which is not available in any library or "
421  "the cache." ), m_requested_id.GetLibItemName().wx_str() );
422  else if( m_cache_candidate && !m_lib_candidate )
423  action.Printf( _( "Rescue symbol %s found only in cache library to %s." ),
425  else
426  action.Printf( _( "Rescue modified symbol %s to %s" ),
428 
429  return action;
430 }
431 
432 
434 {
436 
437  wxCHECK_MSG( tmp, false, "Both cache and library symbols undefined." );
438 
439  LIB_PART new_part( *tmp );
440  new_part.SetLibId( m_new_id );
441  new_part.SetName( m_new_id.GetLibItemName() );
442  new_part.RemoveAllAliases();
443  aRescuer->AddPart( &new_part );
444 
445  for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
446  {
447  if( each_component->GetLibId() != m_requested_id )
448  continue;
449 
450  each_component->SetLibId( m_new_id );
451  each_component->ClearFlags();
452  aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
453  }
454 
455  return true;
456 }
457 
458 
459 RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject )
460 {
461  get_components( m_components );
462  m_prj = &aProject;
463  m_edit_frame = &aEditFrame;
464 }
465 
466 
467 void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
468  const wxString &aNewName )
469 {
470  RESCUE_LOG logitem;
471  logitem.component = aComponent;
472  logitem.old_name = aOldName;
473  logitem.new_name = aNewName;
474  m_rescue_log.push_back( logitem );
475 }
476 
477 
479 {
480  for( RESCUE_CANDIDATE* each_candidate : m_chosen_candidates )
481  {
482  if( ! each_candidate->PerformAction( this ) )
483  return false;
484  }
485 
486  return true;
487 }
488 
489 
491 {
492  for( RESCUE_LOG& each_logitem : m_rescue_log )
493  {
494  LIB_ID libId;
495 
496  libId.SetLibItemName( each_logitem.old_name, false );
497  each_logitem.component->SetLibId( libId );
498  each_logitem.component->ClearFlags();
499  }
500 }
501 
502 
503 bool SCH_EDIT_FRAME::RescueLegacyProject( bool aRunningOnDemand )
504 {
505  LEGACY_RESCUER rescuer( *this, Prj() );
506 
507  return rescueProject( rescuer, aRunningOnDemand );
508 }
509 
510 
511 bool SCH_EDIT_FRAME::RescueSymbolLibTableProject( bool aRunningOnDemand )
512 {
513  SYMBOL_LIB_TABLE_RESCUER rescuer( *this, Prj() );
514 
515  return rescueProject( rescuer, aRunningOnDemand );
516 }
517 
518 
519 bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
520 {
521  aRescuer.FindCandidates();
522 
523  if( ! aRescuer.GetCandidateCount() )
524  {
525  if( aRunningOnDemand )
526  {
527  wxMessageDialog dlg( this, _( "This project has nothing to rescue." ),
528  _( "Project Rescue Helper" ) );
529  dlg.ShowModal();
530  }
531 
532  return true;
533  }
534 
535  aRescuer.RemoveDuplicates();
536 
537  aRescuer.InvokeDialog( !aRunningOnDemand );
538 
539  // If no symbols were rescued, let the user know what's going on. He might
540  // have clicked cancel by mistake, and should have some indication of that.
541  if( !aRescuer.GetChosenCandidateCount() )
542  {
543  wxMessageDialog dlg( this, _( "No symbols were rescued." ),
544  _( "Project Rescue Helper" ) );
545  dlg.ShowModal();
546 
547  // Set the modified flag even on Cancel. Many users seem to instinctively want to Save at
548  // this point, due to the reloading of the symbols, so we'll make the save button active.
549  OnModify();
550  return true;
551  }
552 
553  aRescuer.OpenRescueLibrary();
554 
555  if( !aRescuer.DoRescues() )
556  {
557  aRescuer.UndoRescues();
558  return false;
559  }
560 
561  aRescuer.WriteRescueLibrary( this );
562 
563  LIB_VIEW_FRAME* viewer = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
564 
565  if( viewer )
566  viewer->ReCreateListLib();
567 
568  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
569  m_canvas->Refresh( true );
570  OnModify();
571 
572  return true;
573 }
574 
575 
577 {
578  std::vector<wxString> names_seen;
579 
580  for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
581  it != m_all_candidates.end(); )
582  {
583  bool seen_already = false;
584 
585  for( wxString& name_seen : names_seen )
586  {
587  if( name_seen == it->GetRequestedName() )
588  {
589  seen_already = true;
590  break;
591  }
592  }
593 
594  if( seen_already )
595  {
596  it = m_all_candidates.erase( it );
597  }
598  else
599  {
600  names_seen.push_back( it->GetRequestedName() );
601  ++it;
602  }
603  }
604 }
605 
606 
608 {
609  RESCUE_CASE_CANDIDATE::FindRescues( *this, m_all_candidates );
610  RESCUE_CACHE_CANDIDATE::FindRescues( *this, m_all_candidates );
611 }
612 
613 
614 void LEGACY_RESCUER::InvokeDialog( bool aAskShowAgain )
615 {
616  InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
617 }
618 
619 
621 {
622  wxFileName fn = GetRescueLibraryFileName();
623 
624  std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
625 
626  m_rescue_lib = std::move( rescue_lib );
627  m_rescue_lib->EnableBuffering();
628 
629  // If a rescue library already exists copy the contents of that library so we do not
630  // lose an previous rescues.
631  PART_LIB* rescueLib = m_prj->SchLibs()->FindLibrary( fn.GetName() );
632 
633  if( rescueLib )
634  {
635  // For items in the rescue library, aliases are the root symbol.
636  std::vector< LIB_ALIAS* > aliases;
637 
638  rescueLib->GetAliases( aliases );
639 
640  for( auto alias : aliases )
641  {
642  LIB_PART* part = alias->GetPart();
643 
644  wxCHECK2( part, continue );
645 
646  m_rescue_lib->AddPart( new LIB_PART( *part, m_rescue_lib.get() ) );
647  }
648  }
649 }
650 
651 
653 {
654  try
655  {
656  m_rescue_lib->Save( false );
657  }
658  catch( ... /* IO_ERROR ioe */ )
659  {
660  wxString msg;
661 
662  msg.Printf( _( "Failed to create symbol library file \"%s\"" ),
663  m_rescue_lib->GetFullFileName() );
664  DisplayError( aEditFrame, msg );
665  return false;
666  }
667 
668  wxArrayString libNames;
669  wxString libPaths;
670 
671  wxString libName = m_rescue_lib->GetName();
672  PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
673 
674  if( !libs )
675  {
676  libs = new PART_LIBS();
677  m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
678  }
679 
680  try
681  {
682  PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
683 
684  // Make sure the library is not already in the list
685  while( libNames.Index( libName ) != wxNOT_FOUND )
686  libNames.Remove( libName );
687 
688  // Add the library to the top of the list and save.
689  libNames.Insert( libName, 0 );
690  PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
691  }
692  catch( const IO_ERROR& )
693  {
694  // Could not get or save the current libraries.
695  return false;
696  }
697 
698  // Save the old libraries in case there is a problem after clear(). We'll
699  // put them back in.
700  boost::ptr_vector<PART_LIB> libsSave;
701  libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
702 
703  m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
704 
705  libs = new PART_LIBS();
706 
707  try
708  {
709  libs->LoadAllLibraries( m_prj );
710  }
711  catch( const PARSE_ERROR& )
712  {
713  // Some libraries were not found. There's no point in showing the error,
714  // because it was already shown. Just don't do anything.
715  }
716  catch( const IO_ERROR& )
717  {
718  // Restore the old list
719  libs->clear();
720  libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
721  return false;
722  }
723 
724  m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
725 
726  // Update the schematic symbol library links since the library list has changed.
727  SCH_SCREENS schematic;
728 
729  schematic.UpdateSymbolLinks();
730 
731  return true;
732 }
733 
734 
736 {
737  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
738 
739  aNewPart->SetLib( m_rescue_lib.get() );
740  m_rescue_lib->AddPart( aNewPart );
741 }
742 
743 
745  PROJECT& aProject ) :
746  RESCUER( aEditFrame, aProject )
747 {
748  m_properties = std::make_unique<PROPERTIES>();
749 }
750 
751 
753 {
755 }
756 
757 
758 void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( bool aAskShowAgain )
759 {
760  InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
761 }
762 
763 
765 {
766  m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
767  (*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
768 }
769 
770 
772 {
773  wxString msg;
774  wxFileName fn = GetRescueLibraryFileName();
775 
776  // If the rescue library already exists in the symbol library table no need save it to add
777  // it to the table.
778  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
779  {
780  try
781  {
782  m_pi->SaveLibrary( fn.GetFullPath() );
783  }
784  catch( const IO_ERROR& ioe )
785  {
786  msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
787  DisplayErrorMessage( aEditFrame, msg, ioe.What() );
788  return false;
789  }
790 
791  wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
792  wxString libNickname = fn.GetName();
793 
794  // Spaces in the file name will break the symbol name because they are not
795  // quoted in the symbol library file format.
796  libNickname.Replace( " ", "-" );
797 
798  SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( libNickname, uri,
799  wxString( "Legacy" ) );
800  m_prj->SchSymbolLibTable()->InsertRow( row );
801 
803 
804  try
805  {
806  m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
807  }
808  catch( const IO_ERROR& ioe )
809  {
810  msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
811  DisplayErrorMessage( aEditFrame, msg, ioe.What() );
812  return false;
813  }
814  }
815 
816  // Relaod the symbol library table.
818 
819  // This can only happen if the symbol library table file was currupted on write.
820  if( !m_prj->SchSymbolLibTable() )
821  return false;
822 
823  // Update the schematic symbol library links since the library list has changed.
824  SCH_SCREENS schematic;
825 
826  schematic.UpdateSymbolLinks( true );
827  return true;
828 }
829 
830 
832 {
833  wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
834 
835  wxFileName fn = GetRescueLibraryFileName();
836 
837  try
838  {
839  if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
840  m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
841  else
842  m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
843  }
844  catch( ... /* IO_ERROR */ )
845  {
846  }
847 }
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:56
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:199
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.
SCH_EDIT_FRAME * GetFrame()
PROJECT & Prj()
Definition: kicad.cpp:287
virtual bool WriteRescueLibrary(SCH_EDIT_FRAME *aEditFrame) override
Writes out the rescue library.
const wxString & GetFileName() const
Definition: sch_screen.h:120
virtual void OpenRescueLibrary() override
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.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType)
Replace illegal LIB_ID item name characters with underscores &#39;_&#39;.
Definition: lib_id.cpp:374
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:49
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.
static bool HasIllegalChars(const UTF8 &aLibItemName, LIB_ID_TYPE aType)
Examine aLibItemName for invalid LIB_ID item name characters.
Definition: lib_id.cpp:362
wxString wx_str() const
Definition: utf8.cpp:48
a helper to handle the real device context used in KiCad
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:55
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.
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi
const UTF8 & GetLibItemName() const
Definition: lib_id.h:118
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: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.
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:94
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: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.
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:101
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 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:185
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.
Definition: sch_screen.h:503
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...