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