KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
6 * Copyright (C) 2013-2023 CERN (www.cern.ch)
7 * Copyright The 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 <common.h>
30#include <connection_graph.h>
32#include <dialog_symbol_remap.h>
34#include <eeschema_settings.h>
35#include <id.h>
36#include <kiface_base.h>
37#include <kiplatform/app.h>
38#include <lockfile.h>
39#include <pgm_base.h>
40#include <core/profile.h>
42#include <project_rescue.h>
43#include <project_sch.h>
46#include <reporter.h>
47#include <richio.h>
48#include <sch_bus_entry.h>
49#include <sch_commit.h>
50#include <sch_edit_frame.h>
52#include <sch_file_versions.h>
53#include <sch_line.h>
54#include <sch_sheet.h>
55#include <sch_sheet_path.h>
56#include <schematic.h>
58#include <sim/simulator_frame.h>
59#include <tool/actions.h>
60#include <tool/tool_manager.h>
63#include <trace_helpers.h>
65#include <widgets/wx_infobar.h>
68#include <wx/app.h>
69#include <wx/ffile.h>
70#include <wx/filedlg.h>
71#include <wx/log.h>
72#include <wx/richmsgdlg.h>
73#include <wx/stdpaths.h>
76#include <paths.h>
77#include <wx_filename.h> // For ::ResolvePossibleSymlinks
80
81#include <kiplatform/io.h>
82
84#include "save_project_utils.h"
85
86bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
87{
88 // ensure the splash screen does not obscure any dialog at startup
89 Pgm().HideSplash();
90
91 // implement the pseudo code from KIWAY_PLAYER.h:
92 wxString msg;
93
94 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
95
96 // This is for python:
97 if( aFileSet.size() != 1 )
98 {
99 msg.Printf( "Eeschema:%s() takes only a single filename.", __WXFUNCTION__ );
100 DisplayError( this, msg );
101 return false;
102 }
103
104 wxString fullFileName( aFileSet[0] );
105 wxFileName wx_filename( fullFileName );
106
107 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
108 wxASSERT_MSG( wx_filename.IsAbsolute(), wxS( "Path is not absolute!" ) );
109
110 if( !LockFile( fullFileName ) )
111 {
112 msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), fullFileName,
113 m_file_checker->GetUsername(), m_file_checker->GetHostname() );
114
115 if( !AskOverrideLock( this, msg ) )
116 return false;
117
118 m_file_checker->OverrideLock();
119 }
120
121 if( !AskToSaveChanges() )
122 return false;
123
124#ifdef PROFILE
125 PROF_TIMER openFiles( "OpenProjectFile" );
126#endif
127
128 wxFileName pro = fullFileName;
129 pro.SetExt( FILEEXT::ProjectFileExtension );
130
131 bool is_new = !wxFileName::IsFileReadable( fullFileName );
132
133 // If its a non-existent schematic and caller thinks it exists
134 if( is_new && !( aCtl & KICTL_CREATE ) )
135 {
136 // notify user that fullFileName does not exist, ask if user wants to create it.
137 msg.Printf( _( "Schematic '%s' does not exist. Do you wish to create it?" ),
138 fullFileName );
139
140 if( !IsOK( this, msg ) )
141 return false;
142 }
143
144 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGING );
145 ProcessEventLocally( e );
146
147 // unload current project file before loading new
148 {
151 SetScreen( nullptr );
153 }
154
155 SetStatusText( wxEmptyString );
156 m_infoBar->Dismiss();
157
158 WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Create Schematic" )
159 : _( "Load Schematic" ), 1,
160 PR_CAN_ABORT );
161
162 bool differentProject = pro.GetFullPath() != Prj().GetProjectFullName();
163
164 // This is for handling standalone mode schematic changes
165 if( differentProject )
166 {
167 if( !Prj().IsNullProject() )
168 {
171 }
172
173 // disconnect existing project from schematic before we unload the project
174 Schematic().SetProject( nullptr );
175 GetSettingsManager()->UnloadProject( &Prj(), false );
176
177 GetSettingsManager()->LoadProject( pro.GetFullPath() );
178
179 wxFileName legacyPro( pro );
180 legacyPro.SetExt( FILEEXT::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
188 // Start a new schematic object now that we sorted out our project
189 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
190
191 SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( fullFileName,
193
194 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
195 {
196 // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
197 // They are already saved in the kiface project object.
198 if( differentProject || !Prj().GetElem( PROJECT::ELEM::SCH_SYMBOL_LIBS ) )
199 {
200 // load the libraries here, not in SCH_SCREEN::Draw() which is a context
201 // that will not tolerate DisplayError() dialog since we're already in an
202 // event handler in there.
203 // And when a schematic file is loaded, we need these libs to initialize
204 // some parameters (links to PART LIB, dangling ends ...)
207 }
208 }
209 else
210 {
211 // No legacy symbol libraries including the cache are loaded with the new file format.
213 }
214
215 // Load the symbol library table, this will be used forever more.
218
219 wxFileName rfn( GetCurrentFileName() );
220 rfn.MakeRelativeTo( Prj().GetProjectPath() );
221 LoadWindowState( rfn.GetFullPath() );
222
223 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Schematic file changes are unsaved" ) );
224
225 if( Kiface().IsSingle() )
226 {
228 }
229
230 if( is_new || schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
231 {
232 newSchematic->CreateDefaultScreens();
233 SetSchematic( newSchematic.release() );
234
235 // mark new, unsaved file as modified.
237 GetScreen()->SetFileName( fullFileName );
238
239 if( schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
240 {
241 msg.Printf( _( "'%s' is not a KiCad schematic file.\nUse File -> Import for "
242 "non-KiCad schematic files." ),
243 fullFileName );
244
245 progressReporter.Hide();
246 DisplayErrorMessage( this, msg );
247 }
248 }
249 else
250 {
251 wxFileName autoSaveFn = fullFileName;
252
253 autoSaveFn.SetName( getAutoSaveFileName() );
254 autoSaveFn.ClearExt();
255
256 if( ( aCtl & KICTL_REVERT ) )
257 {
258 DeleteAutoSaveFile( autoSaveFn );
259 }
260 else
261 {
262 // This will rename the file if there is an autosave and the user wants to recover
263 CheckForAutoSaveFile( autoSaveFn );
264 }
265
266 SetScreen( nullptr );
267
268 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( schFileType ) );
269
270 pi->SetProgressReporter( &progressReporter );
271
272 bool failedLoad = false;
273
274 try
275 {
276 {
277 wxBusyCursor busy;
278 WINDOW_DISABLER raii( this );
279
280 newSchematic->SetRoot( pi->LoadSchematicFile( fullFileName, newSchematic.get() ) );
281
282 // Make ${SHEETNAME} work on the root sheet until we properly support
283 // naming the root sheet
284 newSchematic->Root().SetName( _( "Root" ) );
285 wxLogTrace( tracePathsAndFiles, wxS( "Loaded schematic with root sheet UUID %s" ),
286 newSchematic->Root().m_Uuid.AsString() );
287 }
288
289 if( !pi->GetError().IsEmpty() )
290 {
291 DisplayErrorMessage( this, _( "The entire schematic could not be loaded. Errors "
292 "occurred attempting to load hierarchical sheets." ),
293 pi->GetError() );
294 }
295 }
296 catch( const FUTURE_FORMAT_ERROR& ffe )
297 {
298 newSchematic->CreateDefaultScreens();
299 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
300 progressReporter.Hide();
301 DisplayErrorMessage( this, msg, ffe.Problem() );
302
303 failedLoad = true;
304 }
305 catch( const IO_ERROR& ioe )
306 {
307 newSchematic->CreateDefaultScreens();
308 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
309 progressReporter.Hide();
310 DisplayErrorMessage( this, msg, ioe.What() );
311
312 failedLoad = true;
313 }
314 catch( const std::bad_alloc& )
315 {
316 newSchematic->CreateDefaultScreens();
317 msg.Printf( _( "Memory exhausted loading schematic '%s'." ), fullFileName );
318 progressReporter.Hide();
319 DisplayErrorMessage( this, msg, wxEmptyString );
320
321 failedLoad = true;
322 }
323
324 SetSchematic( newSchematic.release() );
325
326 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
327 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
328 // compiled.
329 Raise();
330
331 if( failedLoad )
332 {
333 // Do not leave g_RootSheet == NULL because it is expected to be
334 // a valid sheet. Therefore create a dummy empty root sheet and screen.
337
338 msg.Printf( _( "Failed to load '%s'." ), fullFileName );
339 SetMsgPanel( wxEmptyString, msg );
340
341 return false;
342 }
343
344 // Load project settings after schematic has been set up with the project link, since this will
345 // update some of the needed schematic settings such as drawing defaults
347
348 // It's possible the schematic parser fixed errors due to bugs so warn the user
349 // that the schematic has been fixed (modified).
350 SCH_SHEET_LIST sheetList = Schematic().Hierarchy();
351
352 if( sheetList.IsModified() )
353 {
354 DisplayInfoMessage( this,
355 _( "An error was found when loading the schematic that has "
356 "been automatically fixed. Please save the schematic to "
357 "repair the broken file or it may not be usable with other "
358 "versions of KiCad." ) );
359 }
360
361 if( sheetList.AllSheetPageNumbersEmpty() )
362 sheetList.SetInitialPageNumbers();
363
364 UpdateFileHistory( fullFileName );
365
366 SCH_SCREENS schematic( Schematic().Root() );
367
368 // LIB_ID checks and symbol rescue only apply to the legacy file formats.
369 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
370 {
371 // Convert any legacy bus-bus entries to just be bus wires
372 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
373 {
374 std::vector<SCH_ITEM*> deleted;
375
376 for( SCH_ITEM* item : screen->Items() )
377 {
378 if( item->Type() == SCH_BUS_BUS_ENTRY_T )
379 {
380 SCH_BUS_BUS_ENTRY* entry = static_cast<SCH_BUS_BUS_ENTRY*>( item );
381 std::unique_ptr<SCH_LINE> wire = std::make_unique<SCH_LINE>();
382
383 wire->SetLayer( LAYER_BUS );
384 wire->SetStartPoint( entry->GetPosition() );
385 wire->SetEndPoint( entry->GetEnd() );
386
387 screen->Append( wire.release() );
388 deleted.push_back( item );
389 }
390 }
391
392 for( SCH_ITEM* item : deleted )
393 screen->Remove( item );
394 }
395
396
397 // Convert old projects over to use symbol library table.
398 if( schematic.HasNoFullyDefinedLibIds() )
399 {
400 DIALOG_SYMBOL_REMAP dlgRemap( this );
401
402 dlgRemap.ShowQuasiModal();
403 }
404 else
405 {
406 // Double check to ensure no legacy library list entries have been
407 // added to the project file symbol library list.
408 wxString paths;
409 wxArrayString libNames;
410
411 SYMBOL_LIBS::GetLibNamesAndPaths( &Prj(), &paths, &libNames );
412
413 if( !libNames.IsEmpty() )
414 {
415 if( eeconfig()->m_Appearance.show_illegal_symbol_lib_dialog )
416 {
417 wxRichMessageDialog invalidLibDlg(
418 this,
419 _( "Illegal entry found in project file symbol library list." ),
420 _( "Project Load Warning" ),
421 wxOK | wxCENTER | wxICON_EXCLAMATION );
422 invalidLibDlg.ShowDetailedText(
423 _( "Symbol libraries defined in the project file symbol library "
424 "list are no longer supported and will be removed.\n\n"
425 "This may cause broken symbol library links under certain "
426 "conditions." ) );
427 invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
428 invalidLibDlg.ShowModal();
430 !invalidLibDlg.IsCheckBoxChecked();
431 }
432
433 libNames.Clear();
434 paths.Clear();
435 SYMBOL_LIBS::SetLibNamesAndPaths( &Prj(), paths, libNames );
436 }
437
438 if( !cfg || !cfg->m_RescueNeverShow )
439 {
441 editor->RescueSymbolLibTableProject( false );
442 }
443 }
444
445 // Ensure there is only one legacy library loaded and that it is the cache library.
446 SYMBOL_LIBS* legacyLibs = PROJECT_SCH::SchLibs( &Schematic().Project() );
447
448 if( legacyLibs->GetLibraryCount() == 0 )
449 {
450 wxString extMsg;
451 wxFileName cacheFn = pro;
452
453 cacheFn.SetName( cacheFn.GetName() + "-cache" );
455
456 msg.Printf( _( "The project symbol library cache file '%s' was not found." ),
457 cacheFn.GetFullName() );
458 extMsg = _( "This can result in a broken schematic under certain conditions. "
459 "If the schematic does not have any missing symbols upon opening, "
460 "save it immediately before making any changes to prevent data "
461 "loss. If there are missing symbols, either manual recovery of "
462 "the schematic or recovery of the symbol cache library file and "
463 "reloading the schematic is required." );
464
465 wxMessageDialog dlgMissingCache( this, msg, _( "Warning" ),
466 wxOK | wxCANCEL | wxICON_EXCLAMATION | wxCENTER );
467 dlgMissingCache.SetExtendedMessage( extMsg );
468 dlgMissingCache.SetOKCancelLabels(
469 wxMessageDialog::ButtonLabel( _( "Load Without Cache File" ) ),
470 wxMessageDialog::ButtonLabel( _( "Abort" ) ) );
471
472 if( dlgMissingCache.ShowModal() == wxID_CANCEL )
473 {
474 Schematic().Reset();
476 return false;
477 }
478 }
479
480 // Update all symbol library links for all sheets.
481 schematic.UpdateSymbolLinks();
482
483 m_infoBar->RemoveAllButtons();
484 m_infoBar->AddCloseButton();
485 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
486 "It will be converted to the new format when saved." ),
488
489 // Legacy schematic can have duplicate time stamps so fix that before converting
490 // to the s-expression format.
491 schematic.ReplaceDuplicateTimeStamps();
492
493 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
494 screen->FixLegacyPowerSymbolMismatches();
495
496 // Allow the schematic to be saved to new file format without making any edits.
497 OnModify();
498 }
499 else // S-expression schematic.
500 {
502 {
503 m_infoBar->RemoveAllButtons();
504 m_infoBar->AddCloseButton();
505 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
506 "It will be converted to the new format when saved." ),
508 }
509
510 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
511 screen->UpdateLocalLibSymbolLinks();
512
513 // Restore all of the loaded symbol and sheet instances from the root sheet.
514 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221002 )
515 sheetList.UpdateSymbolInstanceData( Schematic().RootScreen()->GetSymbolInstances() );
516
517 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221110 )
518 sheetList.UpdateSheetInstanceData( Schematic().RootScreen()->GetSheetInstances());
519
520 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
521 for( SCH_SCREEN* screen = schematic.GetFirst(); screen;
522 screen = schematic.GetNext() )
523 screen->FixLegacyPowerSymbolMismatches();
524
525 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
526 screen->MigrateSimModels();
527 }
528
529 // After the schematic is successfully loaded, we load the drawing sheet.
530 // This allows us to use the drawing sheet embedded in the schematic (if any)
531 // instead of the default one.
533
534 schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), sheetList );
535 schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), sheetList );
536 sheetList.CheckForMissingSymbolInstances( Prj().GetProjectName() );
537
539
540 SetScreen( GetCurrentSheet().LastScreen() );
541
542 // Migrate conflicting bus definitions
543 // TODO(JE) This should only run once based on schematic file version
544 if( Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() > 0 )
545 {
546 DIALOG_MIGRATE_BUSES dlg( this );
547 dlg.ShowQuasiModal();
548 OnModify();
549 }
550
551 SCH_COMMIT dummy( this );
552
553 progressReporter.Report( _( "Updating connections..." ) );
554 progressReporter.KeepRefreshing();
555
556 RecalculateConnections( &dummy, GLOBAL_CLEANUP, &progressReporter );
557
558 if( schematic.HasSymbolFieldNamesWithWhiteSpace() )
559 {
560 m_infoBar->QueueShowMessage( _( "This schematic contains symbols that have leading "
561 "and/or trailing white space field names." ),
562 wxICON_WARNING );
563 }
564 }
565
566 // Load any exclusions from the project file
568
571
574
575 // Re-create junctions if needed. Eeschema optimizes wires by merging
576 // colinear segments. If a schematic is saved without a valid
577 // cache library or missing installed libraries, this can cause connectivity errors
578 // unless junctions are added.
579 //
580 // TODO: (RFB) This really needs to be put inside the Load() function of the SCH_IO_KICAD_LEGACY
581 // I can't put it right now because of the extra code that is above to convert legacy bus-bus
582 // entries to bus wires
583 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
585
586 SyncView();
588
590
591 UpdateHierarchyNavigator( false, true );
592
593 wxCommandEvent changedEvt( EDA_EVT_SCHEMATIC_CHANGED );
594 ProcessEventLocally( changedEvt );
595
596 for( wxEvtHandler* listener : m_schematicChangeListeners )
597 {
598 wxCHECK2( listener, continue );
599
600 // Use the windows variant when handling event messages in case there is any special
601 // event handler pre and/or post processing specific to windows.
602 wxWindow* win = dynamic_cast<wxWindow*>( listener );
603
604 if( win )
605 win->HandleWindowEvent( e );
606 else
607 listener->SafelyProcessEvent( e );
608 }
609
610 updateTitle();
611 m_toolManager->GetTool<SCH_NAVIGATE_TOOL>()->ResetHistory();
612
613 wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
614
615 if( fn.FileExists() && !fn.IsFileWritable() )
616 {
617 m_infoBar->RemoveAllButtons();
618 m_infoBar->AddCloseButton();
619 m_infoBar->ShowMessage( _( "Schematic is read only." ),
621 }
622
623#ifdef PROFILE
624 openFiles.Show();
625#endif
626 // Ensure all items are redrawn (especially the drawing-sheet items):
627 if( GetCanvas() )
628 GetCanvas()->DisplaySheet( GetCurrentSheet().LastScreen() );
629
630 return true;
631}
632
633
634void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
635{
636 if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
637 {
638 wxString msg = _( "This operation replaces the contents of the current schematic, "
639 "which will be permanently lost.\n\n"
640 "Do you want to proceed?" );
641
642 if( !IsOK( this, msg ) )
643 return;
644 }
645
646 // Set the project location if none is set or if we are running in standalone mode
647 bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
648 wxString path = wxPathOnly( Prj().GetProjectFullName() );
649
650 wxString fileFiltersStr;
651 wxString allWildcardsStr;
652
653 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
654 {
655 if( fileType == SCH_IO_MGR::SCH_KICAD || fileType == SCH_IO_MGR::SCH_LEGACY )
656 continue; // this is "Import non-KiCad schematic"
657
658 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
659
660 if( !pi )
661 continue;
662
663 const IO_BASE::IO_FILE_DESC& desc = pi->GetSchematicFileDesc();
664
665 if( desc.m_FileExtensions.empty() || !desc.m_CanRead )
666 continue;
667
668 if( !fileFiltersStr.IsEmpty() )
669 fileFiltersStr += wxChar( '|' );
670
671 fileFiltersStr += desc.FileFilter();
672
673 for( const std::string& ext : desc.m_FileExtensions )
674 allWildcardsStr << wxS( "*." ) << formatWildcardExt( ext ) << wxS( ";" );
675 }
676
677 fileFiltersStr = _( "All supported formats" ) + wxS( "|" ) + allWildcardsStr + wxS( "|" )
678 + fileFiltersStr;
679
680 wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFiltersStr,
681 wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
682
683 FILEDLG_IMPORT_NON_KICAD importOptions( eeconfig()->m_System.show_import_issues );
684 dlg.SetCustomizeHook( importOptions );
685
686 if( dlg.ShowModal() == wxID_CANCEL )
687 return;
688
690
691 // Don't leave dangling pointers to previously-opened document.
692 m_toolManager->GetTool<SCH_SELECTION_TOOL>()->ClearSelection();
695
696 if( setProject )
697 {
698 Schematic().SetProject( nullptr );
699 GetSettingsManager()->UnloadProject( &Prj(), false );
700
701 // Clear view before destroying schematic as repaints depend on schematic being valid
702 SetScreen( nullptr );
703
704 Schematic().Reset();
705
706 wxFileName projectFn( dlg.GetPath() );
707 projectFn.SetExt( FILEEXT::ProjectFileExtension );
708 GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
709 }
710
711 wxFileName fn = dlg.GetPath();
712
713 if( !fn.IsFileReadable() )
714 {
715 wxLogError( _( "Insufficient permissions to read file '%s'." ), fn.GetFullPath() );
716 return;
717 }
718
719 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN;
720
721 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
722 {
723 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
724
725 if( !pi )
726 continue;
727
728 if( pi->CanReadSchematicFile( fn.GetFullPath() ) )
729 {
730 pluginType = fileType;
731 break;
732 }
733 }
734
735 if( pluginType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
736 {
737 wxLogError( _( "No loader can read the specified file: '%s'." ), fn.GetFullPath() );
739 SetScreen( Schematic().RootScreen() );
740 return;
741 }
742
743 importFile( dlg.GetPath(), pluginType );
744
746}
747
748
749bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSavePath )
750{
751 wxString msg;
752 wxFileName schematicFileName;
753 wxFileName oldFileName;
754 bool success;
755
756 SCH_SCREEN* screen = aSheet->GetScreen();
757
758 wxCHECK( screen, false );
759
760 // Cannot save to nowhere
761 if( aSavePath.IsEmpty() )
762 return false;
763
764 // Construct the name of the file to be saved
765 schematicFileName = Prj().AbsolutePath( aSavePath );
766 oldFileName = schematicFileName;
767
768 // Write through symlinks, don't replace them
769 WX_FILENAME::ResolvePossibleSymlinks( schematicFileName );
770
771 if( !schematicFileName.DirExists() )
772 {
773 if( !wxMkdir( schematicFileName.GetPath() ) )
774 {
775 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
776 schematicFileName.GetFullPath(),
777 "Could not create directory: %s" + schematicFileName.GetPath() );
778 DisplayError( this, msg );
779
780 return false;
781 }
782 }
783
784 if( !IsWritable( schematicFileName ) )
785 return false;
786
787 wxFileName projectFile( schematicFileName );
788
789 projectFile.SetExt( FILEEXT::ProjectFileExtension );
790
791 if( projectFile.FileExists() )
792 {
793 // Save various ERC settings, such as violation severities (which may have been edited
794 // via the ERC dialog as well as the Schematic Setup dialog), ERC exclusions, etc.
796 }
797
798 // Save
799 wxLogTrace( traceAutoSave, wxS( "Saving file " ) + schematicFileName.GetFullPath() );
800
801 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
802 m_infoBar->Dismiss();
803
804 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
805 schematicFileName.GetFullPath() );
806
807 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
808 pluginType = SCH_IO_MGR::SCH_KICAD;
809
810 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
811
812 try
813 {
814 pi->SaveSchematicFile( schematicFileName.GetFullPath(), aSheet, &Schematic() );
815 success = true;
816 }
817 catch( const IO_ERROR& ioe )
818 {
819 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
820 schematicFileName.GetFullPath(),
821 ioe.What() );
822 DisplayError( this, msg );
823
824 success = false;
825 }
826
827 if( success )
828 {
829 // Delete auto save file.
830 wxFileName autoSaveFileName = schematicFileName;
831 autoSaveFileName.SetName( FILEEXT::AutoSaveFilePrefix + schematicFileName.GetName() );
832
833 if( autoSaveFileName.FileExists() )
834 {
835 wxLogTrace( traceAutoSave,
836 wxS( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() +
837 wxS( ">" ) );
838
839 wxRemoveFile( autoSaveFileName.GetFullPath() );
840 }
841
842 screen->SetContentModified( false );
843
844 msg.Printf( _( "File '%s' saved." ), screen->GetFileName() );
845 SetStatusText( msg, 0 );
846 }
847
848 return success;
849}
850
851
852bool PrepareSaveAsFiles( SCHEMATIC& aSchematic, SCH_SCREENS& aScreens,
853 const wxFileName& aOldRoot, const wxFileName& aNewRoot,
854 bool aSaveCopy, bool aCopySubsheets, bool aIncludeExternSheets,
855 std::unordered_map<SCH_SCREEN*, wxString>& aFilenameMap,
856 wxString& aErrorMsg )
857{
858 SCH_SCREEN* screen;
859
860 for( size_t i = 0; i < aScreens.GetCount(); i++ )
861 {
862 screen = aScreens.GetScreen( i );
863
864 wxCHECK2( screen, continue );
865
866 if( screen == aSchematic.RootScreen() )
867 continue;
868
869 wxFileName src = screen->GetFileName();
870
871 if( !src.IsAbsolute() )
872 src.MakeAbsolute( aOldRoot.GetPath() );
873
874 bool internalSheet = src.GetPath().StartsWith( aOldRoot.GetPath() );
875
876 if( aCopySubsheets && ( internalSheet || aIncludeExternSheets ) )
877 {
878 wxFileName dest = src;
879
880 if( internalSheet && dest.MakeRelativeTo( aOldRoot.GetPath() ) )
881 dest.MakeAbsolute( aNewRoot.GetPath() );
882 else
883 dest.Assign( aNewRoot.GetPath(), dest.GetFullName() );
884
885 wxLogTrace( tracePathsAndFiles,
886 wxS( "Moving schematic from '%s' to '%s'." ),
887 screen->GetFileName(),
888 dest.GetFullPath() );
889
890 if( !dest.DirExists() && !dest.Mkdir() )
891 {
892 aErrorMsg.Printf( _( "Folder '%s' could not be created.\n\n"
893 "Make sure you have write permissions and try again." ),
894 dest.GetPath() );
895 return false;
896 }
897
898 if( aSaveCopy )
899 aFilenameMap[screen] = dest.GetFullPath();
900 else
901 screen->SetFileName( dest.GetFullPath() );
902 }
903 else
904 {
905 if( aSaveCopy )
906 aFilenameMap[screen] = wxString();
907
908 screen->SetFileName( src.GetFullPath() );
909 }
910 }
911
912 for( SCH_SHEET_PATH& sheet : aSchematic.Hierarchy() )
913 {
914 if( !sheet.Last()->IsRootSheet() )
915 sheet.MakeFilePathRelativeToParentSheet();
916 }
917
918 return true;
919}
920
921bool SCH_EDIT_FRAME::SaveProject( bool aSaveAs )
922{
923 wxString msg;
924 SCH_SCREEN* screen;
925 SCH_SCREENS screens( Schematic().Root() );
926 bool saveCopy = aSaveAs && !Kiface().IsSingle();
927 bool success = true;
928 bool updateFileHistory = false;
929 bool createNewProject = false;
930 bool copySubsheets = false;
931 bool includeExternSheets = false;
932
933 // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
934 wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
935 wxFileName fn = fileName;
936
937 // Path to save each screen to: will be the stored filename by default, but is overwritten by
938 // a Save As Copy operation.
939 std::unordered_map<SCH_SCREEN*, wxString> filenameMap;
940
941 // Handle "Save As" and saving a new project/schematic for the first time in standalone
942 if( Prj().IsNullProject() || aSaveAs )
943 {
944 // Null project should only be possible in standalone mode.
945 wxCHECK( Kiface().IsSingle() || aSaveAs, false );
946
947 wxFileName newFileName;
948 wxFileName savePath( Prj().GetProjectFullName() );
949
950 if( !savePath.IsOk() || !savePath.IsDirWritable() )
951 {
952 savePath = GetMruPath();
953
954 if( !savePath.IsOk() || !savePath.IsDirWritable() )
956 }
957
958 if( savePath.HasExt() )
959 savePath.SetExt( FILEEXT::KiCadSchematicFileExtension );
960 else
961 savePath.SetName( wxEmptyString );
962
963 wxFileDialog dlg( this, _( "Schematic Files" ), savePath.GetPath(), savePath.GetFullName(),
965 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
966
967 FILEDLG_HOOK_SAVE_PROJECT newProjectHook;
968
969 // Add a "Create a project" checkbox in standalone mode and one isn't loaded
970 if( Kiface().IsSingle() || aSaveAs )
971 {
972 dlg.SetCustomizeHook( newProjectHook );
973 }
974
975 if( dlg.ShowModal() == wxID_CANCEL )
976 return false;
977
978 newFileName = EnsureFileExtension( dlg.GetPath(), FILEEXT::KiCadSchematicFileExtension );
979
980 if( ( !newFileName.DirExists() && !newFileName.Mkdir() ) ||
981 !newFileName.IsDirWritable() )
982 {
983 msg.Printf( _( "Folder '%s' could not be created.\n\n"
984 "Make sure you have write permissions and try again." ),
985 newFileName.GetPath() );
986
987 wxMessageDialog dlgBadPath( this, msg, _( "Error" ),
988 wxOK | wxICON_EXCLAMATION | wxCENTER );
989
990 dlgBadPath.ShowModal();
991 return false;
992 }
993
994 if( newProjectHook.IsAttachedToDialog() )
995 {
996 createNewProject = newProjectHook.GetCreateNewProject();
997 copySubsheets = newProjectHook.GetCopySubsheets();
998 includeExternSheets = newProjectHook.GetIncludeExternSheets();
999 }
1000
1001 if( !saveCopy )
1002 {
1003 Schematic().Root().SetFileName( newFileName.GetFullName() );
1004 Schematic().RootScreen()->SetFileName( newFileName.GetFullPath() );
1005 updateFileHistory = true;
1006 }
1007 else
1008 {
1009 filenameMap[Schematic().RootScreen()] = newFileName.GetFullPath();
1010 }
1011
1012 if( !PrepareSaveAsFiles( Schematic(), screens, fn, newFileName, saveCopy,
1013 copySubsheets, includeExternSheets, filenameMap, msg ) )
1014 {
1015 wxMessageDialog dlgBadFilePath( this, msg, _( "Error" ),
1016 wxOK | wxICON_EXCLAMATION | wxCENTER );
1017
1018 dlgBadFilePath.ShowModal();
1019 return false;
1020 }
1021 }
1022 else if( !fn.FileExists() )
1023 {
1024 // File doesn't exist yet; true if we just imported something
1025 updateFileHistory = true;
1026 }
1027 else if( screens.GetFirst() && screens.GetFirst()->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
1028 {
1029 // Allow the user to save un-edited files in new format
1030 }
1031 else if( !IsContentModified() )
1032 {
1033 return true;
1034 }
1035
1036 if( filenameMap.empty() || !saveCopy )
1037 {
1038 for( size_t i = 0; i < screens.GetCount(); i++ )
1039 filenameMap[screens.GetScreen( i )] = screens.GetScreen( i )->GetFileName();
1040 }
1041
1042 // Warn user on potential file overwrite. This can happen on shared sheets.
1043 wxArrayString overwrittenFiles;
1044 wxArrayString lockedFiles;
1045
1046 for( size_t i = 0; i < screens.GetCount(); i++ )
1047 {
1048 screen = screens.GetScreen( i );
1049
1050 wxCHECK2( screen, continue );
1051
1052 // Convert legacy schematics file name extensions for the new format.
1053 wxFileName tmpFn = filenameMap[screen];
1054
1055 if( !tmpFn.IsOk() )
1056 continue;
1057
1058 if( tmpFn.FileExists() && !tmpFn.IsFileWritable() )
1059 lockedFiles.Add( tmpFn.GetFullPath() );
1060
1061 if( tmpFn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1062 continue;
1063
1065
1066 if( tmpFn.FileExists() )
1067 overwrittenFiles.Add( tmpFn.GetFullPath() );
1068 }
1069
1070 if( !lockedFiles.IsEmpty() )
1071 {
1072 for( const wxString& lockedFile : lockedFiles )
1073 {
1074 if( msg.IsEmpty() )
1075 msg = lockedFile;
1076 else
1077 msg += "\n" + lockedFile;
1078 }
1079
1080 wxRichMessageDialog dlg( this, wxString::Format( _( "Failed to save %s." ),
1081 Schematic().Root().GetFileName() ),
1082 _( "Locked File Warning" ),
1083 wxOK | wxICON_WARNING | wxCENTER );
1084 dlg.SetExtendedMessage( _( "You do not have write permissions to:\n\n" ) + msg );
1085
1086 dlg.ShowModal();
1087 return false;
1088 }
1089
1090 if( !overwrittenFiles.IsEmpty() )
1091 {
1092 for( const wxString& overwrittenFile : overwrittenFiles )
1093 {
1094 if( msg.IsEmpty() )
1095 msg = overwrittenFile;
1096 else
1097 msg += "\n" + overwrittenFile;
1098 }
1099
1100 wxRichMessageDialog dlg( this, _( "Saving will overwrite existing files." ),
1101 _( "Save Warning" ),
1102 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER |
1103 wxICON_EXCLAMATION );
1104 dlg.ShowDetailedText( _( "The following files will be overwritten:\n\n" ) + msg );
1105 dlg.SetOKCancelLabels( wxMessageDialog::ButtonLabel( _( "Overwrite Files" ) ),
1106 wxMessageDialog::ButtonLabel( _( "Abort Project Save" ) ) );
1107
1108 if( dlg.ShowModal() == wxID_CANCEL )
1109 return false;
1110 }
1111
1112 screens.BuildClientSheetPathList();
1113
1114 for( size_t i = 0; i < screens.GetCount(); i++ )
1115 {
1116 screen = screens.GetScreen( i );
1117
1118 wxCHECK2( screen, continue );
1119
1120 // Convert legacy schematics file name extensions for the new format.
1121 wxFileName tmpFn = filenameMap[screen];
1122
1123 if( tmpFn.IsOk() && tmpFn.GetExt() != FILEEXT::KiCadSchematicFileExtension )
1124 {
1125 updateFileHistory = true;
1127
1128 for( EDA_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
1129 {
1130 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1131 wxFileName sheetFileName = sheet->GetFileName();
1132
1133 if( !sheetFileName.IsOk()
1134 || sheetFileName.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1135 continue;
1136
1137 sheetFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
1138 sheet->SetFileName( sheetFileName.GetFullPath() );
1139 UpdateItem( sheet );
1140 }
1141
1142 filenameMap[screen] = tmpFn.GetFullPath();
1143
1144 if( !saveCopy )
1145 screen->SetFileName( tmpFn.GetFullPath() );
1146 }
1147
1148 // Do not save sheet symbols with no valid filename set
1149 if( !tmpFn.IsOk() )
1150 continue;
1151
1152 std::vector<SCH_SHEET_PATH>& sheets = screen->GetClientSheetPaths();
1153
1154 if( sheets.size() == 1 )
1155 screen->SetVirtualPageNumber( 1 );
1156 else
1157 screen->SetVirtualPageNumber( 0 ); // multiple uses; no way to store the real sheet #
1158
1159 // This is a new schematic file so make sure it has a unique ID.
1160 if( !saveCopy && tmpFn.GetFullPath() != screen->GetFileName() )
1161 screen->AssignNewUuid();
1162
1163 success &= saveSchematicFile( screens.GetSheet( i ), tmpFn.GetFullPath() );
1164 }
1165
1166 if( success )
1167 m_autoSaveRequired = false;
1168
1169 // One or more of the modified sheets did not save correctly so update the auto save file.
1170 if( !aSaveAs && !success )
1171 success &= updateAutoSaveFile();
1172
1173 if( aSaveAs && success )
1174 LockFile( Schematic().RootScreen()->GetFileName() );
1175
1176 if( updateFileHistory )
1177 UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
1178
1179 // Save the sheet name map to the project file
1180 std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
1181 sheets.clear();
1182
1183 for( SCH_SHEET_PATH& sheetPath : Schematic().Hierarchy() )
1184 {
1185 SCH_SHEET* sheet = sheetPath.Last();
1186
1187 wxCHECK2( sheet, continue );
1188
1189 // Use the schematic UUID for the root sheet.
1190 if( sheet->IsRootSheet() )
1191 {
1192 screen = sheet->GetScreen();
1193
1194 wxCHECK2( screen, continue );
1195
1196 // For the root sheet we use the canonical name ( "Root" ) because its name
1197 // cannot be modified by the user
1198 sheets.emplace_back( std::make_pair( screen->GetUuid(), wxT( "Root" ) ) );
1199 }
1200 else
1201 {
1202 sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
1203 }
1204 }
1205
1206 wxASSERT( filenameMap.count( Schematic().RootScreen() ) );
1207 wxFileName projectPath( filenameMap.at( Schematic().RootScreen() ) );
1208 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1209
1210 if( Prj().IsNullProject() || ( aSaveAs && !saveCopy ) )
1211 {
1212 Prj().SetReadOnly( !createNewProject );
1213 GetSettingsManager()->SaveProjectAs( projectPath.GetFullPath() );
1214 }
1215 else if( saveCopy && createNewProject )
1216 {
1217 GetSettingsManager()->SaveProjectCopy( projectPath.GetFullPath() );
1218 }
1219 else
1220 {
1223 }
1224
1225 if( !Kiface().IsSingle() )
1226 {
1227 WX_STRING_REPORTER backupReporter;
1228
1229 if( !GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1230 SetStatusText( backupReporter.GetMessages(), 0 );
1231 }
1232
1233 updateTitle();
1234
1235 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1236 m_infoBar->Dismiss();
1237
1238 return success;
1239}
1240
1241
1243{
1244 if( !Schematic().IsValid() )
1245 return true;
1246
1247 wxFileName tmpFileName = Schematic().Root().GetFileName();
1248 wxFileName fn = tmpFileName;
1249 wxFileName tmp;
1250 SCH_SCREENS screens( Schematic().Root() );
1251
1252 // Don't run autosave if content has not been modified
1253 if( !IsContentModified() )
1254 return true;
1255
1256 bool autoSaveOk = true;
1257
1258 if( fn.GetPath().IsEmpty() )
1259 tmp.AssignDir( Prj().GetProjectPath() );
1260 else
1261 tmp.AssignDir( fn.GetPath() );
1262
1263 if( !tmp.IsOk() )
1264 return false;
1265
1266 if( !IsWritable( tmp, false ) )
1267 {
1269 {
1270 DisplayError( this, wxString::Format(
1271 _( "Could not autosave files to read-only folder: '%s'" ),
1272 tmp.GetPath() ) );
1274 }
1275
1276 return false;
1277 }
1278
1279 wxString title = GetTitle(); // Save frame title, that can be modified by the save process
1280
1281 for( size_t i = 0; i < screens.GetCount(); i++ )
1282 {
1283 // Only create auto save files for the schematics that have been modified.
1284 if( !screens.GetScreen( i )->IsContentModified() )
1285 continue;
1286
1287 tmpFileName = fn = screens.GetScreen( i )->GetFileName();
1288
1289 // Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
1290 fn.SetName( FILEEXT::AutoSaveFilePrefix + fn.GetName() );
1291
1292 if( !IsWritable( fn, false ) )
1293 {
1295 {
1296 DisplayError( this, wxString::Format(
1297 _( "Could not autosave files to read-only folder: '%s'" ),
1298 fn.GetPath() ) );
1300 }
1301
1302 autoSaveOk = false;
1303 continue;
1304 }
1305
1306 if( saveSchematicFile( screens.GetSheet( i ), fn.GetFullPath() ) )
1307 {
1308 // This was only an auto-save, not a real save. Reset the modified flag.
1309 screens.GetScreen( i )->SetContentModified();
1310 }
1311 else
1312 {
1313 autoSaveOk = false;
1314 }
1315 }
1316
1317 if( autoSaveOk && updateAutoSaveFile() )
1318 {
1319 m_autoSaveRequired = false;
1320 m_autoSavePending = false;
1321
1322 if( !Kiface().IsSingle()
1323 && GetSettingsManager()->GetCommonSettings()->m_Backup.backup_on_autosave )
1324 {
1326 }
1327 }
1328
1329 SetTitle( title );
1330
1331 return autoSaveOk;
1332}
1333
1334
1335bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1336 const std::map<std::string, UTF8>* aProperties )
1337{
1338 wxFileName filename( aFileName );
1339 wxFileName newfilename;
1340 SCH_IO_MGR::SCH_FILE_T fileType = (SCH_IO_MGR::SCH_FILE_T) aFileType;
1341
1342 wxCommandEvent changingEvt( EDA_EVT_SCHEMATIC_CHANGING );
1343 ProcessEventLocally( changingEvt );
1344
1345 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
1346
1347 switch( fileType )
1348 {
1349 case SCH_IO_MGR::SCH_ALTIUM:
1350 case SCH_IO_MGR::SCH_CADSTAR_ARCHIVE:
1351 case SCH_IO_MGR::SCH_EAGLE:
1352 case SCH_IO_MGR::SCH_LTSPICE:
1353 case SCH_IO_MGR::SCH_EASYEDA:
1354 case SCH_IO_MGR::SCH_EASYEDAPRO:
1355 {
1356 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
1357 // Unless we are passing the files in aproperties, in which case aFileName can be empty.
1358 wxCHECK_MSG( aFileName.IsEmpty() || filename.IsAbsolute(), false,
1359 wxS( "Import schematic: path is not absolute!" ) );
1360
1361 try
1362 {
1363 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
1364 DIALOG_HTML_REPORTER errorReporter( this );
1365 WX_PROGRESS_REPORTER progressReporter( this, _( "Import Schematic" ), 1, PR_CAN_ABORT );
1366
1367 if( PROJECT_CHOOSER_PLUGIN* c_pi = dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() ) )
1368 {
1369 c_pi->RegisterCallback( std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::RunModal,
1370 this, std::placeholders::_1 ) );
1371 }
1372
1373 if( eeconfig()->m_System.show_import_issues )
1374 pi->SetReporter( errorReporter.m_Reporter );
1375 else
1376 pi->SetReporter( &NULL_REPORTER::GetInstance() );
1377
1378 pi->SetProgressReporter( &progressReporter );
1379
1380 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( aFileName, newSchematic.get(), nullptr,
1381 aProperties );
1382
1383 SetSchematic( newSchematic.release() );
1384
1385 if( loadedSheet )
1386 {
1387 Schematic().SetRoot( loadedSheet );
1388
1389 if( errorReporter.m_Reporter->HasMessage() )
1390 {
1391 errorReporter.m_Reporter->Flush(); // Build HTML messages
1392 errorReporter.ShowModal();
1393 }
1394
1395 // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works
1396 // differently to KiCad), so set it to an empty one.
1398 drawingSheet.SetEmptyLayout();
1399 BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
1400
1401 newfilename.SetPath( Prj().GetProjectPath() );
1402 newfilename.SetName( Prj().GetProjectName() );
1403 newfilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
1404
1405 SetScreen( GetCurrentSheet().LastScreen() );
1406
1407 Schematic().Root().SetFileName( newfilename.GetFullName() );
1408 GetScreen()->SetFileName( newfilename.GetFullPath() );
1410
1411 progressReporter.Report( _( "Updating connections..." ) );
1412
1413 if( !progressReporter.KeepRefreshing() )
1414 THROW_IO_ERROR( _( "File import canceled by user." ) );
1415
1416 RecalculateConnections( nullptr, GLOBAL_CLEANUP, &progressReporter );
1417
1418 // Only perform the dangling end test on root sheet.
1420 }
1421 else
1422 {
1424 }
1425 }
1426 catch( const IO_ERROR& ioe )
1427 {
1428 // Do not leave g_RootSheet == NULL because it is expected to be
1429 // a valid sheet. Therefore create a dummy empty root sheet and screen.
1432
1433 wxString msg = wxString::Format( _( "Error loading schematic '%s'." ), aFileName );
1434 DisplayErrorMessage( this, msg, ioe.What() );
1435
1436 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1437 SetMsgPanel( wxEmptyString, msg );
1438 }
1439 catch( const std::exception& exc )
1440 {
1443
1444 wxString msg = wxString::Format( _( "Unhandled exception occurred loading schematic "
1445 "'%s'." ), aFileName );
1446 DisplayErrorMessage( this, msg, exc.what() );
1447
1448 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1449 SetMsgPanel( wxEmptyString, msg );
1450 }
1451
1454
1457 SyncView();
1458
1459 UpdateHierarchyNavigator( false, true );
1460
1461 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGED );
1462 ProcessEventLocally( e );
1463
1464 for( wxEvtHandler* listener : m_schematicChangeListeners )
1465 {
1466 wxCHECK2( listener, continue );
1467
1468 // Use the windows variant when handling event messages in case there is any
1469 // special event handler pre and/or post processing specific to windows.
1470 wxWindow* win = dynamic_cast<wxWindow*>( listener );
1471
1472 if( win )
1473 win->HandleWindowEvent( e );
1474 else
1475 listener->SafelyProcessEvent( e );
1476 }
1477
1478 updateTitle();
1479 break;
1480 }
1481
1482 default:
1483 break;
1484 }
1485
1486 return true;
1487}
1488
1489
1491{
1492 SCH_SCREENS screenList( Schematic().Root() );
1493
1494 // Save any currently open and modified project files.
1495 for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
1496 {
1497 SIMULATOR_FRAME* simFrame = (SIMULATOR_FRAME*) Kiway().Player( FRAME_SIMULATOR, false );
1498
1499 // Simulator must be closed before loading another schematic, otherwise it may crash.
1500 // If there are any changes in the simulator the user will be prompted to save them.
1501 if( simFrame && !simFrame->Close() )
1502 return false;
1503
1504 if( screen->IsContentModified() )
1505 {
1506 if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
1507 "Save changes?" ),
1508 [&]() -> bool
1509 {
1510 return SaveProject();
1511 } ) )
1512 {
1513 return false;
1514 }
1515 }
1516 }
1517
1518 return true;
1519}
1520
1521
1523{
1524 wxFileName tmpFn = Prj().GetProjectFullName();
1525 wxFileName autoSaveFileName( tmpFn.GetPath(), getAutoSaveFileName() );
1526
1527 if( !autoSaveFileName.IsDirWritable() )
1528 {
1529 wxLogTrace( traceAutoSave, "Insufficient permissions to auto save file '%s'",
1530 autoSaveFileName.GetFullPath() );
1531 return false;
1532 }
1533
1534 wxLogTrace( traceAutoSave, "Creating auto save file '%s'", autoSaveFileName.GetFullPath() );
1535
1536 wxFileName fn;
1537 SCH_SCREENS screens( Schematic().Root() );
1538 std::vector< wxString > autoSavedFiles;
1539
1540 for( size_t i = 0; i < screens.GetCount(); i++ )
1541 {
1542 // Only create auto save files for the schematics that have been modified.
1543 if( !screens.GetScreen( i )->IsContentModified() )
1544 continue;
1545
1546 fn = screens.GetScreen( i )->GetFileName();
1547
1548 // Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
1549 fn.SetName( FILEEXT::AutoSaveFilePrefix + fn.GetName() );
1550 autoSavedFiles.emplace_back( fn.GetFullPath() );
1551 }
1552
1553 wxTextFile autoSaveFile( autoSaveFileName.GetFullPath() );
1554
1555 if( autoSaveFileName.FileExists() && !wxRemoveFile( autoSaveFileName.GetFullPath() ) )
1556 {
1557 wxLogTrace( traceAutoSave, "Error removing auto save file '%s'",
1558 autoSaveFileName.GetFullPath() );
1559
1560 return false;
1561 }
1562
1563 // No modified sheet files to save.
1564 if( autoSavedFiles.empty() )
1565 return true;
1566
1567 if( !autoSaveFile.Create() )
1568 return false;
1569
1570 for( const wxString& fileName : autoSavedFiles )
1571 {
1572 wxLogTrace( traceAutoSave, "Adding auto save file '%s' to '%s'",
1573 fileName, autoSaveFileName.GetName() );
1574 autoSaveFile.AddLine( fileName );
1575 }
1576
1577 if( !autoSaveFile.Write() )
1578 return false;
1579
1580 wxLogTrace( traceAutoSave, "Auto save file '%s' written", autoSaveFileName.GetFullName() );
1581
1582 return true;
1583}
1584
1585
1586void removeFile( const wxString& aFilename, wxArrayString& aUnremoved )
1587{
1588 wxLogTrace( traceAutoSave, wxS( "Removing auto save file '%s'" ), aFilename );
1589
1590 if( wxFileExists( aFilename ) && !wxRemoveFile( aFilename ) )
1591 aUnremoved.Add( aFilename );
1592};
1593
1594
1595void SCH_EDIT_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
1596{
1597 if( !Pgm().IsGUI() )
1598 return;
1599
1600 wxCHECK_RET( aFileName.IsOk(), wxS( "Invalid file name!" ) );
1601
1602 wxLogTrace( traceAutoSave, wxS( "Checking for auto save file '%s'" ), aFileName.GetFullPath() );
1603
1604 if( !aFileName.FileExists() )
1605 return;
1606
1607 wxString msg = _( "Well this is potentially embarrassing!\n"
1608 "It appears that the last time you were editing one or more of the schematic files\n"
1609 "were not saved properly. Do you wish to restore the last saved edits you made?" );
1610
1611 int response = wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxYES_NO | wxICON_QUESTION, this );
1612
1613 wxTextFile fileList( aFileName.GetFullPath() );
1614
1615 if( !fileList.Open() )
1616 {
1617 msg.Printf( _( "The file '%s' could not be opened.\n"
1618 "Manual recovery of automatically saved files is required." ),
1619 aFileName.GetFullPath() );
1620
1621 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1622 return;
1623 }
1624
1625 if( response == wxYES )
1626 {
1627 wxArrayString unrecoveredFiles;
1628
1629 for( wxString fn = fileList.GetFirstLine(); !fileList.Eof(); fn = fileList.GetNextLine() )
1630 {
1631 wxFileName recoveredFn = fn;
1632 wxString tmp = recoveredFn.GetName();
1633
1634 // Strip "_autosave-" prefix from the auto save file name.
1635 tmp.Replace( FILEEXT::AutoSaveFilePrefix, wxS( "" ), false );
1636 recoveredFn.SetName( tmp );
1637
1638 wxFileName backupFn = recoveredFn;
1639
1640 backupFn.SetExt( backupFn.GetExt() + FILEEXT::BackupFileSuffix );
1641
1642 wxLogTrace( traceAutoSave, wxS( "Recovering auto save file:\n"
1643 " Original file: '%s'\n"
1644 " Backup file: '%s'\n"
1645 " Auto save file: '%s'" ),
1646 recoveredFn.GetFullPath(), backupFn.GetFullPath(), fn );
1647
1648 if( !wxFileExists( fn ) )
1649 {
1650 unrecoveredFiles.Add( recoveredFn.GetFullPath() );
1651 }
1652 // Attempt to back up the last schematic file before overwriting it with the auto
1653 // save file.
1654 else if( recoveredFn.Exists()
1655 && !wxCopyFile( recoveredFn.GetFullPath(), backupFn.GetFullPath() ) )
1656 {
1657 unrecoveredFiles.Add( recoveredFn.GetFullPath() );
1658 }
1659 // Attempt to replace last saved file with auto save file
1660 else if( !wxRenameFile( fn, recoveredFn.GetFullPath() ) )
1661 {
1662 unrecoveredFiles.Add( recoveredFn.GetFullPath() );
1663 }
1664 }
1665
1666 if( !unrecoveredFiles.IsEmpty() )
1667 {
1668 msg = _( "The following automatically saved file(s) could not be restored\n" );
1669
1670 for( size_t i = 0; i < unrecoveredFiles.GetCount(); i++ )
1671 msg += unrecoveredFiles[i] + wxS( "\n" );
1672
1673 msg += _( "Manual recovery will be required to restore the file(s) above." );
1674 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1675 }
1676
1677 wxArrayString unremovedFiles;
1678 removeFile( aFileName.GetFullPath(), unremovedFiles );
1679
1680 if( !unremovedFiles.IsEmpty() )
1681 {
1682 msg.Printf( _( "The autosave file '%s' could not be removed.\n"
1683 "Manual removal will be required." ),
1684 unremovedFiles[0] );
1685
1686 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1687 }
1688 }
1689 else
1690 {
1691 DeleteAutoSaveFile( aFileName );
1692 }
1693}
1694
1695
1696void SCH_EDIT_FRAME::DeleteAutoSaveFile( const wxFileName& aFileName )
1697{
1698 if( !Pgm().IsGUI() )
1699 return;
1700
1701 wxCHECK_RET( aFileName.IsOk(), wxS( "Invalid file name!" ) );
1702
1703 if( !aFileName.FileExists() )
1704 return;
1705
1706 wxTextFile fileList( aFileName.GetFullPath() );
1707 wxArrayString unremovedFiles;
1708
1709 for( wxString fn = fileList.GetFirstLine(); !fileList.Eof(); fn = fileList.GetNextLine() )
1710 removeFile( fn, unremovedFiles );
1711
1712 removeFile( aFileName.GetFullPath(), unremovedFiles );
1713
1714 if( !unremovedFiles.IsEmpty() )
1715 {
1716 wxString msg = _( "The following automatically saved file(s) could not be removed\n" );
1717
1718 for( size_t i = 0; i < unremovedFiles.GetCount(); i++ )
1719 msg += unremovedFiles[i] + wxS( "\n" );
1720
1721 msg += _( "Manual removal will be required for the file(s) above." );
1722 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1723 }
1724}
1725
1726
1728{
1729 static wxString autoSaveFileName( wxS( "#auto_saved_files#" ) );
1730
1731 return autoSaveFileName;
1732}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION zoomFitScreen
Definition actions.h:141
bool IsContentModified() const
Definition base_screen.h:60
void SetVirtualPageNumber(int aPageNumber)
Definition base_screen.h:76
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 SetContentModified(bool aModified=true)
Definition base_screen.h:59
Class DIALOG_HTML_REPORTER.
WX_HTML_REPORT_BOX * m_Reporter
static std::vector< IMPORT_PROJECT_DESC > RunModal(wxWindow *aParent, const std::vector< IMPORT_PROJECT_DESC > &aProjectDesc)
Create and show a dialog (modal) and returns the data from it after completion.
int ShowModal() override
Handle the graphic items list to draw/plot the frame and title block.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
void LoadWindowState(const wxString &aFileName)
bool m_autoSavePermissionError
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
SETTINGS_MANAGER * GetSettingsManager() const
WX_INFOBAR * m_infoBar
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
wxString GetMruPath() const
bool IsWritable(const wxFileName &aFileName, bool aVerbose=true)
Check if aFileName can be written.
std::unique_ptr< LOCKFILE > m_file_checker
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void RefreshCanvas() override
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:516
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
bool GetCreateNewProject() const
Gets the selected state of the copy subsheets option.
bool GetCopySubsheets() const
Gets the selected state of the include external sheets option.
bool GetIncludeExternSheets() const
Gets if this hook has attached controls to a dialog box.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
virtual const wxString Problem() const
what was the problem?
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:95
bool IsSingle() const
Is this KIFACE running under single_top?
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:395
static REPORTER & GetInstance()
Definition reporter.cpp:96
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:136
void HideSplash()
Definition pgm_base.cpp:333
A small class to help profiling.
Definition profile.h:49
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition profile.h:105
virtual void Report(const wxString &aMessage) override
Display aMessage in the progress bar dialog.
bool KeepRefreshing(bool aWait=false) override
Update the UI dialog.
Plugin class for import plugins that support choosing a project.
std::vector< FILE_INFO_PAIR > & GetSheets()
static SYMBOL_LIB_TABLE * SchSymbolLibTable(PROJECT *aProject)
Accessor for project symbol library table.
static SYMBOL_LIBS * SchLibs(PROJECT *aProject)
These are all prefaced with "Sch".
virtual void SetReadOnly(bool aReadOnly=true)
Definition project.h:168
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:156
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition project.cpp:375
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:204
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:386
@ SYMBOL_LIB_TABLE
Definition project.h:77
@ SCH_SYMBOL_LIBS
Definition project.h:74
Holds all the data relating to one schematic.
Definition schematic.h:88
void Reset()
Initialize this schematic to a blank one, unloading anything existing.
void ResolveERCExclusionsPostUpdate()
Update markers to match recorded exclusions.
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
void FixupJunctionsAfterImport()
Add junctions to this schematic where required.
void SetRoot(SCH_SHEET *aRootSheet)
Initialize the schematic with a new root sheet.
void SetProject(PROJECT *aPrj)
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:183
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
SCH_SHEET & Root() const
Definition schematic.h:140
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void SyncView()
Mark all items for refresh.
EESCHEMA_SETTINGS * eeconfig() const
Class for a bus to bus entry.
VECTOR2I GetPosition() const override
VECTOR2I GetEnd() const
void DisplaySheet(SCH_SCREEN *aScreen)
bool IsContentModified() const override
Get if the current schematic has been modified but not saved.
const wxString & getAutoSaveFileName() const
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
void SaveProjectLocalSettings() override
Save changes to the project settings to the project (.pro) file.
bool OpenProjectFiles(const std::vector< wxString > &aFileSet, int aCtl=0) override
Open a project or set of files given by aFileList.
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SetScreen(BASE_SCREEN *aScreen) override
bool AskToSaveChanges()
Check if any of the screens has unsaved changes and asks the user whether to save or drop them.
friend class SCH_EDITOR_CONTROL
bool doAutoSave() override
Save the schematic files that have been modified and not yet saved.
std::vector< wxEvtHandler * > m_schematicChangeListeners
SCH_SHEET_PATH & GetCurrentSheet() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, PROGRESS_REPORTER *aProgressReporter=nullptr)
Generate the connection data for the entire schematic hierarchy.
SCHEMATIC & Schematic() const
void updateTitle()
Set the main window title bar text.
void SetSchematic(SCHEMATIC *aSchematic)
bool saveSchematicFile(SCH_SHEET *aSheet, const wxString &aSavePath)
Save aSheet to a schematic file.
bool LoadProjectSettings()
Load the KiCad project file (*.pro) settings specific to Eeschema.
void RecomputeIntersheetRefs()
Update the schematic's page reference map for all global labels, and refresh the labels so that they ...
void UpdateHierarchyNavigator(bool aRefreshNetNavigator=true, bool aClear=false)
Update the hierarchy navigation tree and history.
bool importFile(const wxString &aFileName, int aFileType, const std::map< std::string, UTF8 > *aProperties=nullptr)
Load the given filename but sets the path to the current project path.
void LoadDrawingSheet()
Load the drawing sheet file.
virtual void DeleteAutoSaveFile(const wxFileName &aFileName) override
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
void ClearRepeatItemsList()
Clear the list of items which are to be repeated with the insert key.
void initScreenZoom()
Initialize the zoom value of the current screen and mark the screen as zoom-initialized.
void OnImportProject(wxCommandEvent &event)
virtual void CheckForAutoSaveFile(const wxFileName &aFileName) override
This overloaded version checks if the auto save master file "#auto_saved_files#" exists and recovers ...
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
wxString GetCurrentFileName() const override
Get the full filename + path of the currently opened file in the frame.
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
bool SaveProject(bool aSaveAs=false)
Save the currently-open schematic (including its hierarchy) and associated project.
void saveProjectSettings() override
Save any design-related project settings associated with this frame.
static SCH_FILE_T GuessPluginTypeFromSchPath(const wxString &aSchematicPath, int aCtl=0)
Return a plugin type given a schematic using the file extension of aSchematicPath.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
Handle actions specific to the schematic editor.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:758
SCH_SCREEN * GetNext()
SCH_SCREEN * GetScreen(unsigned int aIndex) const
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
SCH_SCREEN * GetFirst()
void PruneOrphanedSheetInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
void BuildClientSheetPathList()
Build the list of sheet paths sharing a screen for each screen in use.
bool HasSymbolFieldNamesWithWhiteSpace() const
size_t GetCount() const
Definition sch_screen.h:763
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
SCH_SHEET * GetSheet(unsigned int aIndex) const
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
void ClearDrawingState()
Clear the state flags of all the items in the screen.
std::vector< SCH_SHEET_PATH > & GetClientSheetPaths()
Return the number of times this screen is used.
Definition sch_screen.h:186
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.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:117
const wxString & GetFileName() const
Definition sch_screen.h:152
const KIID & GetUuid() const
Definition sch_screen.h:539
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
int GetFileFormatVersionAtLoad() const
Definition sch_screen.h:137
void AssignNewUuid()
Definition sch_screen.h:541
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void UpdateSheetInstanceData(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
void SetInitialPageNumbers()
Set initial sheet page numbers.
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
bool IsModified() const
Check the entire hierarchy for any modifications.
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void CheckForMissingSymbolInstances(const wxString &aProjectName)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:47
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:327
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:321
bool IsRootSheet() const
wxString GetName() const
Definition sch_sheet.h:113
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:116
void SaveProjectAs(const wxString &aFullPath, PROJECT *aProject=nullptr)
Set the currently loaded project path and saves it (pointers remain valid).
void SaveProjectCopy(const wxString &aFullPath, PROJECT *aProject=nullptr)
Save a copy of the current project under the given path.
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Save a loaded project.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Save, unload and unregister the given PROJECT.
bool TriggerBackupIfNeeded(REPORTER &aReporter) const
Call BackupProject() if a new backup is needed according to the current backup policy.
The SIMULATOR_FRAME holds the main user-interface for running simulations.
A collection of SYMBOL_LIB objects.
int GetLibraryCount()
static void SetLibNamesAndPaths(PROJECT *aProject, const wxString &aPaths, const wxArrayString &aNames)
static void GetLibNamesAndPaths(PROJECT *aProject, wxString *aPaths, wxArrayString *aNames=nullptr)
TOOL_MANAGER * m_toolManager
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition tool_base.h:81
Temporarily disable a window, and then re-enable on destruction.
Definition raii.h:87
static void ResolvePossibleSymlinks(wxFileName &aFilename)
void Flush()
Build the HTML messages page.
bool HasMessage() const override
Returns true if any messages were reported.
@ OUTDATED_SAVE
OUTDATED_SAVE Messages that should be cleared on save.
Definition wx_infobar.h:96
Multi-thread safe progress reporter dialog, intended for use of tasks that parallel reporting back of...
A wrapper for reporting to a wxString object.
Definition reporter.h:191
const wxString & GetMessages() const
Definition reporter.cpp:77
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition common.cpp:429
The common library.
bool AskOverrideLock(wxWindow *aParent, const wxString &aMessage)
Display a dialog indicating the file is already open, with an option to reset the lock.
Definition confirm.cpp:42
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:251
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:222
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:129
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:194
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:169
This file is part of the common library.
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
void removeFile(const wxString &aFilename, wxArrayString &aUnremoved)
bool PrepareSaveAsFiles(SCHEMATIC &aSchematic, SCH_SCREENS &aScreens, const wxFileName &aOldRoot, const wxFileName &aNewRoot, bool aSaveCopy, bool aCopySubsheets, bool aIncludeExternSheets, std::unordered_map< SCH_SCREEN *, wxString > &aFilenameMap, wxString &aErrorMsg)
void Reset() override
@ FRAME_SIMULATOR
Definition frame_type.h:38
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string LegacySymbolLibFileExtension
static const std::string BackupFileSuffix
static const std::string AutoSaveFilePrefix
static wxString KiCadSchematicFileWildcard()
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
PROJECT & Prj()
Definition kicad.cpp:612
#define KICTL_CREATE
caller thinks requested project files may not exist.
#define KICTL_REVERT
reverting to a previously-saved (KiCad) file.
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
@ LAYER_BUS
Definition layer_ids.h:452
File locking utilities.
void SetShutdownBlockReason(wxWindow *aWindow, const wxString &aReason)
Sets the block reason why the window/application is preventing OS shutdown.
Definition unix/app.cpp:90
bool RegisterApplicationRestart(const wxString &aCommandLine)
Registers the application for restart with the OS with the given command line string to pass as args.
Definition unix/app.cpp:65
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:913
see class PGM_BASE
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
@ GLOBAL_CLEANUP
Definition schematic.h:77
KIWAY Kiway(KFCTL_STANDALONE)
std::vector< FAB_LAYER_COLOR > dummy
MODEL3D_FORMAT_TYPE fileType(const char *aFileName)
bool show_import_issues
Stored value for "show import issues" when importing non-KiCad designs to this application.
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Container that describes file type info.
Definition io_base.h:43
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition io_base.h:47
bool m_CanRead
Whether the IO can read this file type.
Definition io_base.h:52
wxString FileFilter() const
Definition io_base.cpp:40
Definition for symbol library class.
wxLogTrace helper definitions.
@ SCH_SHEET_T
Definition typeinfo.h:177
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:164
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT