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