KiCad PCB EDA Suite
dialog_symbol_remap.cpp
Go to the documentation of this file.
1 
5 /*
6  * This program source code file is part of KiCad, a free EDA CAD application.
7  *
8  * Copyright (C) 2017 Wayne Stambaugh <stambaughw@verizon.net>
9  * Copyright (C) 2017-2018 KiCad Developers, see AUTHORS.txt for contributors.
10  *
11  * This program is free software: you can redistribute it and/or modify it
12  * under the terms of the GNU General Public License as published by the
13  * Free Software Foundation, either version 3 of the License, or (at your
14  * option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program. If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include <macros.h>
26 #include <pgm_base.h>
27 #include <kiface_i.h>
28 #include <project.h>
29 #include <confirm.h>
30 #include <reporter.h>
32 #include <wx_html_report_panel.h>
33 
34 #include <class_library.h>
35 #include <sch_io_mgr.h>
36 #include <sch_sheet.h>
37 #include <sch_component.h>
38 #include <sch_screen.h>
39 #include <sch_edit_frame.h>
40 #include <symbol_lib_table.h>
41 #include <env_paths.h>
42 
43 #include <dialog_symbol_remap.h>
44 
45 
47  DIALOG_SYMBOL_REMAP_BASE( aParent )
48 {
49  m_remapped = false;
50 
51  if( !wxFileName::IsDirWritable( Prj().GetProjectPath() ) )
52  {
53  DisplayInfoMessage( this, _( "Remapping is not possible because you do not have "
54  "write privileges to the project folder \"%s\"." ) );
55 
56  // Disable the remap button.
57  m_remapped = true;
58  }
59 
60  wxString text;
61 
62  text = _( "This schematic currently uses the project symbol library list look up method "
63  "for loading library symbols. KiCad will attempt to map the existing symbols "
64  "to use the new symbol library table. Remapping will change some project files "
65  "and schematics may not be compatible with older versions of KiCad. All files "
66  "that are changed will be backed up to the \"remap_backup\" folder in the project "
67  "folder should you need to revert any changes. If you choose to skip this step, "
68  "you will be responsible for manually remapping the symbols." );
69 
70  m_htmlCtrl->AppendToPage( text );
71 }
72 
73 
74 void DIALOG_SYMBOL_REMAP::OnRemapSymbols( wxCommandEvent& aEvent )
75 {
76  SCH_EDIT_FRAME* parent = dynamic_cast< SCH_EDIT_FRAME* >( GetParent() );
77 
78  wxCHECK_RET( parent != nullptr, "Parent window is not type SCH_EDIT_FRAME." );
79 
80  wxBusyCursor busy;
81 
83  return;
84 
85  // Ignore the never show rescue setting for one last rescue of legacy symbol
86  // libraries before remapping to the symbol library table. This ensures the
87  // best remapping results.
88  parent->RescueLegacyProject( false );
89 
90  // The schematic is fully loaded, any legacy library symbols have been rescued. Now
91  // check to see if the schematic has not been converted to the symbol library table
92  // method for looking up symbols.
93  wxFileName prjSymLibTableFileName( Prj().GetProjectPath(),
95 
96  // Delete the existing project symbol library table.
97  if( prjSymLibTableFileName.FileExists() )
98  {
99  wxRemoveFile( prjSymLibTableFileName.GetFullPath() );
100  }
101 
104  Prj().SchSymbolLibTable();
105 
107 
108  // Remove all of the libraries from the legacy library list.
109  wxString paths;
110  wxArrayString libNames;
111 
112  PART_LIBS::LibNamesAndPaths( &Prj(), true, &paths, &libNames );
113 
114  // Reload the the cache symbol library.
116  Prj().SchLibs();
117 
118  Raise();
119  m_remapped = true;
120 }
121 
122 
123 size_t DIALOG_SYMBOL_REMAP::getLibsNotInGlobalSymbolLibTable( std::vector< PART_LIB* >& aLibs )
124 {
125  PART_LIBS* libs = Prj().SchLibs();
126 
127  for( PART_LIBS_BASE::iterator it = libs->begin(); it != libs->end(); ++it )
128  {
129  // Ignore the cache library.
130  if( it->IsCache() )
131  continue;
132 
133  // Check for the obvious library name.
134  wxString libFileName = it->GetFullFileName();
135 
136  if( !SYMBOL_LIB_TABLE::GetGlobalLibTable().FindRowByURI( libFileName ) )
137  aLibs.push_back( &(*it) );
138  }
139 
140  return aLibs.size();
141 }
142 
143 
145 {
146  wxString msg;
147  std::vector< PART_LIB* > libs;
148 
150  {
151  SYMBOL_LIB_TABLE prjLibTable;
152  std::vector< wxString > libNames = SYMBOL_LIB_TABLE::GetGlobalLibTable().GetLogicalLibs();
153 
154  for( auto lib : libs )
155  {
156  wxString libName = lib->GetName();
157  int libNameInc = 1;
158  int libNameLen = libName.Length();
159 
160  // Spaces in the file name will break the symbol name because they are not
161  // quoted in the symbol library file format.
162  libName.Replace( " ", "-" );
163 
164  // Don't create duplicate table entries.
165  while( std::find( libNames.begin(), libNames.end(), libName ) != libNames.end() )
166  {
167  libName = libName.Left( libNameLen );
168  libName << libNameInc;
169  libNameInc++;
170  }
171 
172  wxString pluginType = SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY );
173  wxFileName fn = lib->GetFullFileName();
174 
175  // Use environment variable substitution where possible. This is based solely
176  // on the internal user environment variable list. Checking against all of the
177  // system wide environment variables is probably not a good idea.
178  wxString fullFileName = NormalizePath( fn, &Pgm().GetLocalEnvVariables(), &Prj() );
179 
180  // Fall back to the absolute library path.
181  if( fullFileName.IsEmpty() )
182  fullFileName = lib->GetFullFileName();
183 
184  wxFileName tmpFn = fullFileName;
185 
186  // Don't add symbol libraries that do not exist.
187  if( tmpFn.Normalize() && tmpFn.FileExists() )
188  {
189  msg.Printf( _( "Adding library \"%s\", file \"%s\" to project symbol library table." ),
190  libName, fullFileName );
191  aReporter.Report( msg, REPORTER::RPT_INFO );
192 
193  prjLibTable.InsertRow( new SYMBOL_LIB_TABLE_ROW( libName, fullFileName,
194  pluginType ) );
195  }
196  else
197  {
198  msg.Printf( _( "Library \"%s\" not found." ), fullFileName );
199  aReporter.Report( msg, REPORTER::RPT_WARNING );
200  }
201  }
202 
203  // Don't save empty project symbol library table.
204  if( !prjLibTable.IsEmpty() )
205  {
206  wxFileName fn( Prj().GetProjectPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
207 
208  try
209  {
210  FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
211  prjLibTable.Format( &formatter, 0 );
212  }
213  catch( const IO_ERROR& ioe )
214  {
215  msg.Printf( _( "Failed to write project symbol library table. Error:\n %s" ),
216  ioe.What() );
217  aReporter.Report( msg, REPORTER::RPT_ERROR );
218  }
219 
220  aReporter.Report( _( "Created project symbol library table.\n" ), REPORTER::RPT_INFO );
221  }
222  }
223 }
224 
225 
227 {
228  wxString msg;
229  SCH_SCREENS schematic;
230  SCH_COMPONENT* symbol;
231  SCH_ITEM* item;
232  SCH_ITEM* nextItem;
233  SCH_SCREEN* screen;
234 
235  for( screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
236  {
237  for( item = screen->GetDrawItems(); item; item = nextItem )
238  {
239  nextItem = item->Next();
240 
241  if( item->Type() != SCH_COMPONENT_T )
242  continue;
243 
244  symbol = dynamic_cast< SCH_COMPONENT* >( item );
245 
246  if( !remapSymbolToLibTable( symbol ) )
247  {
248  msg.Printf( _( "No symbol \"%s\" found in symbol library table." ),
249  symbol->GetLibId().GetLibItemName().wx_str() );
250  aReporter.Report( msg, REPORTER::RPT_WARNING );
251  }
252  else
253  {
254  msg.Printf( _( "Symbol \"%s\" mapped to symbol library \"%s\"." ),
255  symbol->GetLibId().GetLibItemName().wx_str(),
256  symbol->GetLibId().GetLibNickname().wx_str() );
257  aReporter.Report( msg, REPORTER::RPT_ACTION );
258  screen->SetModify();
259  }
260  }
261  }
262 
263  aReporter.Report( _( "Symbol library table mapping complete!" ), REPORTER::RPT_INFO );
264  schematic.UpdateSymbolLinks( true );
265 }
266 
267 
269 {
270  wxCHECK_MSG( aSymbol != NULL, false, "Null pointer passed to remapSymbolToLibTable." );
271  wxCHECK_MSG( aSymbol->GetLibId().GetLibNickname().empty(), false,
272  "Cannot remap symbol that is already mapped." );
273  wxCHECK_MSG( !aSymbol->GetLibId().GetLibItemName().empty(), false,
274  "The symbol LIB_ID name is empty." );
275 
276  PART_LIBS* libs = Prj().SchLibs();
277 
278  for( PART_LIBS_BASE::iterator it = libs->begin(); it != libs->end(); ++it )
279  {
280  // Ignore the cache library.
281  if( it->IsCache() )
282  continue;
283 
284  LIB_ALIAS* alias = it->FindAlias( aSymbol->GetLibId().GetLibItemName().wx_str() );
285 
286  // Found in the same library as the old look up method assuming the user didn't
287  // change the libraries or library ordering since the last time the schematic was
288  // loaded.
289  if( alias )
290  {
291  // Find the same library in the symbol library table using the full path and file name.
292  wxString libFileName = it->GetFullFileName();
293 
294  const LIB_TABLE_ROW* row = Prj().SchSymbolLibTable()->FindRowByURI( libFileName );
295 
296  if( row )
297  {
298  LIB_ID id = aSymbol->GetLibId();
299 
300  id.SetLibNickname( row->GetNickName() );
301 
302  // Don't resolve symbol library links now.
303  aSymbol->SetLibId( id, nullptr, nullptr );
304  return true;
305  }
306  }
307  }
308 
309  return false;
310 }
311 
312 
314 {
315  static wxString backupPath = "rescue-backup";
316 
317  wxString tmp;
318  wxString errorMsg;
319  wxFileName srcFileName;
320  wxFileName destFileName;
321  SCH_SCREENS schematic;
322 
323  // Copy backup files to different folder so as not to pollute the project folder.
324  destFileName.SetPath( Prj().GetProjectPath() );
325  destFileName.AppendDir( backupPath );
326 
327  if( !destFileName.DirExists() )
328  {
329  if( !destFileName.Mkdir() )
330  {
331  errorMsg.Printf( _( "Cannot create project remap back up folder \"%s\"." ),
332  destFileName.GetPath() );
333 
334  wxMessageDialog dlg( this, errorMsg, _( "Backup Error" ),
335  wxYES_NO | wxCENTRE | wxRESIZE_BORDER | wxICON_QUESTION );
336  dlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Continue with Rescue" ) ),
337  wxMessageDialog::ButtonLabel( _( "Abort Rescue" ) ) );
338 
339  if( dlg.ShowModal() == wxID_NO )
340  return false;
341  }
342  }
343 
344  // Time stamp to append to file name in case multiple remappings are performed.
345  wxString timeStamp = wxDateTime::Now().Format( "-%Y-%m-%d-%H-%M-%S" );
346 
347  // Back up symbol library table.
348  srcFileName.SetPath( Prj().GetProjectPath() );
349  srcFileName.SetName( SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
350  destFileName = srcFileName;
351  destFileName.AppendDir( backupPath );
352  destFileName.SetName( destFileName.GetName() + timeStamp );
353 
354  tmp.Printf( _( "Backing up file \"%s\" to file \"%s\"." ),
355  srcFileName.GetFullPath(), destFileName.GetFullPath() );
356  aReporter.Report( tmp, REPORTER::RPT_INFO );
357 
358  if( wxFileName::Exists( srcFileName.GetFullPath() )
359  && !wxCopyFile( srcFileName.GetFullPath(), destFileName.GetFullPath() ) )
360  {
361  tmp.Printf( _( "Failed to back up file \"%s\".\n" ), srcFileName.GetFullPath() );
362  errorMsg += tmp;
363  }
364 
365  // Back up the schematic files.
366  for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
367  {
368  destFileName = screen->GetFileName();
369  destFileName.SetName( destFileName.GetName() + timeStamp );
370  destFileName.AppendDir( backupPath );
371 
372  tmp.Printf( _( "Backing up file \"%s\" to file \"%s\"." ),
373  screen->GetFileName(), destFileName.GetFullPath() );
374  aReporter.Report( tmp, REPORTER::RPT_INFO );
375 
376  if( wxFileName::Exists( screen->GetFileName() )
377  && !wxCopyFile( screen->GetFileName(), destFileName.GetFullPath() ) )
378  {
379  tmp.Printf( _( "Failed to back up file \"%s\".\n" ), screen->GetFileName() );
380  errorMsg += tmp;
381  }
382  }
383 
384  // Back up the project file.
385  destFileName = Prj().GetProjectFullName();
386  destFileName.SetName( destFileName.GetName() + timeStamp );
387  destFileName.AppendDir( backupPath );
388 
389  tmp.Printf( _( "Backing up file \"%s\" to file \"%s\"." ),
390  Prj().GetProjectFullName(), destFileName.GetFullPath() );
391  aReporter.Report( tmp, REPORTER::RPT_INFO );
392 
393  if( wxFileName::Exists( Prj().GetProjectFullName() )
394  && !wxCopyFile( Prj().GetProjectFullName(), destFileName.GetFullPath() ) )
395  {
396  tmp.Printf( _( "Failed to back up file \"%s\".\n" ), Prj().GetProjectFullName() );
397  errorMsg += tmp;
398  }
399 
400  // Back up the cache library.
401  srcFileName.SetPath( Prj().GetProjectPath() );
402  srcFileName.SetName( Prj().GetProjectName() + "-cache" );
403  srcFileName.SetExt( SchematicLibraryFileExtension );
404 
405  destFileName = srcFileName;
406  destFileName.SetName( destFileName.GetName() + timeStamp );
407  destFileName.AppendDir( backupPath );
408 
409  tmp.Printf( _( "Backing up file \"%s\" to file \"%s\"." ),
410  srcFileName.GetFullPath(), destFileName.GetFullPath() );
411  aReporter.Report( tmp, REPORTER::RPT_INFO );
412 
413  if( srcFileName.Exists()
414  && !wxCopyFile( srcFileName.GetFullPath(), destFileName.GetFullPath() ) )
415  {
416  tmp.Printf( _( "Failed to back up file \"%s\".\n" ), srcFileName.GetFullPath() );
417  errorMsg += tmp;
418  }
419 
420  // Back up the rescue symbol library if it exists.
421  srcFileName.SetName( Prj().GetProjectName() + "-rescue" );
422  destFileName.SetName( srcFileName.GetName() + timeStamp );
423 
424  tmp.Printf( _( "Backing up file \"%s\" to file \"%s\"." ),
425  srcFileName.GetFullPath(), destFileName.GetFullPath() );
426  aReporter.Report( tmp, REPORTER::RPT_INFO );
427 
428  if( srcFileName.Exists()
429  && !wxCopyFile( srcFileName.GetFullPath(), destFileName.GetFullPath() ) )
430  {
431  tmp.Printf( _( "Failed to back up file \"%s\".\n" ), srcFileName.GetFullPath() );
432  errorMsg += tmp;
433  }
434 
435  // Back up the rescue symbol library document file if it exists.
436  srcFileName.SetExt( "dcm" );
437  destFileName.SetExt( srcFileName.GetExt() );
438 
439  tmp.Printf( _( "Backing up file \"%s\" to file \"%s\"." ),
440  srcFileName.GetFullPath(), destFileName.GetFullPath() );
441  aReporter.Report( tmp, REPORTER::RPT_INFO );
442 
443  if( srcFileName.Exists()
444  && !wxCopyFile( srcFileName.GetFullPath(), destFileName.GetFullPath() ) )
445  {
446  tmp.Printf( _( "Failed to back up file \"%s\".\n" ), srcFileName.GetFullPath() );
447  errorMsg += tmp;
448  }
449 
450  if( !errorMsg.IsEmpty() )
451  {
452  wxMessageDialog dlg( this, _( "Some of the project files could not be backed up." ),
453  _( "Backup Error" ),
454  wxYES_NO | wxCENTRE | wxRESIZE_BORDER | wxICON_QUESTION );
455  errorMsg.Trim();
456  dlg.SetExtendedMessage( errorMsg );
457  dlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Continue with Rescue" ) ),
458  wxMessageDialog::ButtonLabel( _( "Abort Rescue" ) ) );
459 
460  if( dlg.ShowModal() == wxID_NO )
461  return false;
462  }
463 
464  return true;
465 }
466 
467 
468 void DIALOG_SYMBOL_REMAP::OnUpdateUIRemapButton( wxUpdateUIEvent& aEvent )
469 {
470  aEvent.Enable( !m_remapped );
471 }
Definition of the SCH_SHEET class for Eeschema.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:227
static const wxString & GetSymbolLibTableFileName()
static SYMBOL_LIB_TABLE & GetGlobalLibTable()
Part library alias object definition.
SCH_SCREEN * GetNext()
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
void OnUpdateUIRemapButton(wxUpdateUIEvent &aEvent) override
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).
Hold a record identifying a library accessed by the appropriate plug in object in the LIB_TABLE...
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
This file is part of the common library.
size_t getLibsNotInGlobalSymbolLibTable(std::vector< PART_LIB * > &aLibs)
Add libraries found in the legacy library list to aLibs that are not found in the global symbol libra...
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
Definition: sch_io_mgr.cpp:76
VTBL_ENTRY const wxString GetProjectFullName() const
Function GetProjectFullName returns the full path and name of the project.
Definition: project.cpp:94
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:65
Schematic editor (Eeschema) main window.
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
SCH_ITEM * Next() const
This file contains miscellaneous commonly used macros and functions.
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:217
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
Class DIALOG_SYMBOL_REMAP_BASE.
void SetLibId(const LIB_ID &aName, PART_LIBS *aLibs=NULL)
void OnRemapSymbols(wxCommandEvent &aEvent) override
wxString wx_str() const
Definition: utf8.cpp:48
void createProjectSymbolLibTable(REPORTER &aReporter)
bool empty() const
Definition: utf8.h:108
const UTF8 & GetLibItemName() const
Definition: lib_id.h:115
REPORTER & Reporter()
returns the reporter object that reports to this panel
void remapSymbolsToLibTable(REPORTER &aReporter)
The common library.
DIALOG_SYMBOL_REMAP(SCH_EDIT_FRAME *aParent)
virtual void Format(OUTPUTFORMATTER *aOutput, int aIndentLevel) const override
Generate the table in s-expression format to aOutput with an indention level of aIndentLevel.
WX_HTML_REPORT_PANEL * m_messagePanel
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:219
A collection of PART_LIB objects.
Definitions for the Eeschema program SCH_SCREEN class.
bool backupProject(REPORTER &aReporter)
Backup all of the files that could be modified by the remapping with a time stamp appended to the fil...
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:138
bool remapSymbolToLibTable(SCH_COMPONENT *aSymbol)
Definition the SCH_COMPONENT class for Eeschema.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
const wxString & GetNickName() const
see class PGM_BASE
void UpdateSymbolLinks(bool aForce=false)
Initialize or reinitialize the weak reference to the LIB_PART for each SCH_COMPONENT found in the ful...
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const PROJECT *aProject)
Helper functions to substitute paths with environmental variables.
Definition: env_paths.cpp:68
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
const LIB_ID & GetLibId() const
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
Class FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
SCH_SCREEN * GetFirst()
Definition for part library class.
void SetModify()
Definition: base_screen.h:324
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:98
bool RescueLegacyProject(bool aRunningOnDemand)
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:272
const wxString SchematicLibraryFileExtension
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...
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:503
bool IsEmpty(bool aIncludeFallback=true)
Return true if the table is empty.
std::vector< wxString > GetLogicalLibs()
Return the logical library names, all of them that are pertinent to a look up done on this LIB_TABLE...