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 <sch_draw_panel.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" ), wxPathOnly( Prj().GetProjectFullName() ),
77  schematicFileName.GetFullName(), SchematicFileWildcard(),
78  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
79 
80  if( dlg.ShowModal() == wxID_CANCEL )
81  return false;
82 
83  schematicFileName = dlg.GetPath();
84 
85  if( schematicFileName.GetExt() != SchematicFileExtension )
86  schematicFileName.SetExt( SchematicFileExtension );
87  }
88 
89  if( !IsWritable( schematicFileName ) )
90  return false;
91 
92  // Create backup if requested
93  if( aCreateBackupFile && schematicFileName.FileExists() )
94  {
95  wxFileName backupFileName = schematicFileName;
96 
97  // Rename the old file to a '.bak' one:
98  backupFileName.SetExt( SchematicBackupFileExtension );
99 
100  if( backupFileName.FileExists() )
101  wxRemoveFile( backupFileName.GetFullPath() );
102 
103  if( !wxRenameFile( schematicFileName.GetFullPath(), backupFileName.GetFullPath() ) )
104  {
105  msg.Printf( _( "Could not save backup of file \"%s\"" ),
106  GetChars( schematicFileName.GetFullPath() ) );
107  DisplayError( this, msg );
108  }
109  }
110 
111  // Save
112  wxLogTrace( traceAutoSave,
113  wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) );
114 
115  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
116 
117  try
118  {
119  pi->Save( schematicFileName.GetFullPath(), aScreen, &Kiway() );
120  success = true;
121  }
122  catch( const IO_ERROR& ioe )
123  {
124  msg.Printf( _( "Error saving schematic file \"%s\".\n%s" ),
125  GetChars( schematicFileName.GetFullPath() ), GetChars( ioe.What() ) );
126  DisplayError( this, msg );
127 
128  msg.Printf( _( "Failed to save \"%s\"" ), GetChars( schematicFileName.GetFullPath() ) );
129  AppendMsgPanel( wxEmptyString, msg, CYAN );
130 
131  success = false;
132  }
133 
134  if( success )
135  {
136  // Delete auto save file.
137  wxFileName autoSaveFileName = schematicFileName;
138  autoSaveFileName.SetName( AUTOSAVE_PREFIX_FILENAME + schematicFileName.GetName() );
139 
140  if( autoSaveFileName.FileExists() )
141  {
142  wxLogTrace( traceAutoSave,
143  wxT( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() +
144  wxT( ">" ) );
145 
146  wxRemoveFile( autoSaveFileName.GetFullPath() );
147  }
148 
149  // Update the screen and frame info and reset the lock file.
150  if( aSaveUnderNewName )
151  {
152  aScreen->SetFileName( schematicFileName.GetFullPath() );
153  LockFile( schematicFileName.GetFullPath() );
154  }
155 
156  aScreen->ClrSave();
157  aScreen->ClrModify();
158 
159  msg.Printf( _( "File %s saved" ), GetChars( aScreen->GetFileName() ) );
160  SetStatusText( msg, 0 );
161  }
162  else
163  {
164  DisplayError( this, _( "File write operation failed." ) );
165  }
166 
167  return success;
168 }
169 
170 
171 void SCH_EDIT_FRAME::Save_File( wxCommandEvent& event )
172 {
173  int id = event.GetId();
174 
175  switch( id )
176  {
177  case ID_UPDATE_ONE_SHEET:
178  SaveEEFile( NULL );
179  break;
180 
182  if( SaveEEFile( NULL, true ) )
183  {
185  }
186  break;
187  }
188 
189  UpdateTitle();
190 }
191 
192 
193 bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
194 {
195  // implement the pseudo code from KIWAY_PLAYER.h:
196 
197  // This is for python:
198  if( aFileSet.size() != 1 )
199  {
200  UTF8 msg = StrPrintf( "Eeschema:%s() takes only a single filename.", __func__ );
201  DisplayError( this, msg );
202  return false;
203  }
204 
205  wxString fullFileName( aFileSet[0] );
206 
207  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
208  wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "Path is not absolute!" ) );
209 
210  if( !LockFile( fullFileName ) )
211  {
212  wxString msg = wxString::Format( _( "Schematic file \"%s\" is already open." ),
213  fullFileName );
214  DisplayError( this, msg );
215  return false;
216  }
217 
218  if( !AskToSaveChanges() )
219  return false;
220 
221  wxFileName pro = fullFileName;
222  pro.SetExt( ProjectFileExtension );
223 
224  bool is_new = !wxFileName::IsFileReadable( fullFileName );
225 
226  // If its a non-existent schematic and caller thinks it exists
227  if( is_new && !( aCtl & KICTL_CREATE ) )
228  {
229  // notify user that fullFileName does not exist, ask if user wants to create it.
230  wxString ask = wxString::Format( _( "Schematic \"%s\" does not exist. Do you wish to create it?" ),
231  fullFileName );
232  if( !IsOK( this, ask ) )
233  return false;
234  }
235 
236  // unload current project file before loading new
237  {
238  delete g_RootSheet;
239  g_RootSheet = NULL;
240 
241  CreateScreens();
242  }
243 
244  GetScreen()->SetFileName( fullFileName );
245  g_RootSheet->SetFileName( fullFileName );
246 
247  SetStatusText( wxEmptyString );
248  ClearMsgPanel();
249 
250  // PROJECT::SetProjectFullName() is an impactful function. It should only be
251  // called under carefully considered circumstances.
252 
253  // The calling code should know not to ask me here to change projects unless
254  // it knows what consequences that will have on other KIFACEs running and using
255  // this same PROJECT. It can be very harmful if that calling code is stupid.
256 
257  // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
258  // They are already saved in the kiface project object.
259  if( pro.GetFullPath() != Prj().GetProjectFullName()
261  {
262  Prj().SetProjectFullName( pro.GetFullPath() );
263 
264  // load the libraries here, not in SCH_SCREEN::Draw() which is a context
265  // that will not tolerate DisplayError() dialog since we're already in an
266  // event handler in there.
267  // And when a schematic file is loaded, we need these libs to initialize
268  // some parameters (links to PART LIB, dangling ends ...)
270  Prj().SchLibs();
271  }
272 
273  LoadProjectFile();
274 
275  // Load the symbol library table, this will be used forever more.
277  Prj().SchSymbolLibTable();
278 
279  if( is_new )
280  {
281  // mark new, unsaved file as modified.
282  GetScreen()->SetModify();
283  }
284  else
285  {
286  delete g_RootSheet; // Delete the current project.
287  g_RootSheet = NULL; // Force CreateScreens() to build new empty project on load failure.
288  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
289 
290  try
291  {
292  g_RootSheet = pi->Load( fullFileName, &Kiway() );
293  m_CurrentSheet->clear();
294  m_CurrentSheet->push_back( g_RootSheet );
295 
296  if( !pi->GetError().IsEmpty() )
297  {
298  DisplayErrorMessage( this,
299  _( "The entire schematic could not be loaded. Errors "
300  "occurred attempting to load \nhierarchical sheet "
301  "schematics." ),
302  pi->GetError() );
303  }
304  }
305  catch( const IO_ERROR& ioe )
306  {
307  // Do not leave g_RootSheet == NULL because it is expected to be
308  // a valid sheet. Therefore create a dummy empty root sheet and screen.
309  CreateScreens();
310  Zoom_Automatique( false );
311 
312  wxString msg;
313  msg.Printf( _( "Error loading schematic file \"%s\".\n%s" ),
314  GetChars( fullFileName ), GetChars( ioe.What() ) );
315  DisplayError( this, msg );
316 
317  msg.Printf( _( "Failed to load \"%s\"" ), GetChars( fullFileName ) );
318  AppendMsgPanel( wxEmptyString, msg, CYAN );
319 
320  return false;
321  }
322 
323  // It's possible the schematic parser fixed errors due to bugs so warn the user
324  // that the schematic has been fixed (modified).
325  SCH_SHEET_LIST sheetList( g_RootSheet );
326 
327  if( sheetList.IsModified() )
328  {
329  DisplayInfoMessage( this,
330  _( "An error was found when loading the schematic that has "
331  "been automatically fixed. Please save the schematic to "
332  "repair the broken file or it may not be usable with other "
333  "versions of KiCad." ) );
334  }
335 
336  UpdateFileHistory( fullFileName );
337 
338  SCH_SCREENS schematic;
339 
340  // Convert old projects over to use symbol library table.
341  if( schematic.HasNoFullyDefinedLibIds() )
342  {
343  DIALOG_SYMBOL_REMAP dlgRemap( this );
344 
345  dlgRemap.ShowQuasiModal();
346  }
347  else
348  {
349  // Check to see whether some old library parts need to be rescued
350  // Only do this if RescueNeverShow was not set.
351  wxConfigBase *config = Kiface().KifaceSettings();
352  bool rescueNeverShow = false;
353  config->Read( RescueNeverShowEntry, &rescueNeverShow, false );
354 
355  if( !rescueNeverShow )
357  }
358 
359  schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
361 
362  // Ensure the schematic is fully segmented on first display
364  SchematicCleanUp( true );
365  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
366  GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
367  GetScreen()->m_Initialized = true;
368  }
369 
371  Zoom_Automatique( false );
373  SyncView();
375 
376  return true;
377 }
378 
379 
381 {
382  wxString msg;
383  wxString fullFileName;
384  SCH_SCREEN* screen = GetScreen();
385 
386  if( !screen )
387  {
388  wxLogError( wxT( "Document not ready, cannot import" ) );
389  return false;
390  }
391 
392  // open file chooser dialog
393  wxString path = wxPathOnly( Prj().GetProjectFullName() );
394 
395  wxFileDialog dlg( this, _( "Append Schematic" ), path, wxEmptyString,
396  SchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
397 
398  if( dlg.ShowModal() == wxID_CANCEL )
399  return false;
400 
401  fullFileName = dlg.GetPath();
402 
403  wxFileName fn = fullFileName;
404 
405  if( fn.IsRelative() )
406  {
407  fn.MakeAbsolute();
408  fullFileName = fn.GetFullPath();
409  }
410 
411  wxString cache_name = PART_LIBS::CacheName( fullFileName );
412 
413  if( !!cache_name )
414  {
415  PART_LIBS* libs = Prj().SchLibs();
416 
417  try
418  {
419  if( PART_LIB* lib = libs->AddLibrary( cache_name ) )
420  lib->SetCache();
421  }
422  catch( const IO_ERROR& ioe )
423  {
424  DisplayError( this, ioe.What() );
425  }
426  }
427 
428  wxLogDebug( wxT( "Importing schematic " ) + fullFileName );
429 
430  // Load the schematic into a temporary sheet.
431  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
432  std::unique_ptr< SCH_SHEET> newSheet( new SCH_SHEET );
433 
434  newSheet->SetFileName( fullFileName );
435 
436  try
437  {
438  pi->Load( fullFileName, &Kiway(), newSheet.get() );
439 
440  if( !pi->GetError().IsEmpty() )
441  {
442  DisplayErrorMessage( this,
443  _( "The entire schematic could not be loaded. Errors "
444  "occurred attempting to load hierarchical sheet "
445  "schematics." ),
446  pi->GetError() );
447  }
448  }
449  catch( const IO_ERROR& ioe )
450  {
451  msg.Printf( _( "Error occurred loading schematic file \"%s\"." ), fullFileName );
452  DisplayErrorMessage( this, msg, ioe.What() );
453 
454  msg.Printf( _( "Failed to load schematic \"%s\"" ), fullFileName );
455  AppendMsgPanel( wxEmptyString, msg, CYAN );
456 
457  return false;
458  }
459 
460  // Make sure any new sheet changes do not cause any recursion issues.
461  SCH_SHEET_LIST hierarchy( g_RootSheet ); // This is the schematic sheet hierarchy.
462  SCH_SHEET_LIST sheetHierarchy( newSheet.get() ); // This is the hierarchy of the import.
463 
464  wxFileName destFile = screen->GetFileName();
465 
466  if( destFile.IsRelative() )
467  destFile.MakeAbsolute( Prj().GetProjectPath() );
468 
469  if( hierarchy.TestForRecursion( sheetHierarchy, destFile.GetFullPath( wxPATH_UNIX ) ) )
470  {
471  msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
472  "has the sheet \"%s\" or one of it's subsheets as a parent somewhere in "
473  "the schematic hierarchy." ),
474  destFile.GetFullPath() );
475  DisplayError( this, msg );
476  return false;
477  }
478 
479  wxArrayString names;
480 
481  // Make sure the imported schematic has been remapped to the symbol library table.
482  SCH_SCREENS newScreens( newSheet.get() ); // All screens associated with the import.
483 
484  if( newScreens.HasNoFullyDefinedLibIds() )
485  {
486  DisplayInfoMessage( this,
487  "This schematic has not been remapped to the symbol library\n"
488  "table. The project this schematic belongs to must first be\n"
489  "remapped before it can be imported into the current project." );
490  return false;
491  }
492  else
493  {
494  // If there are symbol libraries in the imported schematic that are not in the
495  // symbol library table of this project, there could be a lot of broken symbol
496  // library links. Attempt to add the missing libraries to the project symbol
497  // library table.
498  newScreens.GetLibNicknames( names );
499  wxArrayString newLibNames;
500 
501  for( const auto& name : names )
502  {
503  if( !Prj().SchSymbolLibTable()->HasLibrary( name ) )
504  newLibNames.Add( name );
505  }
506 
507  wxFileName symLibTableFn( fn.GetPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
508 
509  if( !newLibNames.IsEmpty() && symLibTableFn.Exists() && symLibTableFn.IsFileReadable() )
510  {
511  SYMBOL_LIB_TABLE table;
512 
513  try
514  {
515  table.Load( symLibTableFn.GetFullPath() );
516  }
517  catch( const IO_ERROR& ioe )
518  {
519  msg.Printf( _( "An error occurred loading the symbol library table \"%s\"." ),
520  symLibTableFn.GetFullPath() );
521  DisplayErrorMessage( NULL, msg, ioe.What() );
522  }
523 
524  if( !table.IsEmpty() )
525  {
526  for( const auto& libName : newLibNames )
527  {
528  if( !table.HasLibrary( libName ) )
529  continue;
530 
531  // Don't expand environment variable because KIPRJMOD will not be correct
532  // for a different project.
533  wxString uri = table.GetFullURI( libName, false );
534  wxFileName newLib;
535 
536  if( uri.Contains( "${KIPRJMOD}" ) )
537  {
538  newLib.SetPath( fn.GetPath() );
539  newLib.SetFullName( uri.AfterLast( '}' ) );
540  uri = newLib.GetFullPath();
541  }
542  else if( uri.Contains( "$(KIPRJMOD)" ) )
543  {
544  newLib.SetPath( fn.GetPath() );
545  newLib.SetFullName( uri.AfterLast( ')' ) );
546  uri = newLib.GetFullPath();
547  }
548  else
549  {
550  uri = table.GetFullURI( libName );
551  }
552 
553  // Add the library from the imported project to the current project
554  // symbol library table.
555  const SYMBOL_LIB_TABLE_ROW* row = table.FindRow( libName );
556 
557  wxCHECK2_MSG( row, continue, "Library '" + libName +
558  "' missing from symbol library table '" +
559  symLibTableFn.GetFullPath() + "'." );
560 
561  wxString newLibName = libName;
562  int libNameCnt = 1;
563 
564  // Rename the imported symbol library if it already exists.
565  while( Prj().SchSymbolLibTable()->HasLibrary( newLibName ) )
566  newLibName = wxString::Format( "%s%d", libName, libNameCnt );
567 
568  auto newRow = new SYMBOL_LIB_TABLE_ROW( newLibName, uri, row->GetType(),
569  row->GetOptions(), row->GetDescr() );
570  Prj().SchSymbolLibTable()->InsertRow( newRow );
571 
572  if( libName != newLibName )
573  newScreens.ChangeSymbolLibNickname( libName, newLibName );
574  }
575  }
576  }
577  }
578 
579  // Check for duplicate sheet names in the current page.
580  wxArrayString duplicateSheetNames;
581  SCH_TYPE_COLLECTOR sheets;
582 
583  sheets.Collect( screen->GetDrawItems(), SCH_COLLECTOR::SheetsOnly );
584 
585  for( int i = 0; i < sheets.GetCount(); ++i )
586  {
587  if( newSheet->GetScreen()->GetSheet( ( ( SCH_SHEET* ) sheets[i] )->GetName() ) )
588  duplicateSheetNames.Add( ( ( SCH_SHEET* ) sheets[i] )->GetName() );
589  }
590 
591  if( !duplicateSheetNames.IsEmpty() )
592  {
593  msg.Printf( "Duplicate sheet names exist on the current page. Do you want to "
594  "automatically rename the duplicate sheet names?" );
595  if( !IsOK( this, msg ) )
596  return false;
597  }
598 
599  SCH_SCREEN* newScreen = newSheet->GetScreen();
600  wxCHECK_MSG( newScreen, false, "No screen defined for imported sheet." );
601 
602  for( const auto& duplicateName : duplicateSheetNames )
603  {
604  SCH_SHEET* renamedSheet = newScreen->GetSheet( duplicateName );
605 
606  wxCHECK2_MSG( renamedSheet, continue,
607  "Sheet " + duplicateName + " not found in imported schematic." );
608 
609  timestamp_t newtimestamp = GetNewTimeStamp();
610  renamedSheet->SetTimeStamp( newtimestamp );
611  renamedSheet->SetName( wxString::Format( "Sheet%8.8lX", (unsigned long) newtimestamp ) );
612  }
613 
614  // It is finally safe to add the imported schematic.
615  screen->Append( newScreen );
616 
617  SCH_SCREENS allScreens;
618  allScreens.ReplaceDuplicateTimeStamps();
619 
620  SCH_SCREENS screens( GetCurrentSheet().Last() );
621  screens.UpdateSymbolLinks( true );
622 
623  // Clear all annotation in the imported schematic to prevent clashes with existing annotation.
624  // Must be done after updating the symbol links as we need to know about multi-unit parts.
625  screens.ClearAnnotation();
626 
628  Zoom_Automatique( false );
630 
631  SyncView();
632  HardRedraw(); // Full reinit of the current screen and the display.
633  OnModify();
634 
635  return true;
636 }
637 
638 
639 void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event )
640 {
641  if( GetScreen() && GetScreen()->IsModified() )
642  {
643  wxString msg = _( "This operation cannot be undone.\n\n"
644  "Do you want to save the current document before proceeding?" );
645 
646  if( IsOK( this, msg ) )
647  SaveProject();
648  }
649 
650  AppendSchematic();
651 }
652 
653 
654 void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
655 {
656  if( !AskToSaveChanges() )
657  return;
658 
659  // Set the project location if none is set
660  bool setProject = Prj().GetProjectFullName().IsEmpty();
661  wxString path = wxPathOnly( Prj().GetProjectFullName() );
662 
663  wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString,
664  EagleSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
665 
666  if( dlg.ShowModal() == wxID_CANCEL )
667  return;
668 
669  if( setProject )
670  {
671  wxFileName projectFn( dlg.GetPath() );
672  projectFn.SetExt( ProjectFileExtension );
673  Prj().SetProjectFullName( projectFn.GetFullPath() );
674  }
675 
676  // For now there is only one import plugin
677  importFile( dlg.GetPath(), SCH_IO_MGR::SCH_EAGLE );
678 }
679 
680 
681 void SCH_EDIT_FRAME::OnSaveProject( wxCommandEvent& aEvent )
682 {
683  SaveProject();
684 }
685 
686 
688 {
689  SCH_SCREEN* screen;
690  SCH_SCREENS screenList;
691  bool success = true;
692 
693  // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
694  wxString fileName = Prj().AbsolutePath( g_RootSheet->GetFileName() );
695  wxFileName fn = fileName;
696 
697  if( !fn.IsDirWritable() )
698  {
699  wxString msg = wxString::Format( _( "Directory \"%s\" is not writable." ), fn.GetPath() );
700  DisplayError( this, msg );
701  return false;
702  }
703 
704  for( screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
705  success &= SaveEEFile( screen );
706 
708 
709  UpdateTitle();
710 
711  return success;
712 }
713 
714 
716 {
717  wxFileName tmpFileName = g_RootSheet->GetFileName();
718  wxFileName fn = tmpFileName;
719  wxFileName tmp;
720  SCH_SCREENS screens;
721 
722  bool autoSaveOk = true;
723 
724  tmp.AssignDir( fn.GetPath() );
725 
726  if( !tmp.IsOk() )
727  return false;
728 
729  if( !IsWritable( tmp ) )
730  return false;
731 
732  for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
733  {
734  // Only create auto save files for the schematics that have been modified.
735  if( !screen->IsSave() )
736  continue;
737 
738  tmpFileName = fn = screen->GetFileName();
739 
740  // Auto save file name is the normal file name prefixed with AUTOSAVE_PREFIX_FILENAME.
741  fn.SetName( AUTOSAVE_PREFIX_FILENAME + fn.GetName() );
742 
743  screen->SetFileName( fn.GetFullPath() );
744 
745  if( SaveEEFile( screen, false, NO_BACKUP_FILE ) )
746  screen->SetModify();
747  else
748  autoSaveOk = false;
749 
750  screen->SetFileName( tmpFileName.GetFullPath() );
751  }
752 
753  if( autoSaveOk )
754  m_autoSaveState = false;
755 
756  return autoSaveOk;
757 }
758 
759 
760 bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
761 {
762  wxString projectpath;
763  wxFileName newfilename;
764  SCH_SHEET_LIST sheetList( g_RootSheet );
765 
766  switch( (SCH_IO_MGR::SCH_FILE_T) aFileType )
767  {
768  case SCH_IO_MGR::SCH_EAGLE:
769  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
770  wxASSERT_MSG( wxFileName( aFileName ).IsAbsolute(),
771  wxT( "Import eagle schematic caller didn't send full filename" ) );
772 
773  if( !LockFile( aFileName ) )
774  {
775  wxString msg = wxString::Format( _( "Schematic file \"%s\" is already open." ),
776  aFileName );
777  DisplayError( this, msg );
778  return false;
779  }
780 
781  try
782  {
783  delete g_RootSheet;
784  g_RootSheet = nullptr;
785  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EAGLE ) );
786  g_RootSheet = pi->Load( aFileName, &Kiway() );
787 
788  // Eagle sheets do not use a worksheet frame by default, so set it to an empty one
790  pglayout.SetEmptyLayout();
791 
792  BASE_SCREEN::m_PageLayoutDescrFileName = "empty.kicad_wks";
793  wxFileName layoutfn( Kiway().Prj().GetProjectPath(),
795  wxFile layoutfile;
796 
797  if( layoutfile.Create( layoutfn.GetFullPath() ) )
798  {
799  layoutfile.Write( WORKSHEET_LAYOUT::EmptyLayout() );
800  layoutfile.Close();
801  }
802 
803  projectpath = Kiway().Prj().GetProjectPath();
804  newfilename.SetPath( Prj().GetProjectPath() );
805  newfilename.SetName( Prj().GetProjectName() );
806  newfilename.SetExt( SchematicFileExtension );
807 
808  m_CurrentSheet->clear();
809  m_CurrentSheet->push_back( g_RootSheet );
811 
812  g_RootSheet->SetFileName( newfilename.GetFullPath() );
813  GetScreen()->SetFileName( newfilename.GetFullPath() );
814  GetScreen()->SetModify();
815  SaveProjectSettings( false );
816 
817  UpdateFileHistory( aFileName );
818  SCH_SCREENS schematic;
819  schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
820 
821  // Ensure the schematic is fully segmented on first display
823  SchematicCleanUp( true );
824  GetScreen()->m_Initialized = true;
825 
826  SCH_TYPE_COLLECTOR components;
827  SCH_SCREENS allScreens;
828 
829  for( SCH_SCREEN* screen = allScreens.GetFirst(); screen; screen = allScreens.GetNext() )
830  {
831  components.Collect( screen->GetDrawItems(), SCH_COLLECTOR::ComponentsOnly );
832 
833  for( int cmpIdx = 0; cmpIdx < components.GetCount(); ++cmpIdx )
834  {
835  std::vector<wxPoint> pts;
836  SCH_COMPONENT* cmp = static_cast<SCH_COMPONENT*>( components[cmpIdx] );
837 
838  // Update footprint LIB_ID to point to the imported Eagle library
839  auto fpField = cmp->GetField( FOOTPRINT );
840 
841  if( !fpField->GetText().IsEmpty() )
842  {
843  LIB_ID fpId;
844  fpId.Parse( fpField->GetText(), LIB_ID::ID_SCH, true );
845  fpId.SetLibNickname( newfilename.GetName() );
846  fpField->SetText( fpId.Format() );
847  }
848 
849  // Add junction dots where necessary
850  cmp->GetConnectionPoints( pts );
851 
852  for( auto i = pts.begin(); i != pts.end(); ++i )
853  {
854  if( GetScreen()->IsJunctionNeeded( *i, true ) )
855  AddJunction( *i, true );
856  }
857  }
858  }
859 
860  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
861  // Only perform the dangling end test on root sheet.
863 
865  Zoom_Automatique( false );
867  SyncView();
868  UpdateTitle();
869  }
870  catch( const IO_ERROR& ioe )
871  {
872  // Do not leave g_RootSheet == NULL because it is expected to be
873  // a valid sheet. Therefore create a dummy empty root sheet and screen.
874  CreateScreens();
875  Zoom_Automatique( false );
876 
877  wxString msg;
878  msg.Printf( _( "Error loading schematic \"%s\".\n%s" ), aFileName, ioe.What() );
879  DisplayError( this, msg );
880 
881  msg.Printf( _( "Failed to load \"%s\"" ), aFileName );
882  AppendMsgPanel( wxEmptyString, msg, CYAN );
883 
884  return false;
885  }
886 
887  return true;
888 
889  default:
890  return false;
891  }
892 }
893 
894 
896 {
897  SCH_SCREENS screenList;
898 
899  // Save any currently open and modified project files.
900  for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
901  {
902  if( screen->IsModify() )
903  {
904  if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. Save changes?" ),
905  [&]()->bool { return SaveProject(); } ) )
906  {
907  return false;
908  }
909  }
910  }
911 
912  return true;
913 }
const std::string SchematicBackupFileExtension
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:114
bool m_autoSaveState
Flag to indicate the last auto save state.
static const wxString & GetSymbolLibTableFileName()
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Function HandleUnsavedChanges displays a dialog with Save, Cancel and Discard Changes buttons...
Definition: confirm.cpp:213
bool IsModified()
Function IsModified checks the entire hierarchy for any modifications.
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 ...
virtual void Zoom_Automatique(bool aWarpPointer) override
Redraw the screen with best zoom level and the best centering that shows all the page or the board...
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()
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
long timestamp_t
timestamp_t is our type to represent unique IDs for all kinds of elements; historically simply the ti...
Definition: common.h:52
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Function DisplayErrorMessage displays an error message with aMessage.
Definition: confirm.cpp:259
This file is part of the common library TODO brief description.
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
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:325
SCH_SHEET * GetSheet(const wxString &aName)
Returns a sheet object pointer that is named aName.
Definition: sch_screen.cpp:624
void OnModify()
Must be called after a schematic change in order to set the "modify" flag of the current screen* and ...
const std::string ProjectFileExtension
virtual void SetScreen(BASE_SCREEN *aScreen) override
#define KICTL_CREATE
caller thinks requested project files may not exist
Definition: kiway_player.h:140
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:131
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
SCH_SCREEN * GetScreen() const override
Return 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.
timestamp_t GetNewTimeStamp()
Definition: common.cpp:212
void Save_File(wxCommandEvent &event)
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:56
SCH_FIELD * GetField(int aFieldNdx) const
Returns a field in this symbol.
void SetName(const wxString &aName)
Definition: sch_sheet.h:269
void HardRedraw() override
Rebuild the GAL and redraw the screen.
void SyncView()
Mark all items for refresh.
bool m_Initialized
Definition: base_screen.h:207
int ShowQuasiModal()
const std::string SchematicFileExtension
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:380
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:107
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:661
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:193
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
void AppendMsgPanel(const wxString &textUpper, const wxString &textLower, COLOR4D color, int pad=6)
Append a message to the message panel.
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:160
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:162
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
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:910
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)
UTF8 Format() const
Definition: lib_id.cpp:237
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:561
virtual void ClearUndoORRedoList(UNDO_REDO_CONTAINER &aList, int aItemCount=-1) override
Free the undo or redo list from aList element.
Definition: sch_screen.cpp:546
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:129
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.
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:277
Object used to load, save, search, and otherwise manipulate symbol library files. ...
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:295
void ClrSave()
Definition: base_screen.h:327
void ClearMsgPanel(void)
Clear all messages from the message panel.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:523
bool IsEmpty(bool aIncludeFallback=true)
Return true if the table is empty.
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName) const
Function TestForRecursion.
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:206