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-2021 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 <symbol_library.h>
28 #include <confirm.h>
29 #include <connection_graph.h>
30 #include <dialog_migrate_buses.h>
31 #include <dialog_symbol_remap.h>
32 #include <eeschema_settings.h>
33 #include <id.h>
34 #include <kiface_base.h>
35 #include <kiplatform/app.h>
36 #include <pgm_base.h>
37 #include <profile.h>
38 #include <project/project_file.h>
39 #include <project_rescue.h>
40 #include <wx_html_report_box.h>
42 #include <reporter.h>
43 #include <richio.h>
44 #include <sch_edit_frame.h>
46 #include <sch_file_versions.h>
47 #include <sch_sheet.h>
48 #include <sch_sheet_path.h>
49 #include <schematic.h>
51 #include <tool/actions.h>
52 #include <tool/tool_manager.h>
54 #include <trace_helpers.h>
55 #include <widgets/infobar.h>
58 #include <wx/ffile.h>
59 #include <wx/filedlg.h>
60 #include <wx/log.h>
62 #include <paths.h>
63 #include <wx_filename.h> // For ::ResolvePossibleSymlinks
65 
66 
68 class CREATE_PROJECT_CHECKBOX : public wxPanel
69 {
70 public:
71  CREATE_PROJECT_CHECKBOX( wxWindow* aParent )
72  : wxPanel( aParent )
73  {
74  m_cbCreateProject = new wxCheckBox( this, wxID_ANY,
75  _( "Create a new project for this schematic" ) );
76  m_cbCreateProject->SetValue( true );
77  m_cbCreateProject->SetToolTip( _( "Creating a project will enable features such as "
78  "text variables, net classes, and ERC exclusions" ) );
79 
80  wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL );
81  sizer->Add( m_cbCreateProject, 0, wxALL, 8 );
82 
83  SetSizerAndFit( sizer );
84  }
85 
86  bool GetValue() const
87  {
88  return m_cbCreateProject->GetValue();
89  }
90 
91  static wxWindow* Create( wxWindow* aParent )
92  {
93  return new CREATE_PROJECT_CHECKBOX( aParent );
94  }
95 
96 protected:
97  wxCheckBox* m_cbCreateProject;
98 };
99 
100 
101 bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
102 {
103  // implement the pseudo code from KIWAY_PLAYER.h:
104  wxString msg;
105 
106  EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
107 
108  // This is for python:
109  if( aFileSet.size() != 1 )
110  {
111  msg.Printf( "Eeschema:%s() takes only a single filename.", __WXFUNCTION__ );
112  DisplayError( this, msg );
113  return false;
114  }
115 
116  wxString fullFileName( aFileSet[0] );
117  wxFileName wx_filename( fullFileName );
118 
119  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
120  wxASSERT_MSG( wx_filename.IsAbsolute(), wxT( "Path is not absolute!" ) );
121 
122  if( !LockFile( fullFileName ) )
123  {
124  msg.Printf( _( "Schematic '%s' is already open." ), wx_filename.GetFullName() );
125 
126  if( !OverrideLock( this, msg ) )
127  return false;
128  }
129 
130  if( !AskToSaveChanges() )
131  return false;
132 
133 #ifdef PROFILE
134  PROF_COUNTER openFiles( "OpenProjectFile" );
135 #endif
136 
137  wxFileName pro = fullFileName;
138  pro.SetExt( ProjectFileExtension );
139 
140  bool is_new = !wxFileName::IsFileReadable( fullFileName );
141 
142  // If its a non-existent schematic and caller thinks it exists
143  if( is_new && !( aCtl & KICTL_CREATE ) )
144  {
145  // notify user that fullFileName does not exist, ask if user wants to create it.
146  msg.Printf( _( "Schematic '%s' does not exist. Do you wish to create it?" ),
147  fullFileName );
148 
149  if( !IsOK( this, msg ) )
150  return false;
151  }
152 
153  // unload current project file before loading new
154  {
156  SetScreen( nullptr );
158  CreateScreens();
159  }
160 
161  SetStatusText( wxEmptyString );
162  m_infoBar->Dismiss();
163 
164  WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Creating Schematic" )
165  : _( "Loading Schematic" ), 1 );
166 
167  bool differentProject = pro.GetFullPath() != Prj().GetProjectFullName();
168 
169  if( differentProject )
170  {
171  if( !Prj().IsNullProject() )
173 
174  Schematic().SetProject( nullptr );
175  GetSettingsManager()->UnloadProject( &Prj(), false );
176 
177  GetSettingsManager()->LoadProject( pro.GetFullPath() );
178 
179  wxFileName legacyPro( pro );
180  legacyPro.SetExt( LegacyProjectFileExtension );
181 
182  // Do not allow saving a project if one doesn't exist. This normally happens if we are
183  // standalone and opening a schematic that has been moved from its project folder.
184  if( !pro.Exists() && !legacyPro.Exists() && !( aCtl & KICTL_CREATE ) )
185  Prj().SetReadOnly();
186 
187  CreateScreens();
188  }
189 
190  SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( fullFileName );
191 
192  if( schFileType == SCH_IO_MGR::SCH_LEGACY )
193  {
194  // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
195  // They are already saved in the kiface project object.
196  if( differentProject || !Prj().GetElem( PROJECT::ELEM_SCH_SYMBOL_LIBS ) )
197  {
198  // load the libraries here, not in SCH_SCREEN::Draw() which is a context
199  // that will not tolerate DisplayError() dialog since we're already in an
200  // event handler in there.
201  // And when a schematic file is loaded, we need these libs to initialize
202  // some parameters (links to PART LIB, dangling ends ...)
204  Prj().SchLibs();
205  }
206  }
207  else
208  {
209  // No legacy symbol libraries including the cache are loaded with the new file format.
211  }
212 
213  // Load the symbol library table, this will be used forever more.
215  Prj().SchSymbolLibTable();
216 
217  // Load project settings after schematic has been set up with the project link, since this will
218  // update some of the needed schematic settings such as drawing defaults
220 
221  wxFileName rfn( GetCurrentFileName() );
222  rfn.MakeRelativeTo( Prj().GetProjectPath() );
223  LoadWindowState( rfn.GetFullPath() );
224 
225  KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Schematic file changes are unsaved" ) );
226 
227  if( Kiface().IsSingle() )
228  {
230  }
231 
232  if( is_new )
233  {
234  // mark new, unsaved file as modified.
236  GetScreen()->SetFileName( fullFileName );
237  }
238  else
239  {
240  // This will rename the file if there is an autosave and the user want to recover.
241  CheckForAutoSaveFile( fullFileName );
242 
243  SetScreen( nullptr );
244 
245  SCH_PLUGIN* plugin = SCH_IO_MGR::FindPlugin( schFileType );
246  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( plugin );
247 
248  pi->SetProgressReporter( &progressReporter );
249 
250  bool failedLoad = false;
251 
252  try
253  {
254  Schematic().SetRoot( pi->Load( fullFileName, &Schematic() ) );
255 
256  if( !pi->GetError().IsEmpty() )
257  {
258  DisplayErrorMessage( this, _( "The entire schematic could not be loaded. Errors "
259  "occurred attempting to load hierarchical sheets." ),
260  pi->GetError() );
261  }
262  }
263  catch( const FUTURE_FORMAT_ERROR& ffe )
264  {
265  msg.Printf( _( "Error loading schematic '%s'." ), fullFileName);
266  progressReporter.Hide();
267  DisplayErrorMessage( this, msg, ffe.Problem() );
268 
269  failedLoad = true;
270  }
271  catch( const IO_ERROR& ioe )
272  {
273  msg.Printf( _( "Error loading schematic '%s'." ), fullFileName);
274  progressReporter.Hide();
275  DisplayErrorMessage( this, msg, ioe.What() );
276 
277  failedLoad = true;
278  }
279  catch( const std::bad_alloc& )
280  {
281  msg.Printf( _( "Memory exhausted loading schematic '%s'." ), fullFileName );
282  progressReporter.Hide();
283  DisplayErrorMessage( this, msg, wxEmptyString );
284 
285  failedLoad = true;
286  }
287 
288  // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
289  // cause any issues on macOS and Windows. If it does, it will have to be conditionally
290  // compiled.
291  Raise();
292 
293  if( failedLoad )
294  {
295  // Do not leave g_RootSheet == NULL because it is expected to be
296  // a valid sheet. Therefore create a dummy empty root sheet and screen.
297  CreateScreens();
299 
300  msg.Printf( _( "Failed to load '%s'." ), fullFileName );
301  SetMsgPanel( wxEmptyString, msg );
302 
303  return false;
304  }
305 
306  // It's possible the schematic parser fixed errors due to bugs so warn the user
307  // that the schematic has been fixed (modified).
308  SCH_SHEET_LIST sheetList = Schematic().GetSheets();
309 
310  if( sheetList.IsModified() )
311  {
312  DisplayInfoMessage( this,
313  _( "An error was found when loading the schematic that has "
314  "been automatically fixed. Please save the schematic to "
315  "repair the broken file or it may not be usable with other "
316  "versions of KiCad." ) );
317  }
318 
319  if( sheetList.AllSheetPageNumbersEmpty() )
320  sheetList.SetInitialPageNumbers();
321 
322  UpdateFileHistory( fullFileName );
323 
324  SCH_SCREENS schematic( Schematic().Root() );
325 
326  // LIB_ID checks and symbol rescue only apply to the legacy file formats.
327  if( schFileType == SCH_IO_MGR::SCH_LEGACY )
328  {
329  // Convert old projects over to use symbol library table.
330  if( schematic.HasNoFullyDefinedLibIds() )
331  {
332  DIALOG_SYMBOL_REMAP dlgRemap( this );
333 
334  dlgRemap.ShowQuasiModal();
335  }
336  else
337  {
338  // Double check to ensure no legacy library list entries have been
339  // added to the projec file symbol library list.
340  wxString paths;
341  wxArrayString libNames;
342 
343  SYMBOL_LIBS::LibNamesAndPaths( &Prj(), false, &paths, &libNames );
344 
345  if( !libNames.IsEmpty() )
346  {
348  {
349  wxRichMessageDialog invalidLibDlg(
350  this,
351  _( "Illegal entry found in project file symbol library list." ),
352  _( "Project Load Warning" ),
353  wxOK | wxCENTER | wxICON_EXCLAMATION );
354  invalidLibDlg.ShowDetailedText(
355  _( "Symbol libraries defined in the project file symbol library "
356  "list are no longer supported and will be removed.\n\n"
357  "This may cause broken symbol library links under certain "
358  "conditions." ) );
359  invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
360  invalidLibDlg.ShowModal();
362  !invalidLibDlg.IsCheckBoxChecked();
363  }
364 
365  libNames.Clear();
366  paths.Clear();
367  SYMBOL_LIBS::LibNamesAndPaths( &Prj(), true, &paths, &libNames );
368  }
369 
370  if( !cfg || !cfg->m_RescueNeverShow )
371  {
373  editor->RescueSymbolLibTableProject( false );
374  }
375  }
376 
377  // Ensure there is only one legacy library loaded and that it is the cache library.
378  SYMBOL_LIBS* legacyLibs = Schematic().Prj().SchLibs();
379 
380  if( legacyLibs->GetLibraryCount() == 0 )
381  {
382  wxString extMsg;
383  wxFileName cacheFn = pro;
384 
385  cacheFn.SetName( cacheFn.GetName() + "-cache" );
386  cacheFn.SetExt( LegacySymbolLibFileExtension );
387 
388  msg.Printf( _( "The project symbol library cache file '%s' was not found." ),
389  cacheFn.GetFullName() );
390  extMsg = _( "This can result in a broken schematic under certain conditions. "
391  "If the schematic does not have any missing symbols upon opening, "
392  "save it immediately before making any changes to prevent data "
393  "loss. If there are missing symbols, either manual recovery of "
394  "the schematic or recovery of the symbol cache library file and "
395  "reloading the schematic is required." );
396 
397  wxMessageDialog dlgMissingCache( this, msg, _( "Warning" ),
398  wxOK | wxCANCEL | wxICON_EXCLAMATION | wxCENTER );
399  dlgMissingCache.SetExtendedMessage( extMsg );
400  dlgMissingCache.SetOKCancelLabels(
401  wxMessageDialog::ButtonLabel( _( "Load Without Cache File" ) ),
402  wxMessageDialog::ButtonLabel( _( "Abort" ) ) );
403 
404  if( dlgMissingCache.ShowModal() == wxID_CANCEL )
405  {
406  Schematic().Reset();
407  CreateScreens();
408  return false;
409  }
410  }
411 
412  // Update all symbol library links for all sheets.
413  schematic.UpdateSymbolLinks();
414 
417  m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
418  "It will be converted to the new format when saved." ),
419  wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
420 
421  // Legacy schematic can have duplicate time stamps so fix that before converting
422  // to the s-expression format.
423  schematic.ReplaceDuplicateTimeStamps();
424 
425  // Allow the schematic to be saved to new file format without making any edits.
426  OnModify();
427  }
428  else // S-expression schematic.
429  {
431  {
434  m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
435  "It will be converted to the new format when saved." ),
436  wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
437  }
438 
439  for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
440  screen->UpdateLocalLibSymbolLinks();
441 
442  // Restore all of the loaded symbol and sheet instances from the root sheet.
443  sheetList.UpdateSymbolInstances( Schematic().RootScreen()->GetSymbolInstances() );
444  sheetList.UpdateSheetInstances( Schematic().RootScreen()->GetSheetInstances() );
445  }
446 
448 
449  SetScreen( GetCurrentSheet().LastScreen() );
450 
451  // Migrate conflicting bus definitions
452  // TODO(JE) This should only run once based on schematic file version
453  if( Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() > 0 )
454  {
455  DIALOG_MIGRATE_BUSES dlg( this );
456  dlg.ShowQuasiModal();
458  OnModify();
459  }
460 
463  }
464 
465  // Load any exclusions from the project file
467 
468  initScreenZoom();
470 
473 
474  // re-create junctions if needed. Eeschema optimizes wires by merging
475  // colinear segments. If a schematic is saved without a valid
476  // cache library or missing installed libraries, this can cause connectivity errors
477  // unless junctions are added.
478  if( schFileType == SCH_IO_MGR::SCH_LEGACY )
479  FixupJunctions();
480 
481  SyncView();
483 
485  UpdateTitle();
486 
487  wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
488 
489  if( fn.FileExists() && !fn.IsFileWritable() )
490  {
493  m_infoBar->ShowMessage( _( "Schematic is read only." ), wxICON_WARNING );
494  }
495 
496 #ifdef PROFILE
497  openFiles.Show();
498 #endif
499 
500  return true;
501 }
502 
503 
505 {
506  wxString fullFileName;
507  SCH_SCREEN* screen = GetScreen();
508 
509  if( !screen )
510  {
511  wxLogError( wxT( "Document not ready, cannot import" ) );
512  return false;
513  }
514 
515  // open file chooser dialog
516  wxString path = wxPathOnly( Prj().GetProjectFullName() );
517 
518  wxFileDialog dlg( this, _( "Insert Schematic" ), path, wxEmptyString,
519  KiCadSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
520 
521  if( dlg.ShowModal() == wxID_CANCEL )
522  return false;
523 
524  fullFileName = dlg.GetPath();
525 
526  if( !LoadSheetFromFile( GetCurrentSheet().Last(), &GetCurrentSheet(), fullFileName ) )
527  return false;
528 
529  initScreenZoom();
531 
532  SyncView();
533  OnModify();
534  HardRedraw(); // Full reinit of the current screen and the display.
535 
537 
538  return true;
539 }
540 
541 
542 void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event )
543 {
544  if( GetScreen() && GetScreen()->IsModified() )
545  {
546  wxString msg = _( "This operation cannot be undone.\n\n"
547  "Do you want to save the current document before proceeding?" );
548 
549  if( IsOK( this, msg ) )
550  SaveProject();
551  }
552 
553  AppendSchematic();
554 }
555 
556 
557 void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
558 {
559  if( !AskToSaveChanges() )
560  return;
561 
562  // Set the project location if none is set or if we are running in standalone mode
563  bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
564  wxString path = wxPathOnly( Prj().GetProjectFullName() );
565 
566  std::list<std::pair<const wxString, const SCH_IO_MGR::SCH_FILE_T>> loaders;
567 
568  // Import Altium schematic files.
569  loaders.emplace_back( AltiumSchematicFileWildcard(), SCH_IO_MGR::SCH_ALTIUM );
570 
571  // Import CADSTAR Schematic Archive files.
572  loaders.emplace_back( CadstarSchematicArchiveFileWildcard(), SCH_IO_MGR::SCH_CADSTAR_ARCHIVE );
573 
574  // Import Eagle schematic files.
575  loaders.emplace_back( EagleSchematicFileWildcard(), SCH_IO_MGR::SCH_EAGLE );
576 
577  wxString fileFilters;
578  wxString allWildcards;
579 
580  for( std::pair<const wxString, const SCH_IO_MGR::SCH_FILE_T>& loader : loaders )
581  {
582  if( !fileFilters.IsEmpty() )
583  fileFilters += wxChar( '|' );
584 
585  fileFilters += wxGetTranslation( loader.first );
586 
587  SCH_PLUGIN::SCH_PLUGIN_RELEASER plugin( SCH_IO_MGR::FindPlugin( loader.second ) );
588  wxCHECK( plugin, /*void*/ );
589  allWildcards += "*." + formatWildcardExt( plugin->GetFileExtension() ) + ";";
590  }
591 
592  fileFilters = _( "All supported formats|" ) + allWildcards + "|" + fileFilters;
593 
594  wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFilters,
595  wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
596 
597  if( dlg.ShowModal() == wxID_CANCEL )
598  return;
599 
600  if( setProject )
601  {
602  Schematic().SetProject( nullptr );
603  GetSettingsManager()->UnloadProject( &Prj(), false );
604 
605  Schematic().Reset();
606 
607  wxFileName projectFn( dlg.GetPath() );
608  projectFn.SetExt( ProjectFileExtension );
609  GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
610 
611  Schematic().SetProject( &Prj() );
612  }
613 
614  wxFileName fn = dlg.GetPath();
615 
616  SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN;
617 
618  for( std::pair<const wxString, const SCH_IO_MGR::SCH_FILE_T>& loader : loaders )
619  {
620  if( fn.GetExt().CmpNoCase( SCH_IO_MGR::GetFileExtension( loader.second ) ) == 0 )
621  {
622  pluginType = loader.second;
623  break;
624  }
625  }
626 
627  if( pluginType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
628  {
629  wxLogError( _( "Unexpected file extension: '%s'." ), fn.GetExt() );
630  return;
631  }
632 
633  m_toolManager->GetTool<EE_SELECTION_TOOL>()->ClearSelection();
634 
635  importFile( dlg.GetPath(), pluginType );
636 
637  RefreshCanvas();
638 }
639 
640 
641 bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSavePath )
642 {
643  wxString msg;
644  wxFileName schematicFileName;
645  wxFileName oldFileName;
646  bool success;
647 
648  SCH_SCREEN* screen = aSheet->GetScreen();
649 
650  wxCHECK( screen, false );
651 
652  // Construct the name of the file to be saved
653  schematicFileName = Prj().AbsolutePath( aSavePath );
654  oldFileName = schematicFileName;
655 
656  // Write through symlinks, don't replace them
657  WX_FILENAME::ResolvePossibleSymlinks( schematicFileName );
658 
659  if( !IsWritable( schematicFileName ) )
660  return false;
661 
662  wxFileName tempFile( schematicFileName );
663  tempFile.SetName( wxT( "." ) + tempFile.GetName() );
664  tempFile.SetExt( tempFile.GetExt() + wxT( "$" ) );
665 
666  // Save
667  wxLogTrace( traceAutoSave, "Saving file " + schematicFileName.GetFullPath() );
668 
669  SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
670  schematicFileName.GetFullPath() );
671  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( pluginType ) );
672 
673  try
674  {
675  pi->Save( tempFile.GetFullPath(), aSheet, &Schematic() );
676  success = true;
677  }
678  catch( const IO_ERROR& ioe )
679  {
680  msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
681  schematicFileName.GetFullPath(),
682  ioe.What() );
683  DisplayError( this, msg );
684 
685  msg.Printf( _( "Failed to create temporary file '%s'." ),
686  tempFile.GetFullPath() );
687  SetMsgPanel( wxEmptyString, msg );
688 
689  // In case we started a file but didn't fully write it, clean up
690  wxRemoveFile( tempFile.GetFullPath() );
691 
692  success = false;
693  }
694 
695  if( success )
696  {
697  // Replace the original with the temporary file we just wrote
698  success = wxRenameFile( tempFile.GetFullPath(), schematicFileName.GetFullPath() );
699 
700  if( !success )
701  {
702  msg.Printf( _( "Error saving schematic file '%s'.\n"
703  "Failed to rename temporary file '%s'." ),
704  schematicFileName.GetFullPath(),
705  tempFile.GetFullPath() );
706  DisplayError( this, msg );
707 
708  msg.Printf( _( "Failed to rename temporary file '%s'." ),
709  tempFile.GetFullPath() );
710  SetMsgPanel( wxEmptyString, msg );
711  }
712  }
713 
714  if( success )
715  {
716  // Delete auto save file.
717  wxFileName autoSaveFileName = schematicFileName;
718  autoSaveFileName.SetName( GetAutoSaveFilePrefix() + schematicFileName.GetName() );
719 
720  if( autoSaveFileName.FileExists() )
721  {
722  wxLogTrace( traceAutoSave,
723  wxT( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() +
724  wxT( ">" ) );
725 
726  wxRemoveFile( autoSaveFileName.GetFullPath() );
727  }
728 
729  screen->SetContentModified( false );
730 
731  msg.Printf( _( "File '%s' saved." ), screen->GetFileName() );
732  SetStatusText( msg, 0 );
733  }
734  else
735  {
736  DisplayError( this, _( "File write operation failed." ) );
737  }
738 
739  return success;
740 }
741 
742 
743 bool SCH_EDIT_FRAME::SaveProject( bool aSaveAs )
744 {
745  wxString msg;
746  SCH_SCREEN* screen;
747  SCH_SCREENS screens( Schematic().Root() );
748  bool saveCopyAs = aSaveAs && !Kiface().IsSingle();
749  bool success = true;
750  bool updateFileType = false;
751  bool createNewProject = false;
752 
753  // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
754  wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
755  wxFileName fn = fileName;
756 
757  // Path to save each screen to: will be the stored filename by default, but is overwritten by
758  // a Save As Copy operation.
759  std::unordered_map<SCH_SCREEN*, wxString> filenameMap;
760 
761  // Handle "Save As" and saving a new project/schematic for the first time in standalone
762  if( Prj().IsNullProject() || aSaveAs )
763  {
764  // Null project should only be possible in standalone mode.
765  wxCHECK( Kiface().IsSingle() || aSaveAs, false );
766 
767  wxFileName newFileName;
768  wxFileName savePath( Prj().GetProjectFullName() );
769 
770  if( !savePath.IsOk() || !savePath.IsDirWritable() )
771  {
772  savePath = GetMruPath();
773 
774  if( !savePath.IsOk() || !savePath.IsDirWritable() )
776  }
777 
778  if( savePath.HasExt() )
779  savePath.SetExt( KiCadSchematicFileExtension );
780  else
781  savePath.SetName( wxEmptyString );
782 
783  wxFileDialog dlg( this, _( "Schematic Files" ), savePath.GetPath(),
784  savePath.GetFullName(), KiCadSchematicFileWildcard(),
785  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
786 
787  if( Kiface().IsSingle() || aSaveAs )
788  {
789  // Add a "Create a project" checkbox in standalone mode and one isn't loaded
790  dlg.SetExtraControlCreator( &CREATE_PROJECT_CHECKBOX::Create );
791  }
792 
793  if( dlg.ShowModal() == wxID_CANCEL )
794  return false;
795 
796  newFileName = dlg.GetPath();
797  newFileName.SetExt( KiCadSchematicFileExtension );
798 
799  if( ( !newFileName.DirExists() && !newFileName.Mkdir() ) ||
800  !newFileName.IsDirWritable() )
801  {
802  msg.Printf( _( "Folder '%s' could not be created.\n\n"
803  "Make sure you have write permissions and try again." ),
804  newFileName.GetPath() );
805 
806  wxMessageDialog dlgBadPath( this, msg, _( "Error" ),
807  wxOK | wxICON_EXCLAMATION | wxCENTER );
808 
809  dlgBadPath.ShowModal();
810  return false;
811  }
812 
813  if( wxWindow* ec = dlg.GetExtraControl() )
814  createNewProject = static_cast<CREATE_PROJECT_CHECKBOX*>( ec )->GetValue();
815 
816  if( !saveCopyAs )
817  {
818  Schematic().Root().SetFileName( newFileName.GetFullName() );
819  Schematic().RootScreen()->SetFileName( newFileName.GetFullPath() );
820  }
821  else
822  {
823  filenameMap[Schematic().RootScreen()] = newFileName.GetFullPath();
824  }
825 
826  // Set the base path to all new sheets.
827  for( size_t i = 0; i < screens.GetCount(); i++ )
828  {
829  screen = screens.GetScreen( i );
830 
831  wxCHECK2( screen, continue );
832 
833  // The root screen file name has already been set.
834  if( screen == Schematic().RootScreen() )
835  continue;
836 
837  wxFileName tmp = screen->GetFileName();
838 
839  // Assume existing sheet files are being reused and do not save them to the new
840  // path. Maybe in the future, add a user option to copy schematic files to the
841  // new project path.
842  if( tmp.FileExists() )
843  continue;
844 
845  if( tmp.GetPath().IsEmpty() )
846  {
847  tmp.SetPath( newFileName.GetPath() );
848  }
849  else if( tmp.GetPath() == fn.GetPath() )
850  {
851  tmp.SetPath( newFileName.GetPath() );
852  }
853  else if( tmp.GetPath().StartsWith( fn.GetPath() ) )
854  {
855  // NOTE: this hasn't been tested because the sheet properties dialog no longer
856  // allows adding a path specifier in the file name field.
857  wxString newPath = newFileName.GetPath();
858  newPath += tmp.GetPath().Right( fn.GetPath().Length() );
859  tmp.SetPath( newPath );
860  }
861 
862  wxLogTrace( tracePathsAndFiles,
863  wxT( "Moving schematic from '%s' to '%s'." ),
864  screen->GetFileName(),
865  tmp.GetFullPath() );
866 
867  if( !tmp.DirExists() && !tmp.Mkdir() )
868  {
869  msg.Printf( _( "Folder '%s' could not be created.\n\n"
870  "Make sure you have write permissions and try again." ),
871  newFileName.GetPath() );
872 
873  wxMessageDialog dlgBadFilePath( this, msg, _( "Error" ),
874  wxOK | wxICON_EXCLAMATION | wxCENTER );
875 
876  dlgBadFilePath.ShowModal();
877  return false;
878  }
879 
880  if( saveCopyAs )
881  filenameMap[screen] = tmp.GetFullPath();
882  else
883  screen->SetFileName( tmp.GetFullPath() );
884  }
885 
886  // Attempt to make sheet file name paths relative to the new root schematic path.
887  SCH_SHEET_LIST sheets = Schematic().GetSheets();
888 
889  for( SCH_SHEET_PATH& sheet : sheets )
890  {
891  if( sheet.Last()->IsRootSheet() )
892  continue;
893 
894  sheet.MakeFilePathRelativeToParentSheet();
895  }
896  }
897 
898  if( filenameMap.empty() || !saveCopyAs )
899  {
900  for( size_t i = 0; i < screens.GetCount(); i++ )
901  filenameMap[screens.GetScreen( i )] = screens.GetScreen( i )->GetFileName();
902  }
903 
904  // Warn user on potential file overwrite. This can happen on shared sheets.
905  wxArrayString overwrittenFiles;
906 
907  for( size_t i = 0; i < screens.GetCount(); i++ )
908  {
909  screen = screens.GetScreen( i );
910 
911  wxCHECK2( screen, continue );
912 
913  // Convert legacy schematics file name extensions for the new format.
914  wxFileName tmpFn = filenameMap[screen];
915 
916  if( !tmpFn.IsOk() )
917  continue;
918 
919  if( tmpFn.GetExt() == KiCadSchematicFileExtension )
920  continue;
921 
922  tmpFn.SetExt( KiCadSchematicFileExtension );
923 
924  if( tmpFn.FileExists() )
925  overwrittenFiles.Add( tmpFn.GetFullPath() );
926  }
927 
928  if( !overwrittenFiles.IsEmpty() )
929  {
930  for( const wxString& overwrittenFile : overwrittenFiles )
931  {
932  if( msg.IsEmpty() )
933  msg = overwrittenFile;
934  else
935  msg += "\n" + overwrittenFile;
936  }
937 
938  wxRichMessageDialog dlg( this, _( "Saving will overwrite existing files." ),
939  _( "Save Warning" ),
940  wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER |
941  wxICON_EXCLAMATION );
942  dlg.ShowDetailedText( _( "The following files will be overwritten:\n\n" ) + msg );
943  dlg.SetOKCancelLabels( wxMessageDialog::ButtonLabel( _( "Overwrite Files" ) ),
944  wxMessageDialog::ButtonLabel( _( "Abort Project Save" ) ) );
945 
946  if( dlg.ShowModal() == wxID_CANCEL )
947  return false;
948  }
949 
950  screens.BuildClientSheetPathList();
951 
952  for( size_t i = 0; i < screens.GetCount(); i++ )
953  {
954  screen = screens.GetScreen( i );
955 
956  wxCHECK2( screen, continue );
957 
958  // Convert legacy schematics file name extensions for the new format.
959  wxFileName tmpFn = filenameMap[screen];
960 
961  if( tmpFn.IsOk() && tmpFn.GetExt() != KiCadSchematicFileExtension )
962  {
963  updateFileType = true;
964  tmpFn.SetExt( KiCadSchematicFileExtension );
965 
966  for( auto item : screen->Items().OfType( SCH_SHEET_T ) )
967  {
968  SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
969  wxFileName sheetFileName = sheet->GetFileName();
970 
971  if( !sheetFileName.IsOk() || sheetFileName.GetExt() == KiCadSchematicFileExtension )
972  continue;
973 
974  sheetFileName.SetExt( KiCadSchematicFileExtension );
975  sheet->SetFileName( sheetFileName.GetFullPath() );
976  UpdateItem( sheet );
977  }
978 
979  filenameMap[screen] = tmpFn.GetFullPath();
980 
981  if( !saveCopyAs )
982  screen->SetFileName( tmpFn.GetFullPath() );
983  }
984 
985  std::vector<SCH_SHEET_PATH>& sheets = screen->GetClientSheetPaths();
986 
987  if( sheets.size() == 1 )
988  screen->SetVirtualPageNumber( 1 );
989  else
990  screen->SetVirtualPageNumber( 0 ); // multiple uses; no way to store the real sheet #
991 
992  // This is a new schematic file so make sure it has a unique ID.
993  if( !saveCopyAs && tmpFn.GetFullPath() != screen->GetFileName() )
994  screen->AssignNewUuid();
995 
996  success &= saveSchematicFile( screens.GetSheet( i ), tmpFn.GetFullPath() );
997  }
998 
999  if( aSaveAs && success )
1000  LockFile( Schematic().RootScreen()->GetFileName() );
1001 
1002  if( updateFileType )
1003  UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
1004 
1005  // Save the sheet name map to the project file
1006  std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
1007  sheets.clear();
1008 
1009  for( SCH_SHEET_PATH& sheetPath : Schematic().GetSheets() )
1010  {
1011  SCH_SHEET* sheet = sheetPath.Last();
1012 
1013  wxCHECK2( sheet, continue );
1014 
1015  // Use the schematic UUID for the root sheet.
1016  if( sheet->IsRootSheet() )
1017  {
1018  screen = sheet->GetScreen();
1019 
1020  wxCHECK2( screen, continue );
1021 
1022  sheets.emplace_back( std::make_pair( screen->GetUuid(), sheet->GetName() ) );
1023  }
1024  else
1025  {
1026  sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
1027  }
1028  }
1029 
1030  wxASSERT( filenameMap.count( Schematic().RootScreen() ) );
1031  wxFileName projectPath( filenameMap.at( Schematic().RootScreen() ) );
1032  projectPath.SetExt( ProjectFileExtension );
1033 
1034  if( Prj().IsNullProject() || ( aSaveAs && !saveCopyAs ) )
1035  {
1036  Prj().SetReadOnly( !createNewProject );
1037  GetSettingsManager()->SaveProjectAs( projectPath.GetFullPath() );
1038  }
1039  else if( saveCopyAs && createNewProject )
1040  {
1041  GetSettingsManager()->SaveProjectCopy( projectPath.GetFullPath() );
1042  }
1043  else
1044  {
1046  }
1047 
1048  if( !Kiface().IsSingle() )
1049  {
1050  WX_STRING_REPORTER backupReporter( &msg );
1051 
1052  if( !GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1053  SetStatusText( msg, 0 );
1054  }
1055 
1056  UpdateTitle();
1057 
1059  m_infoBar->Dismiss();
1060 
1061  return success;
1062 }
1063 
1064 
1066 {
1067  wxFileName tmpFileName = Schematic().Root().GetFileName();
1068  wxFileName fn = tmpFileName;
1069  wxFileName tmp;
1070  SCH_SCREENS screens( Schematic().Root() );
1071 
1072  // Don't run autosave if content has not been modified
1073  if( !IsContentModified() )
1074  return true;
1075 
1076  bool autoSaveOk = true;
1077 
1078  if( fn.GetPath().IsEmpty() )
1079  tmp.AssignDir( Prj().GetProjectPath() );
1080  else
1081  tmp.AssignDir( fn.GetPath() );
1082 
1083  if( !tmp.IsOk() )
1084  return false;
1085 
1086  if( !IsWritable( tmp ) )
1087  return false;
1088 
1089  wxString title = GetTitle(); // Save frame title, that can be modified by the save process
1090 
1091  for( size_t i = 0; i < screens.GetCount(); i++ )
1092  {
1093  // Only create auto save files for the schematics that have been modified.
1094  if( !screens.GetScreen( i )->IsContentModified() )
1095  continue;
1096 
1097  tmpFileName = fn = screens.GetScreen( i )->GetFileName();
1098 
1099  // Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
1100  fn.SetName( GetAutoSaveFilePrefix() + fn.GetName() );
1101 
1102  if( saveSchematicFile( screens.GetSheet( i ), fn.GetFullPath() ) )
1103  screens.GetScreen( i )->SetContentModified();
1104  else
1105  autoSaveOk = false;
1106  }
1107 
1108  if( autoSaveOk )
1109  {
1110  m_autoSaveState = false;
1111 
1112  if( !Kiface().IsSingle() &&
1113  GetSettingsManager()->GetCommonSettings()->m_Backup.backup_on_autosave )
1114  {
1116  }
1117  }
1118 
1119  SetTitle( title );
1120 
1121  return autoSaveOk;
1122 }
1123 
1124 
1125 bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
1126 {
1127  wxFileName filename( aFileName );
1128  wxFileName newfilename;
1129  SCH_SHEET_LIST sheetList = Schematic().GetSheets();
1130  SCH_IO_MGR::SCH_FILE_T fileType = (SCH_IO_MGR::SCH_FILE_T) aFileType;
1131 
1132  switch( fileType )
1133  {
1134  case SCH_IO_MGR::SCH_ALTIUM:
1135  case SCH_IO_MGR::SCH_CADSTAR_ARCHIVE:
1136  case SCH_IO_MGR::SCH_EAGLE:
1137  // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
1138  wxASSERT_MSG( filename.IsAbsolute(), wxT( "Import schematic: path is not absolute!" ) );
1139 
1140  if( !LockFile( aFileName ) )
1141  {
1142  wxString msg;
1143  msg.Printf( _( "Schematic '%s' is already open." ), filename.GetFullName() );
1144 
1145  if( !OverrideLock( this, msg ) )
1146  return false;
1147  }
1148 
1149  try
1150  {
1151  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( fileType ) );
1152  DIALOG_HTML_REPORTER errorReporter( this );
1153  WX_PROGRESS_REPORTER progressReporter( this, _( "Importing Schematic" ), 1 );
1154 
1155  pi->SetReporter( errorReporter.m_Reporter );
1156  pi->SetProgressReporter( &progressReporter );
1157  Schematic().SetRoot( pi->Load( aFileName, &Schematic() ) );
1158 
1159  if( errorReporter.m_Reporter->HasMessage() )
1160  {
1161  errorReporter.m_Reporter->Flush(); // Build HTML messages
1162  errorReporter.ShowModal();
1163  }
1164 
1165  // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works differently
1166  // to KiCad), so set it to an empty one
1167  DS_DATA_MODEL& drawingSheet = DS_DATA_MODEL::GetTheInstance();
1168  drawingSheet.SetEmptyLayout();
1169 
1170  BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
1171  wxFileName layoutfn( Prj().GetProjectPath(), BASE_SCREEN::m_DrawingSheetFileName );
1172  wxFFile layoutfile;
1173 
1174  if( layoutfile.Open( layoutfn.GetFullPath(), "wb" ) )
1175  {
1176  layoutfile.Write( DS_DATA_MODEL::EmptyLayout() );
1177  layoutfile.Close();
1178  }
1179 
1180  newfilename.SetPath( Prj().GetProjectPath() );
1181  newfilename.SetName( Prj().GetProjectName() );
1182  newfilename.SetExt( KiCadSchematicFileExtension );
1183 
1184  SetScreen( GetCurrentSheet().LastScreen() );
1185 
1186  Schematic().Root().SetFileName( newfilename.GetFullPath() );
1187  GetScreen()->SetFileName( newfilename.GetFullPath() );
1189 
1190  // Only fix junctions for CADSTAR importer for now as it may cause issues with
1191  // other importers
1192  if( fileType == SCH_IO_MGR::SCH_CADSTAR_ARCHIVE )
1193  {
1194  FixupJunctions();
1196  }
1197 
1198  // Only perform the dangling end test on root sheet.
1200 
1202 
1203  initScreenZoom();
1205  SyncView();
1206 
1208  UpdateTitle();
1209  }
1210  catch( const IO_ERROR& ioe )
1211  {
1212  // Do not leave g_RootSheet == NULL because it is expected to be
1213  // a valid sheet. Therefore create a dummy empty root sheet and screen.
1214  CreateScreens();
1216 
1217  wxString msg = wxString::Format( _( "Error loading schematic '%s'." ), aFileName );
1218  DisplayErrorMessage( this, msg, ioe.What() );
1219 
1220  msg.Printf( _( "Failed to load '%s'." ), aFileName );
1221  SetMsgPanel( wxEmptyString, msg );
1222 
1223  return false;
1224  }
1225 
1226  return true;
1227 
1228  default:
1229  return false;
1230  }
1231 }
1232 
1233 
1235 {
1236  SCH_SCREENS screenList( Schematic().Root() );
1237 
1238  // Save any currently open and modified project files.
1239  for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
1240  {
1241  if( screen->IsContentModified() )
1242  {
1243  if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
1244  "Save changes?" ),
1245  [&]()->bool { return SaveProject(); } ) )
1246  {
1247  return false;
1248  }
1249  }
1250  }
1251 
1252  return true;
1253 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:271
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:216
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: infobar.cpp:142
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:231
const wxString & GetFileName() const
Definition: sch_screen.h:145
Handle the graphic items list to draw/plot the frame and title block.
Definition: ds_data_model.h:38
SCH_SCREEN * GetNext()
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Open a project or set of files given by aFileList.
bool IsContentModified() const
Definition: base_screen.h:60
void SetVirtualPageNumber(int aPageNumber)
Definition: base_screen.h:76
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:284
SETTINGS_MANAGER * GetSettingsManager() const
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
void RecalculateConnections(SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
Model changes (required full reload)
Definition: tool_base.h:80
CONNECTION_GRAPH * ConnectionGraph() const override
Definition: schematic.h:131
This file is part of the common library.
void SaveProjectAs(const wxString &aFullPath)
Sets the currently loaded project path and saves it (pointers remain valid) Note that this will not m...
void SetFileName(const wxString &aFilename)
Definition: sch_sheet.h:321
bool IsModified() const
Check the entire hierarchy for any modifications.
const std::string ProjectFileExtension
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
void SetScreen(BASE_SCREEN *aScreen) override
const std::string LegacySymbolLibFileExtension
virtual PROJECT_FILE & GetProjectFile() const
Definition: project.h:145
#define KICTL_CREATE
caller thinks requested project files may not exist.
Definition: kiway_player.h:82
static void LibNamesAndPaths(PROJECT *aProject, bool doSave, wxString *aPaths, wxArrayString *aNames=nullptr)
Save or load the names of the currently configured symbol libraries (without paths).
void Flush()
Build the HTML messages page.
bool AskToSaveChanges()
Check if any of the screens has unsaved changes and asks the user whether to save or drop them.
wxString KiCadSchematicFileWildcard()
int GetFileFormatVersionAtLoad() const
Definition: sch_screen.h:130
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
void ResolveERCExclusions()
Update markers to match recorded exclusions.
static TOOL_ACTION zoomFitScreen
Definition: actions.h:96
void TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr, std::function< void(SCH_ITEM *)> *aChangedHandler=nullptr) const
Test all of the connectable objects in the schematic for unused connection points.
Definition: sch_screen.cpp:978
void UpdateTitle()
Set the main window title bar text.
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Run the specified action.
Definition: tool_manager.h:143
void OnAppendProject(wxCommandEvent &event)
int GetLibraryCount()
void RefreshCanvas() override
CREATE_PROJECT_CHECKBOX(wxWindow *aParent)
void AssignNewUuid()
Definition: sch_screen.h:471
bool IsWritable(const wxFileName &aFileName)
Checks if aFileName can be written.
void UpdateAllScreenReferences()
Update all the symbol references for this sheet path.
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:103
A small class to help profiling.
Definition: profile.h:45
bool importFile(const wxString &aFileName, int aFileType)
Load the given filename but sets the path to the current project path.
virtual const wxString Problem() const
what was the problem?
Definition: exceptions.cpp:46
void LoadWindowState(const wxString &aFileName)
bool IsContentModified() const override
Get if the current schematic has been modified but not saved.
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
void UpdateSheetInstances(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:269
void OnImportProject(wxCommandEvent &event)
virtual void SetElem(ELEM_T aIndex, _ELEM *aElem)
Definition: project.cpp:258
bool SaveProject(bool aSaveAs=false)
Saves the currently-open schematic (including its hierarchy) and associated project.
EESCHEMA_SETTINGS * eeconfig() const
void SetShutdownBlockReason(wxWindow *aWindow, const wxString &aReason)
Sets the block reason why the window/application is preventing OS shutdown.
Definition: gtk/app.cpp:83
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
Definition: schematic.cpp:104
Handle actions specific to the schematic editor.
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:169
wxString GetMruPath() const
wxString CadstarSchematicArchiveFileWildcard()
bool HasMessage() const override
Returns true if the reporter client is non-empty.
void Dismiss() override
Dismisses the infobar and updates the containing layout and AUI manager (if one is provided).
Definition: infobar.cpp:175
static DS_DATA_MODEL & GetTheInstance()
static function: returns the instance of DS_DATA_MODEL used in the application
Base class that schematic file and library loading and saving plugins should derive from.
Definition: sch_io_mgr.h:152
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
void SaveProjectCopy(const wxString &aFullPath)
Saves a copy of the current project under the given path.
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:105
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:101
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
MESSAGE_TYPE GetMessageType() const
Definition: infobar.h:99
void HardRedraw() override
Rebuild the GAL and redraw the screen.
static wxWindow * Create(wxWindow *aParent)
void SyncView()
Mark all items for refresh.
bool TriggerBackupIfNeeded(REPORTER &aReporter) const
Calls BackupProject if a new backup is needed according to the current backup policy.
static const wxString GetFileExtension(SCH_FILE_T aFileType)
Return the schematic file extension for aFileType.
Definition: sch_io_mgr.cpp:121
WX_HTML_REPORT_BOX * m_Reporter
int ShowQuasiModal()
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
bool saveSchematicFile(SCH_SHEET *aSheet, const wxString &aSavePath)
Save aSheet to a schematic file.
bool IsRootSheet() const
Definition: sch_sheet.cpp:188
void initScreenZoom()
Initialize the zoom value of the current screen and mark the screen as zoom-initialized.
static void ResolvePossibleSymlinks(wxFileName &aFilename)
Definition: wx_filename.cpp:85
SCHEMATIC & Schematic() const
Class DIALOG_HTML_REPORTER.
void UpdateHierarchyNavigator(bool aForceUpdate=false)
Run the Hierarchy Navigator dialog.
void BuildClientSheetPathList()
built the list of sheet paths sharing a screen for each screen in use
Definition of file extensions used in Kicad.
bool AppendSchematic()
Import a KiCad schematic into the current sheet.
static wxString EmptyLayout()
Return a string containing the empty layout shape.
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition for symbol library class.
#define _(s)
wxLogTrace helper definitions.
size_t GetCount() const
Definition: sch_screen.h:563
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
virtual const wxString GetProjectFullName() const
Return 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:315
FormatType fileType(const char *aFileName)
Definition: loadmodel.cpp:275
const std::string LegacyProjectFileExtension
void SetProject(PROJECT *aPrj)
Definition: schematic.cpp:76
void UpdateSymbolInstances(const std::vector< SYMBOL_INSTANCE_REFERENCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void RemoveAllButtons()
Remove all the buttons that have been added by the user.
Definition: infobar.cpp:286
bool LoadProjectSettings()
Load the KiCad project file (*.pro) settings specific to Eeschema.
A collection of SYMBOL_LIB objects.
A wrapper for reporting to a wxString object.
Definition: reporter.h:163
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:54
bool doAutoSave() override
Save the schematic files that have been modified and not yet saved.
PROJECT & Prj() const override
Return a reference to the project this schematic is part of.
Definition: schematic.h:75
const KIID m_Uuid
Definition: eda_item.h:475
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void SetContentModified(bool aModified=true)
Definition: base_screen.h:59
static wxString GetAutoSaveFilePrefix()
const KIID & GetUuid() const
Definition: sch_screen.h:469
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:479
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Loads a project or sets up a new project with a specified path.
< Helper widget to select whether a new project should be created for a file when saving
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:139
void Reset()
Initialize this schematic to a blank one, unloading anything existing.
Definition: schematic.cpp:51
SCH_SHEET_LIST GetSheets() const override
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:87
std::vector< FILE_INFO_PAIR > & GetSheets()
Definition: project_file.h:84
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
SCH_SHEET & Root() const
Definition: schematic.h:92
virtual void SetReadOnly(bool aReadOnly=true)
Definition: project.h:126
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:158
see class PGM_BASE
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
wxString EagleSchematicFileWildcard()
WX_INFOBAR * m_infoBar
static wxString m_DrawingSheetFileName
the name of the drawing sheet file, or empty to use the default drawing sheet
Definition: base_screen.h:85
void RecomputeIntersheetRefs()
Update the schematic's page reference map for all global labels, and refresh the labels so that they ...
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Saves, unloads and unregisters the given PROJECT.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
bool SaveProject(const wxString &aFullPath=wxEmptyString)
Saves a loaded project.
SCH_SHEET * GetSheet(unsigned int aIndex) const
const std::string KiCadSchematicFileExtension
wxString GetCurrentFileName() const override
Get the full filename + path of the currently opened file in the frame.
OUTDATED_SAVE Messages that should be cleared on save.
SCH_SHEET_PATH & GetCurrentSheet() const
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
std::vector< SCH_SHEET_PATH > & GetClientSheetPaths()
Return the number of times this screen is used.
Definition: sch_screen.h:171
SCH_SCREEN * GetFirst()
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition: profile.h:102
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:825
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:174
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:108
static REPORTER & GetInstance()
Definition: reporter.cpp:117
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
Definition: schematic.cpp:117
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
bool OverrideLock(wxWindow *aParent, const wxString &aMessage)
Display a dialog indicating the file is already open, with an option to reset the lock.
Definition: confirm.cpp:154
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL 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:299
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:315
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
wxString AltiumSchematicFileWildcard()
void SetInitialPageNumbers()
Set initial sheet page numbers.
bool IsSingle() const
Is this KIFACE running under single_top?
Definition: kiface_base.h:104
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition: sch_screen.h:557
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
bool RegisterApplicationRestart(const wxString &aCommandLine)
Registers the application for restart with the OS with the given command line string to pass as args.
Definition: gtk/app.cpp:58
void AddCloseButton(const wxString &aTooltip=_("Hide this message."))
Add the default close button to the infobar on the right side.
Definition: infobar.cpp:276