KiCad PCB EDA Suite
eeschema/files-io.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) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
6  * Copyright (C) 2013 CERN (www.cern.ch)
7  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
31 #include <fctsys.h>
32 #include <class_drawpanel.h>
33 #include <confirm.h>
34 #include <gestfich.h>
35 #include <sch_edit_frame.h>
36 #include <pgm_base.h>
37 #include <kiface_i.h>
38 #include <richio.h>
39 #include <trace_helpers.h>
40 
41 #include <eeschema_id.h>
42 #include <class_library.h>
43 #include <lib_edit_frame.h>
44 #include <sch_sheet.h>
45 #include <sch_sheet_path.h>
46 #include <sch_component.h>
48 #include <project_rescue.h>
49 #include <eeschema_config.h>
50 #include <sch_legacy_plugin.h>
51 #include <sch_eagle_plugin.h>
52 #include <symbol_lib_table.h>
53 #include <dialog_symbol_remap.h>
55 
56 
57 bool SCH_EDIT_FRAME::SaveEEFile( SCH_SCREEN* aScreen, bool aSaveUnderNewName,
58  bool aCreateBackupFile )
59 {
60  wxString msg;
61  wxFileName schematicFileName;
62  bool success;
63 
64  if( aScreen == NULL )
65  aScreen = GetScreen();
66 
67  // If no name exists in the window yet - save as new.
68  if( aScreen->GetFileName().IsEmpty() )
69  aSaveUnderNewName = true;
70 
71  // Construct the name of the file to be saved
72  schematicFileName = Prj().AbsolutePath( aScreen->GetFileName() );
73 
74  if( aSaveUnderNewName )
75  {
76  wxFileDialog dlg( this, _( "Schematic Files" ),
77  wxPathOnly( Prj().GetProjectFullName() ),
78  schematicFileName.GetFullName(), SchematicFileWildcard(),
79  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
80 
81  if( dlg.ShowModal() == wxID_CANCEL )
82  return false;
83 
84  schematicFileName = dlg.GetPath();
85 
86  if( schematicFileName.GetExt() != SchematicFileExtension )
87  schematicFileName.SetExt( SchematicFileExtension );
88  }
89 
90  if( !IsWritable( schematicFileName ) )
91  return false;
92 
93  // Create backup if requested
94  if( aCreateBackupFile && schematicFileName.FileExists() )
95  {
96  wxFileName backupFileName = schematicFileName;
97 
98  // Rename the old file to a '.bak' one:
99  backupFileName.SetExt( SchematicBackupFileExtension );
100 
101  if( backupFileName.FileExists() )
102  wxRemoveFile( backupFileName.GetFullPath() );
103 
104  if( !wxRenameFile( schematicFileName.GetFullPath(), backupFileName.GetFullPath() ) )
105  {
106  msg.Printf( _( "Could not save backup of file \"%s\"" ),
107  GetChars( schematicFileName.GetFullPath() ) );
108  DisplayError( this, msg );
109  }
110  }
111 
112  // Save
113  wxLogTrace( traceAutoSave,
114  wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) );
115 
116  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
117 
118  try
119  {
120  pi->Save( schematicFileName.GetFullPath(), aScreen, &Kiway() );
121  success = true;
122  }
123  catch( const IO_ERROR& ioe )
124  {
125  msg.Printf( _( "Error saving schematic file \"%s\".\n%s" ),
126  GetChars( schematicFileName.GetFullPath() ), GetChars( ioe.What() ) );
127  DisplayError( this, msg );
128 
129  msg.Printf( _( "Failed to save \"%s\"" ), GetChars( schematicFileName.GetFullPath() ) );
130  AppendMsgPanel( wxEmptyString, msg, CYAN );
131 
132  success = false;
133  }
134 
135  if( success )
136  {
137  // Delete auto save file.
138  wxFileName autoSaveFileName = schematicFileName;
139  autoSaveFileName.SetName( AUTOSAVE_PREFIX_FILENAME + schematicFileName.GetName() );
140 
141  if( autoSaveFileName.FileExists() )
142  {
143  wxLogTrace( traceAutoSave,
144  wxT( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() +
145  wxT( ">" ) );
146 
147  wxRemoveFile( autoSaveFileName.GetFullPath() );
148  }
149 
150  // Update the screen and frame info.
151  if( aSaveUnderNewName )
152  aScreen->SetFileName( schematicFileName.GetFullPath() );
153 
154  aScreen->ClrSave();
155  aScreen->ClrModify();
156 
157  msg.Printf( _( "File %s saved" ), GetChars( aScreen->GetFileName() ) );
158  SetStatusText( msg, 0 );
159  }
160  else
161  {
162  DisplayError( this, _( "File write operation failed." ) );
163  }
164 
165  return success;
166 }
167 
168 
169 void SCH_EDIT_FRAME::Save_File( wxCommandEvent& event )
170 {
171  int id = event.GetId();
172 
173  switch( id )
174  {
175  case ID_UPDATE_ONE_SHEET:
176  SaveEEFile( NULL );
177  break;
178 
180  if( SaveEEFile( NULL, true ) )
181  {
183  }
184  break;
185  }
186 
187  UpdateTitle();
188 }
189 
190 
191 bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
192 {
193  // implement the pseudo code from KIWAY_PLAYER.h:
194 
195  // This is for python:
196  if( aFileSet.size() != 1 )
197  {
198  UTF8 msg = StrPrintf( "Eeschema:%s() takes only a single filename.", __func__ );
199  DisplayError( this, msg );
200  return false;
201  }
202 
203  wxString fullFileName( aFileSet[0] );
204 
205  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
206  wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(),
207  wxT( "bug in single_top.cpp or project manager." ) );
208 
209  if( !LockFile( fullFileName ) )
210  {
211  wxString msg = wxString::Format( _(
212  "Schematic file \"%s\" is already open." ),
213  GetChars( fullFileName )
214  );
215  DisplayError( this, msg );
216  return false;
217  }
218 
219  if( !AskToSaveChanges() )
220  return false;
221 
222  wxFileName pro = fullFileName;
223  pro.SetExt( ProjectFileExtension );
224 
225  bool is_new = !wxFileName::IsFileReadable( fullFileName );
226 
227  // If its a non-existent schematic and caller thinks it exists
228  if( is_new && !( aCtl & KICTL_CREATE ) )
229  {
230  // notify user that fullFileName does not exist, ask if user wants to create it.
231  wxString ask = wxString::Format( _(
232  "Schematic \"%s\" does not exist. Do you wish to create it?" ),
233  GetChars( fullFileName )
234  );
235  if( !IsOK( this, ask ) )
236  return false;
237  }
238 
239  // unload current project file before loading new
240  {
241  delete g_RootSheet;
242  g_RootSheet = NULL;
243 
244  CreateScreens();
245  }
246 
247  GetScreen()->SetFileName( fullFileName );
248  g_RootSheet->SetFileName( fullFileName );
249 
250  SetStatusText( wxEmptyString );
251  ClearMsgPanel();
252 
253  // PROJECT::SetProjectFullName() is an impactful function. It should only be
254  // called under carefully considered circumstances.
255 
256  // The calling code should know not to ask me here to change projects unless
257  // it knows what consequences that will have on other KIFACEs running and using
258  // this same PROJECT. It can be very harmful if that calling code is stupid.
259 
260  // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
261  // They are already saved in the kiface project object.
262  if( pro.GetFullPath() != Prj().GetProjectFullName()
264  {
265  Prj().SetProjectFullName( pro.GetFullPath() );
266 
267  // load the libraries here, not in SCH_SCREEN::Draw() which is a context
268  // that will not tolerate DisplayError() dialog since we're already in an
269  // event handler in there.
270  // And when a schematic file is loaded, we need these libs to initialize
271  // some parameters (links to PART LIB, dangling ends ...)
273  Prj().SchLibs();
274  }
275 
276  LoadProjectFile();
277 
278  // Load the symbol library table, this will be used forever more.
280  Prj().SchSymbolLibTable();
281 
282  if( is_new )
283  {
284  // mark new, unsaved file as modified.
285  GetScreen()->SetModify();
286  }
287  else
288  {
289  delete g_RootSheet; // Delete the current project.
290  g_RootSheet = NULL; // Force CreateScreens() to build new empty project on load failure.
291  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
292 
293  try
294  {
295  g_RootSheet = pi->Load( fullFileName, &Kiway() );
296  m_CurrentSheet->clear();
297  m_CurrentSheet->push_back( g_RootSheet );
298 
299  if( !pi->GetError().IsEmpty() )
300  {
301  DisplayErrorMessage( this,
302  _( "The entire schematic could not be loaded. Errors "
303  "occurred attempting to load \nhierarchical sheet "
304  "schematics." ),
305  pi->GetError() );
306  }
307  }
308  catch( const IO_ERROR& ioe )
309  {
310  // Do not leave g_RootSheet == NULL because it is expected to be
311  // a valid sheet. Therefore create a dummy empty root sheet and screen.
312  CreateScreens();
313  Zoom_Automatique( false );
314 
315  wxString msg;
316  msg.Printf( _( "Error loading schematic file \"%s\".\n%s" ),
317  GetChars( fullFileName ), GetChars( ioe.What() ) );
318  DisplayError( this, msg );
319 
320  msg.Printf( _( "Failed to load \"%s\"" ), GetChars( fullFileName ) );
321  AppendMsgPanel( wxEmptyString, msg, CYAN );
322 
323  return false;
324  }
325 
327 
328  // It's possible the schematic parser fixed errors due to bugs so warn the user
329  // that the schematic has been fixed (modified).
330  SCH_SHEET_LIST sheetList( g_RootSheet );
331 
332  if( sheetList.IsModified() )
333  {
334  DisplayInfoMessage( this,
335  _( "An error was found when loading the schematic that has "
336  "been automatically fixed. Please save the schematic to "
337  "repair the broken file or it may not be usable with other "
338  "versions of KiCad." ) );
339  }
340 
341  UpdateFileHistory( fullFileName );
342 
343  SCH_SCREENS schematic;
344 
345  // Convert old projects over to use symbol library table.
346  if( schematic.HasNoFullyDefinedLibIds() )
347  {
348  DIALOG_SYMBOL_REMAP dlgRemap( this );
349 
350  dlgRemap.ShowQuasiModal();
351  }
352  else
353  {
354  // Check to see whether some old library parts need to be rescued
355  // Only do this if RescueNeverShow was not set.
356  wxConfigBase *config = Kiface().KifaceSettings();
357  bool rescueNeverShow = false;
358  config->Read( RescueNeverShowEntry, &rescueNeverShow, false );
359 
360  if( !rescueNeverShow )
362  }
363 
364  schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
365 
366  // Ensure the schematic is fully segmented on first display
368  SchematicCleanUp( true );
369  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
370  GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
371  }
372 
374  Zoom_Automatique( false );
376  m_canvas->Refresh( true );
378 
379  return true;
380 }
381 
382 
384 {
385  wxString msg;
386  wxString fullFileName;
387 
388  SCH_SCREEN* screen = GetScreen();
389 
390  if( !screen )
391  {
392  wxLogError( wxT( "Document not ready, cannot import" ) );
393  return false;
394  }
395 
396  // open file chooser dialog
397  wxString path = wxPathOnly( Prj().GetProjectFullName() );
398 
399  wxFileDialog dlg( this, _( "Append Schematic" ), path,
400  wxEmptyString, SchematicFileWildcard(),
401  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
402 
403  if( dlg.ShowModal() == wxID_CANCEL )
404  return false;
405 
406  fullFileName = dlg.GetPath();
407 
408  wxFileName fn = fullFileName;
409 
410  if( fn.IsRelative() )
411  {
412  fn.MakeAbsolute();
413  fullFileName = fn.GetFullPath();
414  }
415 
416  wxString cache_name = PART_LIBS::CacheName( fullFileName );
417 
418  if( !!cache_name )
419  {
420  PART_LIBS* libs = Prj().SchLibs();
421 
422  try
423  {
424  if( PART_LIB* lib = libs->AddLibrary( cache_name ) )
425  lib->SetCache();
426  }
427  catch( const IO_ERROR& ioe )
428  {
429  DisplayError( this, ioe.What() );
430  }
431  }
432 
433  wxLogDebug( wxT( "Importing schematic " ) + fullFileName );
434 
435  // Load the schematic into a temporary sheet.
436  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
437  std::unique_ptr< SCH_SHEET> newSheet( new SCH_SHEET );
438 
439  newSheet->SetFileName( fullFileName );
440 
441  try
442  {
443  pi->Load( fullFileName, &Kiway(), newSheet.get() );
444 
445  if( !pi->GetError().IsEmpty() )
446  {
447  DisplayErrorMessage( this,
448  _( "The entire schematic could not be load. Errors "
449  "occurred attempting to load hierarchical sheet "
450  "schematics." ),
451  pi->GetError() );
452  }
453  }
454  catch( const IO_ERROR& ioe )
455  {
456  msg.Printf( _( "Error occurred loading schematic file \"%s\"." ), fullFileName );
457  DisplayErrorMessage( this, msg, ioe.What() );
458 
459  msg.Printf( _( "Failed to load schematic \"%s\"" ), fullFileName );
460  AppendMsgPanel( wxEmptyString, msg, CYAN );
461 
462  return false;
463  }
464 
465  // Make sure any new sheet changes do not cause any recursion issues.
466  SCH_SHEET_LIST hierarchy( g_RootSheet ); // This is the schematic sheet hierarchy.
467  SCH_SHEET_LIST sheetHierarchy( newSheet.get() ); // This is the hierarchy of the import.
468 
469  wxFileName destFile = screen->GetFileName();
470 
471  if( destFile.IsRelative() )
472  destFile.MakeAbsolute( Prj().GetProjectPath() );
473 
474  if( hierarchy.TestForRecursion( sheetHierarchy, destFile.GetFullPath( wxPATH_UNIX ) ) )
475  {
476  msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
477  "has the sheet \"%s\" or one of it's subsheets as a parent somewhere in "
478  "the schematic hierarchy." ),
479  destFile.GetFullPath() );
480  DisplayError( this, msg );
481  return false;
482  }
483 
484  wxArrayString names;
485 
486  // Make sure the imported schematic has been remapped to the symbol library table.
487  SCH_SCREENS newScreens( newSheet.get() ); // All screens associated with the import.
488 
489  if( newScreens.HasNoFullyDefinedLibIds() )
490  {
491  if( !IsOK( this,
492  "This schematic has not been remapped to the symbol library table. "
493  "Therefore, all of the library symbol links will be broken. Do you "
494  "want to continue?" ) )
495  return false;
496  }
497  else
498  {
499  // If there are symbol libraries in the imported schematic that are not in the
500  // symbol library table of this project, there could be a lot of broken symbol
501  // library links. Attempt to add the missing libraries to the project symbol
502  // library table.
503  newScreens.GetLibNicknames( names );
504  wxArrayString newLibNames;
505 
506  for( const auto& name : names )
507  {
508  if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
509  newLibNames.Add( name );
510  }
511 
512  wxFileName symLibTableFn( fn.GetPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
513 
514  if( !newLibNames.IsEmpty() && symLibTableFn.Exists() && symLibTableFn.IsFileReadable() )
515  {
516  SYMBOL_LIB_TABLE table;
517 
518  try
519  {
520  table.Load( symLibTableFn.GetFullPath() );
521  }
522  catch( const IO_ERROR& ioe )
523  {
524  msg.Printf( _( "An error occurred loading the symbol library table \"%s\"." ),
525  symLibTableFn.GetFullPath() );
526  DisplayErrorMessage( NULL, msg, ioe.What() );
527  }
528 
529  if( !table.IsEmpty() )
530  {
531  for( const auto& libName : newLibNames )
532  {
533  if( !table.HasLibrary( libName ) )
534  continue;
535 
536  // Don't expand environment variable because KIPRJMOD will not be correct
537  // for a different project.
538  wxString uri = table.GetFullURI( libName, false );
539 
540  wxFileName newLib;
541 
542  if( uri.Contains( "${KIPRJMOD}" ) )
543  {
544  newLib.SetPath( fn.GetPath() );
545  newLib.SetFullName( uri.AfterLast( '}' ) );
546  uri = newLib.GetFullPath();
547  }
548  else if( uri.Contains( "$(KIPRJMOD)" ) )
549  {
550  newLib.SetPath( fn.GetPath() );
551  newLib.SetFullName( uri.AfterLast( ')' ) );
552  uri = newLib.GetFullPath();
553  }
554  else
555  {
556  uri = table.GetFullURI( libName );
557  }
558 
559  // Add the library from the imported project to the current project
560  // symbol library table.
561  const SYMBOL_LIB_TABLE_ROW* row = table.FindRow( libName );
562 
563  wxCHECK2_MSG( row, continue, "Library '" + libName +
564  "' missing from symbol library table '" +
565  symLibTableFn.GetFullPath() + "'." );
566 
567  wxString newLibName = libName;
568  int libNameCnt = 1;
569 
570  // Rename the imported symbol library if it already exists.
571  while( Prj().SchSymbolLibTable()->HasLibrary( newLibName ) )
572  {
573  newLibName = wxString::Format( "%s%d", libName, libNameCnt );
574  }
575 
576  SYMBOL_LIB_TABLE_ROW* newRow = new SYMBOL_LIB_TABLE_ROW( newLibName,
577  uri,
578  row->GetType(),
579  row->GetOptions(),
580  row->GetDescr() );
581  Prj().SchSymbolLibTable()->InsertRow( newRow );
582 
583  if( libName != newLibName )
584  newScreens.ChangeSymbolLibNickname( libName, newLibName );
585  }
586  }
587  }
588  }
589 
590  // Check for duplicate sheet names in the current page.
591  wxArrayString duplicateSheetNames;
592  SCH_TYPE_COLLECTOR sheets;
593 
594  sheets.Collect( screen->GetDrawItems(), SCH_COLLECTOR::SheetsOnly );
595 
596  for( int i = 0; i < sheets.GetCount(); ++i )
597  {
598  if( newSheet->GetScreen()->GetSheet( ( ( SCH_SHEET* ) sheets[i] )->GetName() ) )
599  duplicateSheetNames.Add( ( ( SCH_SHEET* ) sheets[i] )->GetName() );
600  }
601 
602  if( !duplicateSheetNames.IsEmpty() )
603  {
604  msg.Printf( "Duplicate sheet names exist on the current page. Do you want to "
605  "automatically rename the duplicate sheet names?" );
606  if( !IsOK( this, msg ) )
607  return false;
608  }
609 
610  SCH_SCREEN* newScreen = newSheet->GetScreen();
611  wxCHECK_MSG( newScreen, false, "No screen defined for imported sheet." );
612 
613  for( const auto& duplicateName : duplicateSheetNames )
614  {
615  SCH_SHEET* renamedSheet = newScreen->GetSheet( duplicateName );
616 
617  wxCHECK2_MSG( renamedSheet, continue,
618  "Sheet " + duplicateName + " not found in imported schematic." );
619 
620  timestamp_t newtimestamp = GetNewTimeStamp();
621  renamedSheet->SetTimeStamp( newtimestamp );
622  renamedSheet->SetName( wxString::Format( "Sheet%8.8lX", (unsigned long) newtimestamp ) );
623  }
624 
625  // It is finally safe to add the imported schematic.
626  screen->Append( newScreen );
627 
628  SCH_SCREENS allScreens;
629  allScreens.ReplaceDuplicateTimeStamps();
630 
631  OnModify();
632 
633  SCH_SCREENS screens( GetCurrentSheet().Last() );
634  screens.UpdateSymbolLinks( true );
635 
636  // Clear all annotation in the imported schematic to prevent clashes with existing annotation.
637  // Must be done after updating the symbol links as we need to know about multi-unit parts.
638  screens.ClearAnnotation();
639 
641  Zoom_Automatique( false );
643  m_canvas->Refresh( true );
644  return true;
645 }
646 
647 
648 void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event )
649 {
650  if( GetScreen() && GetScreen()->IsModified() )
651  {
652  wxString msg = _( "This operation cannot be undone.\n\n"
653  "Do you want to save the current document before proceeding?" );
654 
655  if( IsOK( this, msg ) )
656  OnSaveProject( event );
657  }
658 
659  AppendSchematic();
660 }
661 
662 
663 void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
664 {
665  if( !AskToSaveChanges() )
666  return;
667 
668  // Set the project location if none is set
669  bool setProject = Prj().GetProjectFullName().IsEmpty();
670  wxString path = wxPathOnly( Prj().GetProjectFullName() );
671 
672  wxFileDialog dlg( this, _( "Import Schematic" ), path,
673  wxEmptyString, EagleSchematicFileWildcard(),
674  wxFD_OPEN | wxFD_FILE_MUST_EXIST );
675 
676  if( dlg.ShowModal() == wxID_CANCEL )
677  return;
678 
679  if( setProject )
680  {
681  wxFileName projectFn( dlg.GetPath() );
682  projectFn.SetExt( ProjectFileExtension );
683  Prj().SetProjectFullName( projectFn.GetFullPath() );
684  }
685 
686  // For now there is only one import plugin
687  importFile( dlg.GetPath(), SCH_IO_MGR::SCH_EAGLE );
688 }
689 
690 
691 void SCH_EDIT_FRAME::OnSaveProject( wxCommandEvent& aEvent )
692 {
693  SCH_SCREEN* screen;
694  SCH_SCREENS screenList;
695 
696  // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
697  wxString fileName = Prj().AbsolutePath( g_RootSheet->GetFileName() );
698 
699  wxFileName fn = fileName;
700 
701  if( !fn.IsDirWritable() )
702  {
703  wxString msg = wxString::Format( _( "Directory \"%s\" is not writable." ), fn.GetPath() );
704 
705  DisplayError( this, msg );
706  return;
707  }
708 
709  for( screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
710  SaveEEFile( screen );
711 
713 
714  UpdateTitle();
715 }
716 
717 
719 {
720  wxFileName tmpFileName = g_RootSheet->GetFileName();
721  wxFileName fn = tmpFileName;
722  wxFileName tmp;
723  SCH_SCREENS screens;
724 
725  bool autoSaveOk = true;
726 
727  tmp.AssignDir( fn.GetPath() );
728 
729  if( !tmp.IsOk() )
730  return false;
731 
732  if( !IsWritable( tmp ) )
733  return false;
734 
735  for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
736  {
737  // Only create auto save files for the schematics that have been modified.
738  if( !screen->IsSave() )
739  continue;
740 
741  tmpFileName = fn = screen->GetFileName();
742 
743  // Auto save file name is the normal file name prefixed with AUTOSAVE_PREFIX_FILENAME.
744  fn.SetName( AUTOSAVE_PREFIX_FILENAME + fn.GetName() );
745 
746  screen->SetFileName( fn.GetFullPath() );
747 
748  if( SaveEEFile( screen, false, NO_BACKUP_FILE ) )
749  screen->SetModify();
750  else
751  autoSaveOk = false;
752 
753  screen->SetFileName( tmpFileName.GetFullPath() );
754  }
755 
756  if( autoSaveOk )
757  m_autoSaveState = false;
758 
759  return autoSaveOk;
760 }
761 
762 
763 bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
764 {
765  wxString fullFileName( aFileName );
766  wxString projectpath;
767  wxFileName newfilename;
768  SCH_SHEET_LIST sheetList( g_RootSheet );
769 
770  switch( (SCH_IO_MGR::SCH_FILE_T) aFileType )
771  {
772  case SCH_IO_MGR::SCH_EAGLE:
773  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
774  wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(),
775  wxT( "Import eagle schematic caller didn't send full filename" ) );
776 
777  if( !LockFile( fullFileName ) )
778  {
779  wxString msg = wxString::Format( _( "Schematic file \"%s\" is already open." ),
780  GetChars( fullFileName ) );
781  DisplayError( this, msg );
782  return false;
783  }
784 
785  try
786  {
787  delete g_RootSheet;
788  g_RootSheet = nullptr;
789  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EAGLE ) );
790  g_RootSheet = pi->Load( fullFileName, &Kiway() );
791 
792 
793  // Eagle sheets do not use a worksheet frame by default, so set it to an empty one
795  pglayout.SetEmptyLayout();
796 
797  BASE_SCREEN::m_PageLayoutDescrFileName = "empty.kicad_wks";
798  wxFileName layoutfn( Kiway().Prj().GetProjectPath(),
800  wxFile layoutfile;
801 
802  if( layoutfile.Create( layoutfn.GetFullPath() ) )
803  {
804  layoutfile.Write( WORKSHEET_LAYOUT::EmptyLayout() );
805  layoutfile.Close();
806  }
807 
808  projectpath = Kiway().Prj().GetProjectPath();
809  newfilename.SetPath( Prj().GetProjectPath() );
810  newfilename.SetName( Prj().GetProjectName() );
811  newfilename.SetExt( SchematicFileExtension );
812 
813  m_CurrentSheet->clear();
814  m_CurrentSheet->push_back( g_RootSheet );
816 
817  g_RootSheet->SetFileName( newfilename.GetFullPath() );
818  GetScreen()->SetFileName( newfilename.GetFullPath() );
819  GetScreen()->SetModify();
820  SaveProjectSettings( false );
821 
822  UpdateFileHistory( fullFileName );
823  SCH_SCREENS schematic;
824  schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
825 
826  // Ensure the schematic is fully segmented on first display
828  SchematicCleanUp( true );
829 
830 
831  SCH_TYPE_COLLECTOR components;
832  SCH_SCREENS allScreens;
833  for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
834  {
835  components.Collect( screen->GetDrawItems(), SCH_COLLECTOR::ComponentsOnly );
836 
837  for( int cmpIdx = 0; cmpIdx < components.GetCount(); ++cmpIdx )
838  {
839  std::vector<wxPoint> pts;
840  SCH_COMPONENT* cmp = static_cast<SCH_COMPONENT*>( components[cmpIdx] );
841 
842  // Update footprint LIB_ID to point to the imported Eagle library
843  auto fpField = cmp->GetField( FOOTPRINT );
844 
845  if( !fpField->GetText().IsEmpty() )
846  {
847  LIB_ID fpId( fpField->GetText() );
848  fpId.SetLibNickname( newfilename.GetName() );
849  fpField->SetText( fpId.Format() );
850  }
851 
852  // Add junction dots where necessary
853  cmp->GetConnectionPoints( pts );
854 
855  for( auto i = pts.begin(); i != pts.end(); ++i )
856  {
857  if( GetScreen()->IsJunctionNeeded( *i, true ) )
858  AddJunction( *i, true );
859  }
860  }
861  }
862 
863 
864  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
865  // Only perform the dangling end test on root sheet.
867 
869  Zoom_Automatique( false );
871  m_canvas->Refresh( true );
872  UpdateTitle();
873  }
874  catch( const IO_ERROR& ioe )
875  {
876  // Do not leave g_RootSheet == NULL because it is expected to be
877  // a valid sheet. Therefore create a dummy empty root sheet and screen.
878  CreateScreens();
879  Zoom_Automatique( false );
880 
881  wxString msg;
882  msg.Printf( _( "Error loading schematic file \"%s\".\n%s" ),
883  fullFileName, ioe.What() );
884  DisplayError( this, msg );
885 
886  msg.Printf( _( "Failed to load \"%s\"" ), fullFileName );
887  AppendMsgPanel( wxEmptyString, msg, CYAN );
888 
889  return false;
890  }
891 
892  return true;
893 
894  default:
895  return false;
896  }
897 
898  return false;
899 }
900 
901 
903 {
904  SCH_SCREENS screenList;
905 
906  // Save any currently open and modified project files.
907  for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
908  {
909  if( screen->IsModify() )
910  {
911  int response = YesNoCancelDialog( m_parent, _(
912  "The current schematic has been modified. Do you wish to save the changes?" ),
913  wxEmptyString,
914  _( "Save and Load" ),
915  _( "Load Without Saving" )
916  );
917 
918  if( response == wxID_CANCEL )
919  {
920  return false;
921  }
922  else if( response == wxID_YES )
923  {
924  wxCommandEvent dummy;
925  OnSaveProject( dummy );
926  }
927  // else wxID_NO, so do not save
928 
929  break;
930  }
931  }
932 
933  return true;
934 }
Definition of the SCH_SHEET class for Eeschema.
Class UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion supp...
Definition: utf8.h:73
Class SCH_SHEET_LIST.
SCH_JUNCTION * AddJunction(const wxPoint &aPosition, bool aPutInUndoList=false)
Add a new junction at aPosition.
int GetCount() const
Function GetCount returns the number of objects in the list.
Definition: collector.h:106
bool m_autoSaveState
Flag to indicate the last auto save state.
static const wxString & GetSymbolLibTableFileName()
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: base_struct.h:155
SYMBOL_LIB_TABLE_ROW * FindRow(const wxString &aNickName)
Return an SYMBOL_LIB_TABLE_ROW if aNickName is found in this table or in any chained fallBack table f...
bool SchematicCleanUp(bool aAppend=false)
Performs routine schematic cleaning including breaking wire and buses and deleting identical objects ...
SCH_SCREEN * GetNext()
Hold a record identifying a symbol library accessed by the appropriate symbol library SCH_PLUGIN obje...
Class TYPE_COLLECTOR merely gathers up all SCH_ITEMs of a given set of KICAD_T type(s).
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
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
wxString SchematicFileWildcard()
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:199
This file is part of the common library TODO brief description.
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
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:338
This file is part of the common library.
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:467
bool IsJunctionNeeded(const wxPoint &aPosition, bool aNew=false)
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:346
SCH_SHEET * GetSheet(const wxString &aName)
Returns a sheet object pointer that is named aName.
Definition: sch_screen.cpp:645
void OnModify()
Must be called after a schematic change in order to set the "modify" flag of the current screen* and ...
const wxString ProjectFileExtension
void SetScreen(BASE_SCREEN *aScreen)
Definition: draw_frame.h:167
#define KICTL_CREATE
caller thinks requested project files may not exist
Definition: kiway_player.h:131
void GetConnectionPoints(std::vector< wxPoint > &aPoints) const override
Function GetConnectionPoints add all the connection points for this item to aPoints.
const wxString & GetFileName() const
Definition: sch_screen.h:120
bool AskToSaveChanges()
Checks if any of the screens has unsaved changes and asks the user whether to save or drop them...
bool BreakSegmentsOnJunctions(bool aApped=false)
Tests all junctions and bus entries in the schematic for intersections with wires and buses and break...
virtual SCH_SHEET * Load(const wxString &aFileName, KIWAY *aKiway, SCH_SHEET *aAppendToMe=NULL, const PROPERTIES *aProperties=NULL)
Load information from some input file format that this SCH_PLUGIN implementation knows about...
Definition: sch_plugin.cpp:50
const wxChar RescueNeverShowEntry[]
void UpdateTitle()
Set the main window title bar text.
static const KICAD_T ComponentsOnly[]
A scan list for schematic component items only.
void OnAppendProject(wxCommandEvent &event)
VTBL_ENTRY const wxString GetProjectFullName() const
Function GetProjectFullName returns the full path and name of the project.
Definition: project.cpp:96
const wxString & GetOptions() const
Return the options string, which may hold a password or anything else needed to instantiate the under...
virtual wxConfigBase * config()
Function config returns the wxConfigBase used in SaveSettings(), and is overloaded in KICAD_MANAGER_F...
SCH_SCREEN * LastScreen() const
Function LastScreen.
VTBL_ENTRY _ELEM * GetElem(ELEM_T aIndex)
Typically wrapped somewhere else in a more meaningful function wrapper.
Definition: project.cpp:205
bool IsWritable(const wxFileName &aFileName)
Function IsWritable checks if aFileName can be written.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
#define NO_BACKUP_FILE
static const wxString CacheName(const wxString &aFullProjectFilename)
Return the name of the cache library after potentially fixing it from an older naming scheme...
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
Field Name Module PCB, i.e. "16DIP300".
void UpdateFileHistory(const wxString &FullFileName, wxFileHistory *aFileHistory=NULL)
Function UpdateFileHistory Updates the list of recently opened files.
static wxString EmptyLayout()
Returns a string containing the empty layout shape.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
static WORKSHEET_LAYOUT & GetTheInstance()
static function: returns the instance of WORKSHEET_LAYOUT used in the application ...
void SaveProjectSettings(bool aAskForSave) override
Save changes to the project settings to the project (.pro) file.
void OnImportProject(wxCommandEvent &event)
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:217
static wxString m_PageLayoutDescrFileName
the name of the page layout descr file, or emty to used the default pagelayout
Definition: base_screen.h:180
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
SCH_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
SCH_SHEET_PATH * m_CurrentSheet
which sheet we are presently working on.
void Zoom_Automatique(bool aWarpPointer)
Function Zoom_Automatique redraws the screen with best zoom level and the best centering that shows a...
Definition: zoom.cpp:102
timestamp_t GetNewTimeStamp()
Definition: common.cpp:160
void Save_File(wxCommandEvent &event)
const wxString SchematicBackupFileExtension
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library table.
SCH_SHEET * g_RootSheet
Definition: eeschema.cpp:55
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
void SetName(const wxString &aName)
Definition: sch_sheet.h:269
int ShowQuasiModal()
VTBL_ENTRY PROJECT & Prj() const
Function Prj returns the PROJECT associated with this KIWAY.
Definition: kiway.cpp:142
const wxString GetType() const override
Return the type of symbol library table represented by this row.
SCH_SHEET_PATH & GetCurrentSheet()
PART_LIB * AddLibrary(const wxString &aFileName)
Allocate and adds a part library to the library list.
Definition: colors.h:59
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project&#39;s directory to be an absolu...
Definition: project.cpp:383
The common library.
bool AppendSchematic()
Import a KiCad schematic into the current page.
bool SaveEEFile(SCH_SCREEN *aScreen, bool aSaveUnderNewName=false, bool aCreateBackupFile=CREATE_BACKUP_FILE)
Save aScreen to a schematic file.
bool CreateArchiveLibraryCacheFile(bool aUseCurrentSheetFilename=false)
Create a symbol library file with the name of the root document plus the &#39;-cache&#39; suffix...
Definition: libarch.cpp:42
void OnSaveProject(wxCommandEvent &aEvent)
Command event handler to save the entire project and create a component library archive.
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:103
wxLogTrace helper definitions.
bool LoadProjectFile()
Loads the KiCad project file (*.pro) settings specific to Eeschema.
virtual const wxString & GetError() const
Return an error string to the caller.
Definition: sch_plugin.cpp:193
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set...
int m_LastGridSizeId
Definition: draw_frame.h:91
void Load(const wxString &aFileName)
Load the library table using the path defined by aFileName aFallBackTable.
const wxString & GetDescr() const
Return the description of the library referenced by this row.
VTBL_ENTRY void SetProjectFullName(const wxString &aFullPathAndName)
Function SetProjectFullName sets the: 1) full directory, 2) basename, and 3) extension of the project...
Definition: project.cpp:64
wxString GetFileName(void) const
Return the filename corresponding to this sheet.
Definition: sch_sheet.cpp:646
WORKSHEET_LAYOUT handles the graphic items list to draw/plot the title block and other items (page re...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:209
virtual bool doAutoSave() override
Save the schematic files that have been modified and not yet saved.
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.
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:523
EDA_DRAW_PANEL * m_canvas
The area to draw on.
Definition: draw_frame.h:106
void AppendMsgPanel(const wxString &textUpper, const wxString &textLower, COLOR4D color, int pad=6)
Append a message to the message panel.
Definition: draw_frame.cpp:812
wxString GetFullURI(const wxString &aLibNickname, bool aExpandEnvVars=true) const
Return the full URI of the library mapped to aLibNickname.
SCH_ITEM * GetDrawItems() const
Definition: sch_screen.h:138
Definition the SCH_COMPONENT class for Eeschema.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
#define AUTOSAVE_PREFIX_FILENAME
Prefix to create filenames for schematic files or other difile when auto-saved to retrieve a crash...
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
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...
const char * name
Definition: DXF_plotter.cpp:61
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
void Append(SCH_ITEM *aItem)
Definition: sch_screen.h:140
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
void ClearAnnotation()
Clear the annotation for all components in the hierarchy.
wxString EagleSchematicFileWildcard()
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
Definition: sch_screen.cpp:913
void SetEmptyLayout()
Fills the list with an empty layout shape.
size_t i
Definition: json11.cpp:597
void ClrModify()
Definition: base_screen.h:325
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:69
void Collect(SCH_ITEM *aBoard, const KICAD_T aScanList[])
Function Collect scans a BOARD_ITEM using this class&#39;s Inspector method, which does the collection...
VTBL_ENTRY const wxString GetProjectPath() const
Function GetProjectPath returns the full path of the project.
Definition: project.cpp:102
static const KICAD_T SheetsOnly[]
A scan list for schematic sheet items only.
bool RescueSymbolLibTableProject(bool aRunningOnDemand)
Definition of class LIB_EDIT_FRAME.
int ReplaceDuplicateTimeStamps()
Test all sheet and component objects in the schematic for duplicate time stamps and replaces them as ...
classes and function to generate graphics to plt or draw titles blocks and frame references ...
SCH_SCREEN * GetFirst()
void ClearDrawingState()
Clear the state flags of all the items in the screen.
Definition: sch_screen.cpp:582
virtual void ClearUndoORRedoList(UNDO_REDO_CONTAINER &aList, int aItemCount=-1) override
Free the undo or redo list from aList element.
Definition: sch_screen.cpp:567
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:118
Definition for part library class.
void SetModify()
Definition: base_screen.h:324
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
int SetGrid(const wxRealPoint &size)
set the current grid size m_Grid.
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:216
Object used to load, save, search, and otherwise manipulate symbol library files. ...
size_t GetLibNicknames(wxArrayString &aLibNicknames)
Fetch all of the symbol library nickames into aLibNicknames.
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
int YesNoCancelDialog(wxWindow *aParent, const wxString &aPrimaryMessage, const wxString &aSecondaryMessage, const wxString &aYesButtonText, const wxString &aNoButtonText, const wxString &aCancelButtonText)
Function YesNoCancelDialog displays a yes/no/cancel dialog with aMessage and returns the user respons...
Definition: confirm.cpp:270
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:233
void ClrSave()
Definition: base_screen.h:327
void ClearMsgPanel(void)
Clear all messages from the message panel.
Definition: draw_frame.cpp:823
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:503
const wxString SchematicFileExtension
bool IsEmpty(bool aIncludeFallback=true)
Return true if the table is empty.
bool LockFile(const wxString &aFileName)
Function LockFile marks a schematic file as being in use.
Definition: draw_frame.cpp:260
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName) const
Function TestForRecursion.
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:214