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-2020 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 
27 #include <fctsys.h>
28 #include <sch_draw_panel.h>
29 #include <confirm.h>
30 #include <env_paths.h>
31 #include <gestfich.h>
32 #include <sch_edit_frame.h>
33 #include <pgm_base.h>
34 #include <kiface_i.h>
35 #include <richio.h>
36 #include <trace_helpers.h>
37 #include <tool/tool_manager.h>
38 #include <id.h>
39 #include <class_library.h>
40 #include <lib_edit_frame.h>
41 #include <sch_sheet.h>
42 #include <sch_sheet_path.h>
43 #include <sch_component.h>
44 #include <schematic.h>
46 #include <project_rescue.h>
47 #include <eeschema_config.h>
48 #include <eeschema_settings.h>
49 #include <sch_legacy_plugin.h>
50 #include <sch_eagle_plugin.h>
51 #include <symbol_lib_table.h>
52 #include <dialog_symbol_remap.h>
53 #include <dialog_migrate_buses.h>
54 #include <ws_data_model.h>
55 #include <connection_graph.h>
56 #include <tool/actions.h>
58 #include <project/project_file.h>
60 #include <netlist.h>
61 #include <widgets/infobar.h>
62 
63 
64 bool SCH_EDIT_FRAME::SaveEEFile( SCH_SHEET* aSheet, bool aSaveUnderNewName )
65 {
66  wxString msg;
67  wxFileName schematicFileName;
68  bool success;
69 
70  if( aSheet == NULL )
71  aSheet = GetCurrentSheet().Last();
72 
73  SCH_SCREEN* screen = aSheet->GetScreen();
74 
75  wxCHECK( screen, false );
76 
77  // If no name exists in the window yet - save as new.
78  if( screen->GetFileName().IsEmpty() )
79  aSaveUnderNewName = true;
80 
81  // Construct the name of the file to be saved
82  schematicFileName = Prj().AbsolutePath( screen->GetFileName() );
83 
84  if( aSaveUnderNewName )
85  {
86  wxString wildcards = KiCadSchematicFileWildcard();
87 
88  wxFileDialog dlg( this, _( "Schematic Files" ), wxPathOnly( Prj().GetProjectFullName() ),
89  schematicFileName.GetFullName(), wildcards,
90  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
91 
92  if( dlg.ShowModal() == wxID_CANCEL )
93  return false;
94 
95  schematicFileName = dlg.GetPath();
96 
97  if( schematicFileName.GetExt().IsEmpty() )
98  schematicFileName.SetExt( KiCadSchematicFileExtension );
99  }
100 
101  if( !IsWritable( schematicFileName ) )
102  return false;
103 
104  wxFileName tempFile( schematicFileName );
105  tempFile.SetName( wxT( "." ) + tempFile.GetName() );
106  tempFile.SetExt( tempFile.GetExt() + wxT( "$" ) );
107 
108  // Save
109  wxLogTrace( traceAutoSave,
110  wxT( "Saving file <" ) + schematicFileName.GetFullPath() + wxT( ">" ) );
111 
112  SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
113  schematicFileName.GetFullPath() );
114  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( pluginType ) );
115 
116  try
117  {
118  pi->Save( tempFile.GetFullPath(), aSheet, &Schematic() );
119  success = true;
120  }
121  catch( const IO_ERROR& ioe )
122  {
123  msg.Printf( _( "Error saving schematic file \"%s\".\n%s" ),
124  schematicFileName.GetFullPath(), ioe.What() );
125  DisplayError( this, msg );
126 
127  msg.Printf( _( "Failed to create temporary file \"%s\"" ), tempFile.GetFullPath() );
128  AppendMsgPanel( wxEmptyString, msg, CYAN );
129 
130  // In case we started a file but didn't fully write it, clean up
131  wxRemoveFile( tempFile.GetFullPath() );
132 
133  success = false;
134  }
135 
136  if( success )
137  {
138  // Replace the original with the temporary file we just wrote
139  success = wxRenameFile( tempFile.GetFullPath(), schematicFileName.GetFullPath() );
140 
141  if( !success )
142  {
143  msg.Printf( _( "Error saving schematic file \"%s\".\n"
144  "Failed to rename temporary file %s" ),
145  schematicFileName.GetFullPath(), tempFile.GetFullPath() );
146  DisplayError( this, msg );
147 
148  msg.Printf( _( "Failed to rename temporary file \"%s\"" ), tempFile.GetFullPath() );
149  AppendMsgPanel( wxEmptyString, msg, CYAN );
150  }
151  }
152 
153  if( success )
154  {
155  // Delete auto save file.
156  wxFileName autoSaveFileName = schematicFileName;
157  autoSaveFileName.SetName( GetAutoSaveFilePrefix() + schematicFileName.GetName() );
158 
159  if( autoSaveFileName.FileExists() )
160  {
161  wxLogTrace( traceAutoSave,
162  wxT( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() +
163  wxT( ">" ) );
164 
165  wxRemoveFile( autoSaveFileName.GetFullPath() );
166  }
167 
168  // Update the screen and frame info and reset the lock file.
169  if( aSaveUnderNewName )
170  {
171  screen->SetFileName( schematicFileName.GetFullPath() );
172  LockFile( schematicFileName.GetFullPath() );
173  }
174 
175  screen->ClrSave();
176  screen->ClrModify();
177 
178  msg.Printf( _( "File %s saved" ), screen->GetFileName() );
179  SetStatusText( msg, 0 );
180  }
181  else
182  {
183  DisplayError( this, _( "File write operation failed." ) );
184  }
185 
186  return success;
187 }
188 
189 
190 void SCH_EDIT_FRAME::Save_File( bool doSaveAs )
191 {
192  if( doSaveAs )
193  {
194  if( SaveEEFile( NULL, true ) )
195  {
196  SCH_SCREEN* screen = GetScreen();
197 
198  wxCHECK( screen, /* void */ );
199 
200  wxFileName fn = screen->GetFileName();
201 
202  if( fn.GetExt() == LegacySchematicFileExtension )
204  }
205  }
206  else
207  {
208  SaveEEFile( NULL );
209  }
210 
211  UpdateTitle();
212 }
213 
214 
215 bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
216 {
217  // implement the pseudo code from KIWAY_PLAYER.h:
218  wxString msg;
219 
220  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
221 
222  // This is for python:
223  if( aFileSet.size() != 1 )
224  {
225  msg.Printf( "Eeschema:%s() takes only a single filename.", __WXFUNCTION__ );
226  DisplayError( this, msg );
227  return false;
228  }
229 
230  wxString fullFileName( aFileSet[0] );
231 
232  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
233  wxASSERT_MSG( wxFileName( fullFileName ).IsAbsolute(), wxT( "Path is not absolute!" ) );
234 
235  if( !LockFile( fullFileName ) )
236  {
237  msg.Printf( _( "Schematic file \"%s\" is already open." ), fullFileName );
238  DisplayError( this, msg );
239  return false;
240  }
241 
242  if( !AskToSaveChanges() )
243  return false;
244 
245  wxFileName pro = fullFileName;
246  pro.SetExt( ProjectFileExtension );
247 
248  bool is_new = !wxFileName::IsFileReadable( fullFileName );
249 
250  // If its a non-existent schematic and caller thinks it exists
251  if( is_new && !( aCtl & KICTL_CREATE ) )
252  {
253  // notify user that fullFileName does not exist, ask if user wants to create it.
254  msg.Printf( _( "Schematic \"%s\" does not exist. Do you wish to create it?" ),
255  fullFileName );
256 
257  if( !IsOK( this, msg ) )
258  return false;
259  }
260 
261  // unload current project file before loading new
262  {
263  SetScreen( nullptr );
264  CreateScreens();
265  }
266 
267  SetStatusText( wxEmptyString );
268  ClearMsgPanel();
269 
270  SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( fullFileName );
271 
272  // PROJECT::SetProjectFullName() is an impactful function. It should only be
273  // called under carefully considered circumstances.
274 
275  // The calling code should know not to ask me here to change projects unless
276  // it knows what consequences that will have on other KIFACEs running and using
277  // this same PROJECT. It can be very harmful if that calling code is stupid.
278 
279  // NOTE: The calling code should never call this in hosted (non-standalone) mode with a
280  // different project than what has been loaded by the manager frame. This will crash.
281 
282  bool differentProject = pro.GetFullPath() != Prj().GetProjectFullName();
283 
284  if( differentProject )
285  {
287  Schematic().SetProject( nullptr );
289  GetSettingsManager()->LoadProject( pro.GetFullPath() );
290  CreateScreens();
291  }
292 
293  if( schFileType == SCH_IO_MGR::SCH_LEGACY )
294  {
295  // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
296  // They are already saved in the kiface project object.
297  if( differentProject || !Prj().GetElem( PROJECT::ELEM_SCH_PART_LIBS ) )
298  {
299  // load the libraries here, not in SCH_SCREEN::Draw() which is a context
300  // that will not tolerate DisplayError() dialog since we're already in an
301  // event handler in there.
302  // And when a schematic file is loaded, we need these libs to initialize
303  // some parameters (links to PART LIB, dangling ends ...)
305  Prj().SchLibs();
306  }
307  }
308  else
309  {
310  // No legacy symbol libraries including the cache are loaded with the new file format.
312  }
313 
314  // Load the symbol library table, this will be used forever more.
316  Prj().SchSymbolLibTable();
317 
318  // Load project settings after schematic has been set up with the project link, since this will
319  // update some of the needed schematic settings such as drawing defaults
321 
322  SetShutdownBlockReason( _( "Schematic file changes are unsaved" ) );
323 
324  if( is_new )
325  {
326  // mark new, unsaved file as modified.
327  GetScreen()->SetModify();
328  }
329  else
330  {
331  SetScreen( nullptr );
332 
333  SCH_PLUGIN* plugin = SCH_IO_MGR::FindPlugin( schFileType );
334  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( plugin );
335 
336  // This will rename the file if there is an autosave and the user want to recover
337  CheckForAutoSaveFile( fullFileName );
338 
339  try
340  {
341  Schematic().SetRoot( pi->Load( fullFileName, &Schematic() ) );
342 
343  GetCurrentSheet().push_back( &Schematic().Root() );
344 
345  if( !pi->GetError().IsEmpty() )
346  {
347  DisplayErrorMessage( this,
348  _( "The entire schematic could not be loaded. Errors "
349  "occurred attempting to load \nhierarchical sheet "
350  "schematics." ),
351  pi->GetError() );
352  }
353  }
354  catch( const IO_ERROR& ioe )
355  {
356  // Do not leave g_RootSheet == NULL because it is expected to be
357  // a valid sheet. Therefore create a dummy empty root sheet and screen.
358  CreateScreens();
360 
361  msg.Printf( _( "Error loading schematic file \"%s\".\n%s" ),
362  fullFileName, ioe.What() );
363  DisplayError( this, msg );
364 
365  msg.Printf( _( "Failed to load \"%s\"" ), fullFileName );
366  AppendMsgPanel( wxEmptyString, msg, CYAN );
367 
368  return false;
369  }
370 
371  // It's possible the schematic parser fixed errors due to bugs so warn the user
372  // that the schematic has been fixed (modified).
373  SCH_SHEET_LIST sheetList = Schematic().GetSheets();
374 
375  if( sheetList.IsModified() )
376  {
377  DisplayInfoMessage( this,
378  _( "An error was found when loading the schematic that has "
379  "been automatically fixed. Please save the schematic to "
380  "repair the broken file or it may not be usable with other "
381  "versions of KiCad." ) );
382  }
383 
384  UpdateFileHistory( fullFileName );
385 
386  SCH_SCREENS schematic( Schematic().Root() );
387 
388  // LIB_ID checks and symbol rescue only apply to the legacy file formats.
389  if( schFileType == SCH_IO_MGR::SCH_LEGACY )
390  {
391  // Convert old projects over to use symbol library table.
392  if( schematic.HasNoFullyDefinedLibIds() )
393  {
394  DIALOG_SYMBOL_REMAP dlgRemap( this );
395 
396  dlgRemap.ShowQuasiModal();
397  }
398  else
399  {
400  // Double check to ensure no legacy library list entries have been
401  // added to the projec file symbol library list.
402  wxString paths;
403  wxArrayString libNames;
404 
405  PART_LIBS::LibNamesAndPaths( &Prj(), false, &paths, &libNames );
406 
407  if( !libNames.IsEmpty() )
408  {
410  {
411  wxRichMessageDialog invalidLibDlg(
412  this,
413  _( "Illegal entry found in project file symbol library list." ),
414  _( "Project Load Warning" ),
415  wxOK | wxCENTER | wxICON_EXCLAMATION );
416  invalidLibDlg.ShowDetailedText(
417  _( "Symbol libraries defined in the project file symbol library "
418  "list are no longer supported and will be\nremoved. This may "
419  "cause broken symbol library links under certain conditions." ) );
420  invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
421  invalidLibDlg.ShowModal();
423  !invalidLibDlg.IsCheckBoxChecked();
424  }
425 
426  libNames.Clear();
427  paths.Clear();
428  PART_LIBS::LibNamesAndPaths( &Prj(), true, &paths, &libNames );
429  }
430 
431  if( !cfg || !cfg->m_RescueNeverShow )
432  {
434  editor->RescueSymbolLibTableProject( false );
435  }
436  }
437 
438  // Update all symbol library links for all sheets.
439  schematic.UpdateSymbolLinks();
440 
441  if( !cfg || cfg->m_Appearance.show_sexpr_file_convert_warning )
442  {
443  wxRichMessageDialog newFileFormatDlg(
444  this,
445  _( "The schematic file will be converted to the new file format on save." ),
446  _( "Project Load Warning" ),
447  wxOK | wxCENTER | wxICON_EXCLAMATION );
448  newFileFormatDlg.ShowDetailedText(
449  _( "This schematic was saved in the legacy file format which is no "
450  "longer supported and will be saved\nusing the new file format. The "
451  "new file format cannot be opened with previous versions of KiCad." ) );
452  newFileFormatDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
453  newFileFormatDlg.ShowModal();
454 
455  if( cfg )
456  cfg->m_Appearance.show_sexpr_file_convert_warning =
457  !newFileFormatDlg.IsCheckBoxChecked();
458  }
459 
460  // Legacy schematic can have duplicate time stamps so fix that before converting
461  // to the s-expression format.
462  schematic.ReplaceDuplicateTimeStamps();
463 
464  // Allow the schematic to be saved to new file format without making any edits.
465  OnModify();
466  }
467  else // S-expression schematic.
468  {
469  for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
470  screen->UpdateLocalLibSymbolLinks();
471 
472  // Restore all of the loaded symbol instances from the root sheet screen.
473  sheetList.UpdateSymbolInstances( Schematic().RootScreen()->m_symbolInstances );
474  }
475 
477 
478  SetScreen( GetCurrentSheet().LastScreen() );
479 
480  // Migrate conflicting bus definitions
481  // TODO(JE) This should only run once based on schematic file version
482  if( Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() > 0 )
483  {
484  DIALOG_MIGRATE_BUSES dlg( this );
485  dlg.ShowQuasiModal();
487  OnModify();
488  }
489 
490  GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.
492  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
493  GetScreen()->m_Initialized = true;
494  }
495 
498 
499  // re-create junctions if needed. Eeschema optimizes wires by merging
500  // colinear segments. If a schematic is saved without a valid
501  // cache library or missing installed libraries, this can cause connectivity errors
502  // unless junctions are added.
503  FixupJunctions();
504 
505  SyncView();
507 
508  UpdateTitle();
509 
510  wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
511  m_infoBar->Dismiss();
512 
513  if( fn.FileExists() && !fn.IsFileWritable() )
514  {
517  m_infoBar->ShowMessage( "Schematic file is read only.", wxICON_WARNING );
518  }
519 
520  return true;
521 }
522 
523 
525 {
526  wxString fullFileName;
527  SCH_SCREEN* screen = GetScreen();
528 
529  if( !screen )
530  {
531  wxLogError( wxT( "Document not ready, cannot import" ) );
532  return false;
533  }
534 
535  // open file chooser dialog
536  wxString path = wxPathOnly( Prj().GetProjectFullName() );
537 
538  wxFileDialog dlg( this, _( "Append Schematic" ), path, wxEmptyString,
539  KiCadSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
540 
541  if( dlg.ShowModal() == wxID_CANCEL )
542  return false;
543 
544  fullFileName = dlg.GetPath();
545 
546  if( !LoadSheetFromFile( GetCurrentSheet().Last(), &GetCurrentSheet(), fullFileName ) )
547  return false;
548 
549  SCH_SCREENS screens( GetCurrentSheet().Last() );
550  screens.TestDanglingEnds();
551 
554 
555  SyncView();
556  HardRedraw(); // Full reinit of the current screen and the display.
557  OnModify();
558 
559  return true;
560 }
561 
562 
563 void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event )
564 {
565  if( GetScreen() && GetScreen()->IsModified() )
566  {
567  wxString msg = _( "This operation cannot be undone.\n\n"
568  "Do you want to save the current document before proceeding?" );
569 
570  if( IsOK( this, msg ) )
571  SaveProject();
572  }
573 
574  AppendSchematic();
575 }
576 
577 
578 void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
579 {
580  if( !AskToSaveChanges() )
581  return;
582 
583  // Set the project location if none is set
584  bool setProject = Prj().GetProjectFullName().IsEmpty();
585  wxString path = wxPathOnly( Prj().GetProjectFullName() );
586 
587  wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString,
588  EagleSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
589 
590  if( dlg.ShowModal() == wxID_CANCEL )
591  return;
592 
593  if( setProject )
594  {
595  wxFileName projectFn( dlg.GetPath() );
596  projectFn.SetExt( ProjectFileExtension );
597  GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
598  }
599 
600  // For now there is only one import plugin
601  importFile( dlg.GetPath(), SCH_IO_MGR::SCH_EAGLE );
602 }
603 
604 
606 {
607  wxString msg;
608  SCH_SCREEN* screen;
609  SCH_SCREENS screens( Schematic().Root() );
610  bool success = true;
611  bool updateFileType = false;
612 
613  // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
614  wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
615  wxFileName fn = fileName;
616 
617  if( !fn.IsDirWritable() )
618  {
619  msg = wxString::Format( _( "Directory \"%s\" is not writable." ), fn.GetPath() );
620  DisplayError( this, msg );
621  return false;
622  }
623 
624  // Warn user on potential file overwrite. This can happen on shared sheets.
625  wxArrayString overwrittenFiles;
626 
627  for( size_t i = 0; i < screens.GetCount(); i++ )
628  {
629  screen = screens.GetScreen( i );
630 
631  wxCHECK2( screen, continue );
632 
633  // Convert legacy schematics file name extensions for the new format.
634  wxFileName tmpFn = screen->GetFileName();
635 
636  if( tmpFn.GetExt() == KiCadSchematicFileExtension )
637  continue;
638 
639  tmpFn.SetExt( KiCadSchematicFileExtension );
640 
641  if( tmpFn.FileExists() )
642  overwrittenFiles.Add( tmpFn.GetFullPath() );
643  }
644 
645  if( !overwrittenFiles.IsEmpty() )
646  {
647  for( auto overwrittenFile : overwrittenFiles )
648  {
649  if( msg.IsEmpty() )
650  msg = overwrittenFile;
651  else
652  msg += "\n" + overwrittenFile;
653  }
654 
655  wxRichMessageDialog dlg(
656  this,
657  _( "Saving the project to the new file format will overwrite existing files." ),
658  _( "Project Save Warning" ),
659  wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER | wxICON_EXCLAMATION );
660  dlg.ShowDetailedText( wxString::Format(
661  _( "The following files will be overwritten:\n\n%s" ), msg ) );
662  dlg.SetOKCancelLabels( wxMessageDialog::ButtonLabel( _( "Overwrite Files" ) ),
663  wxMessageDialog::ButtonLabel( _( "Abort Project Save" ) ) );
664 
665  if( dlg.ShowModal() == wxID_CANCEL )
666  return false;
667  }
668 
669  for( size_t i = 0; i < screens.GetCount(); i++ )
670  {
671  screen = screens.GetScreen( i );
672 
673  wxCHECK2( screen, continue );
674 
675  // Convert legacy schematics file name extensions for the new format.
676  wxFileName tmpFn = screen->GetFileName();
677 
678  if( tmpFn.GetExt() != KiCadSchematicFileExtension )
679  {
680  updateFileType = true;
681  tmpFn.SetExt( KiCadSchematicFileExtension );
682 
683  for( auto item : screen->Items().OfType( SCH_SHEET_T ) )
684  {
685  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
686  wxFileName sheetFileName = sheet->GetFileName();
687 
688  if( sheetFileName.GetExt() == KiCadSchematicFileExtension )
689  continue;
690 
691  sheetFileName.SetExt( KiCadSchematicFileExtension );
692  sheet->SetFileName( sheetFileName.GetFullPath() );
693  RefreshItem( sheet );
694  }
695 
696  screen->SetFileName( tmpFn.GetFullPath() );
697  }
698 
699  success &= SaveEEFile( screens.GetSheet( i ) );
700  }
701 
702  if( updateFileType )
703  UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
704 
705  // Save the sheet name map to the project file
706  std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
707  sheets.clear();
708 
709  for( SCH_SHEET_PATH& sheetPath : Schematic().GetSheets() )
710  {
711  SCH_SHEET* sheet = sheetPath.Last();
712  sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
713  }
714 
715  Pgm().GetSettingsManager().SaveProject();
716 
717  UpdateTitle();
718 
719  return success;
720 }
721 
722 
724 {
725  wxFileName tmpFileName = Schematic().Root().GetFileName();
726  wxFileName fn = tmpFileName;
727  wxFileName tmp;
728  SCH_SCREENS screens( Schematic().Root() );
729 
730  bool autoSaveOk = true;
731 
732  tmp.AssignDir( fn.GetPath() );
733 
734  if( !tmp.IsOk() )
735  return false;
736 
737  if( !IsWritable( tmp ) )
738  return false;
739 
740  for( size_t i = 0; i < screens.GetCount(); i++ )
741  {
742  // Only create auto save files for the schematics that have been modified.
743  if( !screens.GetScreen( i )->IsSave() )
744  continue;
745 
746  tmpFileName = fn = screens.GetScreen( i )->GetFileName();
747 
748  // Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
749  fn.SetName( GetAutoSaveFilePrefix() + fn.GetName() );
750 
751  screens.GetScreen( i )->SetFileName( fn.GetFullPath() );
752 
753  if( SaveEEFile( screens.GetSheet( i ), false ) )
754  screens.GetScreen( i )->SetModify();
755  else
756  autoSaveOk = false;
757 
758  screens.GetScreen( i )->SetFileName( tmpFileName.GetFullPath() );
759  }
760 
761  if( autoSaveOk )
762  m_autoSaveState = false;
763 
764  return autoSaveOk;
765 }
766 
767 
768 bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
769 {
770  wxFileName newfilename;
771  SCH_SHEET_LIST sheetList = Schematic().GetSheets();
772 
773  switch( (SCH_IO_MGR::SCH_FILE_T) aFileType )
774  {
775  case SCH_IO_MGR::SCH_EAGLE:
776  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
777  wxASSERT_MSG( wxFileName( aFileName ).IsAbsolute(),
778  wxT( "Import eagle schematic caller didn't send full filename" ) );
779 
780  if( !LockFile( aFileName ) )
781  {
782  wxString msg = wxString::Format( _( "Schematic file \"%s\" is already open." ),
783  aFileName );
784  DisplayError( this, msg );
785  return false;
786  }
787 
788  try
789  {
790  Schematic().Reset();
791 
792  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_EAGLE ) );
793  Schematic().SetRoot( pi->Load( aFileName, &Schematic() ) );
794 
795  // Eagle sheets do not use a worksheet frame by default, so set it to an empty one
797  pglayout.SetEmptyLayout();
798 
799  BASE_SCREEN::m_PageLayoutDescrFileName = "empty.kicad_wks";
800  wxFileName layoutfn( Prj().GetProjectPath(), BASE_SCREEN::m_PageLayoutDescrFileName );
801  wxFile layoutfile;
802 
803  if( layoutfile.Create( layoutfn.GetFullPath() ) )
804  {
805  layoutfile.Write( WS_DATA_MODEL::EmptyLayout() );
806  layoutfile.Close();
807  }
808 
809  newfilename.SetPath( Prj().GetProjectPath() );
810  newfilename.SetName( Prj().GetProjectName() );
811  newfilename.SetExt( LegacySchematicFileExtension );
812 
813  GetCurrentSheet().push_back( &Schematic().Root() );
814  SetScreen( GetCurrentSheet().LastScreen() );
815 
816  Schematic().Root().SetFileName( newfilename.GetFullPath() );
817  GetScreen()->SetFileName( newfilename.GetFullPath() );
818  GetScreen()->SetModify();
820 
821  UpdateFileHistory( aFileName );
822  SCH_SCREENS schematic( Schematic().Root() );
823  schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
824 
825  GetScreen()->m_Initialized = true;
826 
827  for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
828  {
829  for( auto item : screen->Items().OfType( SCH_COMPONENT_T ) )
830  {
831  std::vector<wxPoint> pts;
832  SCH_COMPONENT* cmp = static_cast<SCH_COMPONENT*>( item );
833 
834  // Update footprint LIB_ID to point to the imported Eagle library
835  auto fpField = cmp->GetField( FOOTPRINT );
836 
837  if( !fpField->GetText().IsEmpty() )
838  {
839  LIB_ID fpId;
840  fpId.Parse( fpField->GetText(), LIB_ID::ID_SCH, true );
841  fpId.SetLibNickname( newfilename.GetName() );
842  fpField->SetText( fpId.Format() );
843  }
844  }
845  }
846  // Only perform the dangling end test on root sheet.
848 
849  GetScreen()->ClearUndoORRedoList( GetScreen()->m_UndoList, 1 );
850 
853  SyncView();
854  UpdateTitle();
855  }
856  catch( const IO_ERROR& ioe )
857  {
858  // Do not leave g_RootSheet == NULL because it is expected to be
859  // a valid sheet. Therefore create a dummy empty root sheet and screen.
860  CreateScreens();
862 
863  wxString msg;
864  msg.Printf( _( "Error loading schematic \"%s\".\n%s" ), aFileName, ioe.What() );
865  DisplayError( this, msg );
866 
867  msg.Printf( _( "Failed to load \"%s\"" ), aFileName );
868  AppendMsgPanel( wxEmptyString, msg, CYAN );
869 
870  return false;
871  }
872 
873  return true;
874 
875  default:
876  return false;
877  }
878 }
879 
880 
882 {
883  SCH_SCREENS screenList( Schematic().Root() );
884 
885  // Save any currently open and modified project files.
886  for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
887  {
888  if( screen->IsModify() )
889  {
890  if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
891  "Save changes?" ),
892  [&]()->bool { return SaveProject(); } ) )
893  {
894  return false;
895  }
896  }
897  }
898 
899  return true;
900 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
WS_DATA_MODEL handles the graphic items list to draw/plot the frame and title block.
Definition: ws_data_model.h:39
SCH_SHEET_LIST.
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: infobar.cpp:119
void Save_File(bool doSaveAs=false)
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:201
void UpdateSymbolInstances(const std::vector< COMPONENT_INSTANCE_REFERENCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
bool IsModified()
Function IsModified checks the entire hierarchy for any modifications.
const wxString & GetFileName() const
Definition: sch_screen.h:189
SCH_SCREEN * GetNext()
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Function OpenProjectFiles is abstract, and opens a project or set of files given by aFileList.
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
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).
void SetShutdownBlockReason(const wxString &reason)
Sets the block reason why the window/application is preventing OS shutdown.
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:92
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
This file is part of the common library TODO brief description.
SETTINGS_MANAGER * GetSettingsManager() const
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generates the connection data for the entire schematic hierarchy.
void SaveProjectSettings() override
Save changes to the project settings to the project (.pro) file.
CONNECTION_GRAPH * ConnectionGraph() const
Definition: schematic.h:132
SCH_SHEET * Last() const
Function Last returns a pointer to the last sheet of the list One can see the others sheet as the "pa...
This file is part of the common library.
const std::string ProjectFileExtension
void SetScreen(BASE_SCREEN *aScreen) override
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
#define KICTL_CREATE
caller thinks requested project files may not exist
Definition: kiway_player.h:79
EE_TYPE OfType(KICAD_T aType)
Definition: sch_rtree.h:219
bool AskToSaveChanges()
Checks if any of the screens has unsaved changes and asks the user whether to save or drop them.
wxString KiCadSchematicFileWildcard()
static TOOL_ACTION zoomFitScreen
Definition: actions.h:93
void UpdateTitle()
Set the main window title bar text.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
void OnAppendProject(wxCommandEvent &event)
static wxString EmptyLayout()
Returns a string containing the empty layout shape.
bool IsWritable(const wxFileName &aFileName)
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
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:282
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
bool SaveEEFile(SCH_SHEET *aSheet, bool aSaveUnderNewName=false)
Save aSheet to a schematic file.
Field Name Module PCB, i.e. "16DIP300".
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
VTBL_ENTRY const wxString AbsolutePath(const wxString &aFileName) const
Function AbsolutePath fixes up aFileName if it is relative to the project's directory to be an absolu...
Definition: project.cpp:270
static WS_DATA_MODEL & GetTheInstance()
static function: returns the instance of WS_DATA_MODEL used in the application
void OnImportProject(wxCommandEvent &event)
VTBL_ENTRY void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:252
static wxString m_PageLayoutDescrFileName
the name of the page layout descr file, or emty to used the default pagelayout
Definition: base_screen.h:59
EESCHEMA_SETTINGS * eeconfig() const
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SetRoot(SCH_SHEET *aRootSheet)
Initializes the schematic with a new root sheet.
Definition: schematic.cpp:112
bool RescueSymbolLibTableProject(bool aRunningOnDemand)
SCH_EDITOR_CONTROL.
static SCH_FILE_T GuessPluginTypeFromSchPath(const wxString &aSchematicPath)
Return a plugin type given a schematic using the file extension of aSchematicPath.
Definition: sch_io_mgr.cpp:171
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:139
Base class that schematic file and library loading and saving plugins should derive from.
Definition: sch_io_mgr.h:151
void SetFileName(wxString aFilename)
Definition: sch_sheet.h:502
bool LoadSheetFromFile(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy, const wxString &aFileName)
Load a the KiCad schematic file aFileName into the sheet aSheet.
Definition: sheet.cpp:104
void CheckForAutoSaveFile(const wxFileName &aFileName)
Check if an auto save file exists for aFileName and takes the appropriate action depending on the use...
wxString GetName() const
Definition: sch_sheet.h:280
#define NULL
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void HardRedraw() override
Rebuild the GAL and redraw the screen.
void SyncView()
Mark all items for refresh.
bool m_Initialized
Definition: base_screen.h:79
int ShowQuasiModal()
VTBL_ENTRY PROJECT_FILE & GetProjectFile() const
Definition: project.h:129
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
SCHEMATIC & Schematic() const
Definition of file extensions used in Kicad.
bool AppendSchematic()
Import a KiCad schematic into the current sheet.
bool CreateArchiveLibraryCacheFile(bool aUseCurrentSheetFilename=false)
Create a symbol library file with the name of the root document plus the '-cache' suffix,...
Definition: libarch.cpp:43
Definition: color4d.h:58
wxLogTrace helper definitions.
size_t GetCount() const
Definition: sch_screen.h:561
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
SCH_SHEET_PATH.
VTBL_ENTRY const wxString GetProjectFullName() const
Function GetProjectFullName returns the full path and name of the project.
Definition: project.cpp:116
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:496
void SetProject(PROJECT *aPrj)
Definition: schematic.cpp:71
virtual void ClearMsgPanel()
Clear all messages from the message panel.
const std::string LegacySchematicFileExtension
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:212
UTF8 Format() const
Definition: lib_id.cpp:237
bool LoadProjectSettings()
Loads the KiCad project file (*.pro) settings specific to Eeschema.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:216
bool doAutoSave() override
Save the schematic files that have been modified and not yet saved.
const KIID m_Uuid
Definition: base_struct.h:162
int SetLibNickname(const UTF8 &aNickname)
Override the logical library name portion of the LIB_ID to aNickname.
Definition: lib_id.cpp:193
static wxString GetAutoSaveFilePrefix()
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:468
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
void AppendMsgPanel(const wxString &textUpper, const wxString &textLower, COLOR4D color, int pad=6)
Append a message to the message panel.
void Reset()
Initializes this schematic to a blank one, unloading anything existing.
Definition: schematic.cpp:48
std::vector< FILE_INFO_PAIR > & GetSheets()
Definition: project_file.h:81
SCH_SHEET & Root() const
Definition: schematic.h:97
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:48
see class PGM_BASE
bool IsSave() const
Definition: base_screen.h:188
void TestDanglingEnds()
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 SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
wxString EagleSchematicFileWildcard()
void RefreshItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
WX_INFOBAR * m_infoBar
#define _(s)
Definition: 3d_actions.cpp:33
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Saves, unloads and unregisters the given PROJECT.
EE_RTREE & Items()
Definition: sch_screen.h:162
bool SaveProject(const wxString &aFullPath=wxEmptyString)
Saves a loaded project.
SCH_SHEET * GetSheet(unsigned int aIndex) const
const std::string KiCadSchematicFileExtension
void ClrModify()
Definition: base_screen.h:184
Schematic symbol object.
Definition: sch_component.h:88
SCH_SHEET_PATH & GetCurrentSheet() const
int ReplaceDuplicateTimeStamps()
Test all sheet and component objects in the schematic for duplicate time stamps and replaces them as ...
SCH_SCREEN * GetFirst()
SCH_SCREEN * GetScreen(unsigned int aIndex) const
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
void ClearDrawingState()
Clear the state flags of all the items in the screen.
Definition: sch_screen.cpp:819
virtual void ClearUndoORRedoList(UNDO_REDO_CONTAINER &aList, int aItemCount=-1) override
Free the undo or redo list from aList element.
Definition: sch_screen.cpp:804
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:187
Definition for part library class.
void SetModify()
Definition: base_screen.h:183
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
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 UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_PART reference for each SCH_COMPONENT found in the full schematic.
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:267
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)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:283
void ClrSave()
Definition: base_screen.h:186
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:550
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
bool TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr)
Test all of the connectable objects in the schematic for unused connection points.
Definition: sch_screen.cpp:994
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: infobar.cpp:202