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-2023 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 }
274
275 if( !pi->GetError().IsEmpty() )
276 {
277 DisplayErrorMessage( this, _( "The entire schematic could not be loaded. Errors "
278 "occurred attempting to load hierarchical sheets." ),
279 pi->GetError() );
280 }
281 }
282 catch( const FUTURE_FORMAT_ERROR& ffe )
283 {
284 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName);
285 progressReporter.Hide();
286 DisplayErrorMessage( this, msg, ffe.Problem() );
287
288 failedLoad = true;
289 }
290 catch( const IO_ERROR& ioe )
291 {
292 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName);
293 progressReporter.Hide();
294 DisplayErrorMessage( this, msg, ioe.What() );
295
296 failedLoad = true;
297 }
298 catch( const std::bad_alloc& )
299 {
300 msg.Printf( _( "Memory exhausted loading schematic '%s'." ), fullFileName );
301 progressReporter.Hide();
302 DisplayErrorMessage( this, msg, wxEmptyString );
303
304 failedLoad = true;
305 }
306
307 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
308 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
309 // compiled.
310 Raise();
311
312 if( failedLoad )
313 {
314 // Do not leave g_RootSheet == NULL because it is expected to be
315 // a valid sheet. Therefore create a dummy empty root sheet and screen.
318
319 msg.Printf( _( "Failed to load '%s'." ), fullFileName );
320 SetMsgPanel( wxEmptyString, msg );
321
322 return false;
323 }
324
325 // It's possible the schematic parser fixed errors due to bugs so warn the user
326 // that the schematic has been fixed (modified).
327 SCH_SHEET_LIST sheetList = Schematic().GetSheets();
328
329 if( sheetList.IsModified() )
330 {
331 DisplayInfoMessage( this,
332 _( "An error was found when loading the schematic that has "
333 "been automatically fixed. Please save the schematic to "
334 "repair the broken file or it may not be usable with other "
335 "versions of KiCad." ) );
336 }
337
338 if( sheetList.AllSheetPageNumbersEmpty() )
339 sheetList.SetInitialPageNumbers();
340
341 UpdateFileHistory( fullFileName );
342
343 SCH_SCREENS schematic( Schematic().Root() );
344
345 // LIB_ID checks and symbol rescue only apply to the legacy file formats.
346 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
347 {
348 // Convert any legacy bus-bus entries to just be bus wires
349 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
350 {
351 std::vector<SCH_ITEM*> deleted;
352
353 for( SCH_ITEM* item : screen->Items() )
354 {
355 if( item->Type() == SCH_BUS_BUS_ENTRY_T )
356 {
357 SCH_BUS_BUS_ENTRY* entry = static_cast<SCH_BUS_BUS_ENTRY*>( item );
358 std::unique_ptr<SCH_LINE> wire = std::make_unique<SCH_LINE>();
359
360 wire->SetLayer( LAYER_BUS );
361 wire->SetStartPoint( entry->GetPosition() );
362 wire->SetEndPoint( entry->GetEnd() );
363
364 screen->Append( wire.release() );
365 deleted.push_back( item );
366 }
367 }
368
369 for( SCH_ITEM* item : deleted )
370 screen->Remove( item );
371 }
372
373
374 // Convert old projects over to use symbol library table.
375 if( schematic.HasNoFullyDefinedLibIds() )
376 {
377 DIALOG_SYMBOL_REMAP dlgRemap( this );
378
379 dlgRemap.ShowQuasiModal();
380 }
381 else
382 {
383 // Double check to ensure no legacy library list entries have been
384 // added to the project file symbol library list.
385 wxString paths;
386 wxArrayString libNames;
387
388 SYMBOL_LIBS::GetLibNamesAndPaths( &Prj(), &paths, &libNames );
389
390 if( !libNames.IsEmpty() )
391 {
392 if( eeconfig()->m_Appearance.show_illegal_symbol_lib_dialog )
393 {
394 wxRichMessageDialog invalidLibDlg(
395 this,
396 _( "Illegal entry found in project file symbol library list." ),
397 _( "Project Load Warning" ),
398 wxOK | wxCENTER | wxICON_EXCLAMATION );
399 invalidLibDlg.ShowDetailedText(
400 _( "Symbol libraries defined in the project file symbol library "
401 "list are no longer supported and will be removed.\n\n"
402 "This may cause broken symbol library links under certain "
403 "conditions." ) );
404 invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
405 invalidLibDlg.ShowModal();
407 !invalidLibDlg.IsCheckBoxChecked();
408 }
409
410 libNames.Clear();
411 paths.Clear();
412 SYMBOL_LIBS::SetLibNamesAndPaths( &Prj(), paths, libNames );
413 }
414
415 if( !cfg || !cfg->m_RescueNeverShow )
416 {
418 editor->RescueSymbolLibTableProject( false );
419 }
420 }
421
422 // Ensure there is only one legacy library loaded and that it is the cache library.
423 SYMBOL_LIBS* legacyLibs = PROJECT_SCH::SchLibs( &Schematic().Prj() );
424
425 if( legacyLibs->GetLibraryCount() == 0 )
426 {
427 wxString extMsg;
428 wxFileName cacheFn = pro;
429
430 cacheFn.SetName( cacheFn.GetName() + "-cache" );
432
433 msg.Printf( _( "The project symbol library cache file '%s' was not found." ),
434 cacheFn.GetFullName() );
435 extMsg = _( "This can result in a broken schematic under certain conditions. "
436 "If the schematic does not have any missing symbols upon opening, "
437 "save it immediately before making any changes to prevent data "
438 "loss. If there are missing symbols, either manual recovery of "
439 "the schematic or recovery of the symbol cache library file and "
440 "reloading the schematic is required." );
441
442 wxMessageDialog dlgMissingCache( this, msg, _( "Warning" ),
443 wxOK | wxCANCEL | wxICON_EXCLAMATION | wxCENTER );
444 dlgMissingCache.SetExtendedMessage( extMsg );
445 dlgMissingCache.SetOKCancelLabels(
446 wxMessageDialog::ButtonLabel( _( "Load Without Cache File" ) ),
447 wxMessageDialog::ButtonLabel( _( "Abort" ) ) );
448
449 if( dlgMissingCache.ShowModal() == wxID_CANCEL )
450 {
451 Schematic().Reset();
453 return false;
454 }
455 }
456
457 // Update all symbol library links for all sheets.
458 schematic.UpdateSymbolLinks();
459
462 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
463 "It will be converted to the new format when saved." ),
465
466 // Legacy schematic can have duplicate time stamps so fix that before converting
467 // to the s-expression format.
468 schematic.ReplaceDuplicateTimeStamps();
469
470 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
471 screen->FixLegacyPowerSymbolMismatches();
472
473 // Allow the schematic to be saved to new file format without making any edits.
474 OnModify();
475 }
476 else // S-expression schematic.
477 {
479 {
482 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
483 "It will be converted to the new format when saved." ),
485 }
486
487 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
488 screen->UpdateLocalLibSymbolLinks();
489
490 // Restore all of the loaded symbol and sheet instances from the root sheet.
491 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221002 )
492 sheetList.UpdateSymbolInstanceData( Schematic().RootScreen()->GetSymbolInstances());
493
494 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221110 )
495 sheetList.UpdateSheetInstanceData( Schematic().RootScreen()->GetSheetInstances());
496
497 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
498 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
499 screen->FixLegacyPowerSymbolMismatches();
500
501 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
502 screen->MigrateSimModels();
503
505 {
506 // Allow the schematic to be saved to new file format without making any edits.
507 OnModify();
508 }
509 }
510
511 schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), Schematic().GetSheets() );
512 schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), Schematic().GetSheets() );
513
515
516 SetScreen( GetCurrentSheet().LastScreen() );
517
518 // Migrate conflicting bus definitions
519 // TODO(JE) This should only run once based on schematic file version
520 if( Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() > 0 )
521 {
522 DIALOG_MIGRATE_BUSES dlg( this );
523 dlg.ShowQuasiModal();
524 OnModify();
525 }
526
527 SCH_COMMIT dummy( this );
528
530 }
531
532 // Load any exclusions from the project file
534
537
540
541 // Re-create junctions if needed. Eeschema optimizes wires by merging
542 // colinear segments. If a schematic is saved without a valid
543 // cache library or missing installed libraries, this can cause connectivity errors
544 // unless junctions are added.
545 //
546 // TODO: (RFB) This really needs to be put inside the Load() function of the SCH_IO_KICAD_LEGACY
547 // I can't put it right now because of the extra code that is above to convert legacy bus-bus
548 // entries to bus wires
549 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
551
552 SyncView();
554
556
558
559 wxCommandEvent changedEvt( EDA_EVT_SCHEMATIC_CHANGED );
560 ProcessEventLocally( changedEvt );
561
562 for( wxEvtHandler* listener : m_schematicChangeListeners )
563 {
564 wxCHECK2( listener, continue );
565
566 // Use the windows variant when handling event messages in case there is any special
567 // event handler pre and/or post processing specific to windows.
568 wxWindow* win = dynamic_cast<wxWindow*>( listener );
569
570 if( win )
571 win->HandleWindowEvent( e );
572 else
573 listener->SafelyProcessEvent( e );
574 }
575
576 updateTitle();
577 m_toolManager->GetTool<SCH_NAVIGATE_TOOL>()->ResetHistory();
578
579 wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
580
581 if( fn.FileExists() && !fn.IsFileWritable() )
582 {
585 m_infoBar->ShowMessage( _( "Schematic is read only." ),
587 }
588
589#ifdef PROFILE
590 openFiles.Show();
591#endif
592 // Ensure all items are redrawn (especially the drawing-sheet items):
593 if( GetCanvas() )
594 GetCanvas()->DisplaySheet( GetCurrentSheet().LastScreen() );
595
596 return true;
597}
598
599
601{
602 SCH_SCREEN* screen = GetScreen();
603
604 if( !screen )
605 {
606 wxLogError( wxS( "Document not ready, cannot import" ) );
607 return false;
608 }
609
610 // open file chooser dialog
611 wxString path = wxPathOnly( Prj().GetProjectFullName() );
612
613 wxFileDialog dlg( this, _( "Insert Schematic" ), path, wxEmptyString,
614 FILEEXT::KiCadSchematicFileWildcard(), wxFD_OPEN | wxFD_FILE_MUST_EXIST );
615
616 if( dlg.ShowModal() == wxID_CANCEL )
617 return false;
618
619 return AddSheetAndUpdateDisplay( dlg.GetPath() );
620}
621
622
623bool SCH_EDIT_FRAME::AddSheetAndUpdateDisplay( const wxString aFullFileName )
624{
625 SCH_COMMIT commit( m_toolManager );
627
628 selectionTool->ClearSelection();
629
630 // Mark all existing items on the screen so we don't select them after appending
631 for( EDA_ITEM* item : GetScreen()->Items() )
632 item->SetFlags( SKIP_STRUCT );
633
634 if( !LoadSheetFromFile( GetCurrentSheet().Last(), &GetCurrentSheet(), aFullFileName ) )
635 return false;
636
639
640 SyncView();
641 OnModify();
642 HardRedraw(); // Full reinit of the current screen and the display.
643
644 // Select all new items
645 for( EDA_ITEM* item : GetScreen()->Items() )
646 {
647 if( !item->HasFlag( SKIP_STRUCT ) )
648 {
649 commit.Added( item, GetScreen() );
650 selectionTool->AddItemToSel( item );
651
652 if( item->Type() == SCH_LINE_T )
653 item->SetFlags( STARTPOINT | ENDPOINT );
654 }
655 else
656 item->ClearFlags( SKIP_STRUCT );
657 }
658
659 // Start moving selection, cancel undoes the insertion
661 commit.Revert();
662 else
663 commit.Push( _( "Import Schematic Sheet Content..." ) );
664
666
667 return true;
668}
669
670
671void SCH_EDIT_FRAME::OnAppendProject( wxCommandEvent& event )
672{
673 if( GetScreen() && GetScreen()->IsModified() )
674 {
675 wxString msg = _( "This operation cannot be undone.\n\n"
676 "Do you want to save the current document before proceeding?" );
677
678 if( IsOK( this, msg ) )
679 SaveProject();
680 }
681
683}
684
685
686void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
687{
688 if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
689 {
690 wxString msg = _( "This operation replaces the contents of the current schematic, "
691 "which will be permanently lost.\n\n"
692 "Do you want to proceed?" );
693
694 if( !IsOK( this, msg ) )
695 return;
696 }
697
698 // Set the project location if none is set or if we are running in standalone mode
699 bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
700 wxString path = wxPathOnly( Prj().GetProjectFullName() );
701
702 wxString fileFiltersStr;
703 wxString allWildcardsStr;
704
705 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
706 {
707 if( fileType == SCH_IO_MGR::SCH_KICAD || fileType == SCH_IO_MGR::SCH_LEGACY )
708 continue; // this is "Import non-KiCad schematic"
709
710 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
711
712 if( !pi )
713 continue;
714
715 const IO_BASE::IO_FILE_DESC& desc = pi->GetSchematicFileDesc();
716
717 if( desc.m_FileExtensions.empty() )
718 continue;
719
720 if( !fileFiltersStr.IsEmpty() )
721 fileFiltersStr += wxChar( '|' );
722
723 fileFiltersStr += desc.FileFilter();
724
725 for( const std::string& ext : desc.m_FileExtensions )
726 allWildcardsStr << wxS( "*." ) << formatWildcardExt( ext ) << wxS( ";" );
727 }
728
729 fileFiltersStr = _( "All supported formats" ) + wxS( "|" ) + allWildcardsStr + wxS( "|" )
730 + fileFiltersStr;
731
732 wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFiltersStr,
733 wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
734
735 if( dlg.ShowModal() == wxID_CANCEL )
736 return;
737
738 // Don't leave dangling pointers to previously-opened document.
739 m_toolManager->GetTool<EE_SELECTION_TOOL>()->ClearSelection();
741
742 if( setProject )
743 {
744 Schematic().SetProject( nullptr );
745 GetSettingsManager()->UnloadProject( &Prj(), false );
746
747 // Clear view before destroying schematic as repaints depend on schematic being valid
748 SetScreen( nullptr );
749
750 Schematic().Reset();
751
752 wxFileName projectFn( dlg.GetPath() );
753 projectFn.SetExt( FILEEXT::ProjectFileExtension );
754 GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
755
756 Schematic().SetProject( &Prj() );
757 }
758
759 wxFileName fn = dlg.GetPath();
760
761 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN;
762
763 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
764 {
765 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
766
767 if( !pi )
768 continue;
769
770 if( pi->CanReadSchematicFile( fn.GetFullPath() ) )
771 {
772 pluginType = fileType;
773 break;
774 }
775 }
776
777 if( pluginType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
778 {
779 wxLogError( _( "No loader can read the specified file: '%s'." ), fn.GetFullPath() );
780 return;
781 }
782
783 importFile( dlg.GetPath(), pluginType );
784
786}
787
788
789bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSavePath )
790{
791 wxString msg;
792 wxFileName schematicFileName;
793 wxFileName oldFileName;
794 bool success;
795
796 SCH_SCREEN* screen = aSheet->GetScreen();
797
798 wxCHECK( screen, false );
799
800 // Cannot save to nowhere
801 wxCHECK( !aSavePath.IsEmpty(), false );
802
803 // Construct the name of the file to be saved
804 schematicFileName = Prj().AbsolutePath( aSavePath );
805 oldFileName = schematicFileName;
806
807 // Write through symlinks, don't replace them
808 WX_FILENAME::ResolvePossibleSymlinks( schematicFileName );
809
810 if( !IsWritable( schematicFileName ) )
811 return false;
812
813 wxFileName projectFile( schematicFileName );
814
815 projectFile.SetExt( FILEEXT::ProjectFileExtension );
816
817 if( projectFile.FileExists() )
818 {
819 // Save various ERC settings, such as violation severities (which may have been edited
820 // via the ERC dialog as well as the Schematic Setup dialog), ERC exclusions, etc.
822 }
823
824 wxString tempFile = wxFileName::CreateTempFileName( wxS( "eeschema" ) );
825
826 // Save
827 wxLogTrace( traceAutoSave, wxS( "Saving file " ) + schematicFileName.GetFullPath() );
828
831
832 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
833 schematicFileName.GetFullPath() );
834
835 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
836 pluginType = SCH_IO_MGR::SCH_KICAD;
837
838 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
839
840 try
841 {
842 pi->SaveSchematicFile( tempFile, aSheet, &Schematic() );
843 success = true;
844 }
845 catch( const IO_ERROR& ioe )
846 {
847 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
848 schematicFileName.GetFullPath(),
849 ioe.What() );
850 DisplayError( this, msg );
851
852 msg.Printf( _( "Failed to create temporary file '%s'." ),
853 tempFile );
854 SetMsgPanel( wxEmptyString, msg );
855
856 // In case we started a file but didn't fully write it, clean up
857 wxRemoveFile( tempFile );
858
859 success = false;
860 }
861
862 if( success )
863 {
864 // Preserve the permissions of the current file
865 KIPLATFORM::IO::DuplicatePermissions( schematicFileName.GetFullPath(), tempFile );
866
867 // Replace the original with the temporary file we just wrote
868 success = wxRenameFile( tempFile, schematicFileName.GetFullPath() );
869
870 if( !success )
871 {
872 msg.Printf( _( "Error saving schematic file '%s'.\n"
873 "Failed to rename temporary file '%s'." ),
874 schematicFileName.GetFullPath(),
875 tempFile );
876 DisplayError( this, msg );
877
878 msg.Printf( _( "Failed to rename temporary file '%s'." ),
879 tempFile );
880 SetMsgPanel( wxEmptyString, msg );
881 }
882 }
883
884 if( success )
885 {
886 // Delete auto save file.
887 wxFileName autoSaveFileName = schematicFileName;
888 autoSaveFileName.SetName( GetAutoSaveFilePrefix() + schematicFileName.GetName() );
889
890 if( autoSaveFileName.FileExists() )
891 {
892 wxLogTrace( traceAutoSave,
893 wxS( "Removing auto save file <" ) + autoSaveFileName.GetFullPath() +
894 wxS( ">" ) );
895
896 wxRemoveFile( autoSaveFileName.GetFullPath() );
897 }
898
899 screen->SetContentModified( false );
900
901 msg.Printf( _( "File '%s' saved." ), screen->GetFileName() );
902 SetStatusText( msg, 0 );
903 }
904 else
905 {
906 DisplayError( this, _( "File write operation failed." ) );
907 }
908
909 return success;
910}
911
912
913bool SCH_EDIT_FRAME::SaveProject( bool aSaveAs )
914{
915 wxString msg;
916 SCH_SCREEN* screen;
917 SCH_SCREENS screens( Schematic().Root() );
918 bool saveCopy = aSaveAs && !Kiface().IsSingle();
919 bool success = true;
920 bool updateFileHistory = false;
921 bool createNewProject = false;
922
923 // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
924 wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
925 wxFileName fn = fileName;
926
927 // Path to save each screen to: will be the stored filename by default, but is overwritten by
928 // a Save As Copy operation.
929 std::unordered_map<SCH_SCREEN*, wxString> filenameMap;
930
931 // Handle "Save As" and saving a new project/schematic for the first time in standalone
932 if( Prj().IsNullProject() || aSaveAs )
933 {
934 // Null project should only be possible in standalone mode.
935 wxCHECK( Kiface().IsSingle() || aSaveAs, false );
936
937 wxFileName newFileName;
938 wxFileName savePath( Prj().GetProjectFullName() );
939
940 if( !savePath.IsOk() || !savePath.IsDirWritable() )
941 {
942 savePath = GetMruPath();
943
944 if( !savePath.IsOk() || !savePath.IsDirWritable() )
946 }
947
948 if( savePath.HasExt() )
949 savePath.SetExt( FILEEXT::KiCadSchematicFileExtension );
950 else
951 savePath.SetName( wxEmptyString );
952
953 wxFileDialog dlg( this, _( "Schematic Files" ), savePath.GetPath(), savePath.GetFullName(),
955 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
956
957 FILEDLG_HOOK_SAVE_PROJECT newProjectHook;
958
959 // Add a "Create a project" checkbox in standalone mode and one isn't loaded
960 if( Kiface().IsSingle() || aSaveAs )
961 {
962 dlg.SetCustomizeHook( newProjectHook );
963 }
964
965 if( dlg.ShowModal() == wxID_CANCEL )
966 return false;
967
968 newFileName = EnsureFileExtension( dlg.GetPath(), FILEEXT::KiCadSchematicFileExtension );
969
970 if( ( !newFileName.DirExists() && !newFileName.Mkdir() ) ||
971 !newFileName.IsDirWritable() )
972 {
973 msg.Printf( _( "Folder '%s' could not be created.\n\n"
974 "Make sure you have write permissions and try again." ),
975 newFileName.GetPath() );
976
977 wxMessageDialog dlgBadPath( this, msg, _( "Error" ),
978 wxOK | wxICON_EXCLAMATION | wxCENTER );
979
980 dlgBadPath.ShowModal();
981 return false;
982 }
983
984 if( newProjectHook.IsAttachedToDialog() )
985 createNewProject = newProjectHook.GetCreateNewProject();
986
987 if( !saveCopy )
988 {
989 Schematic().Root().SetFileName( newFileName.GetFullName() );
990 Schematic().RootScreen()->SetFileName( newFileName.GetFullPath() );
991 updateFileHistory = true;
992 }
993 else
994 {
995 filenameMap[Schematic().RootScreen()] = newFileName.GetFullPath();
996 }
997
998 // Set the base path to all new sheets.
999 for( size_t i = 0; i < screens.GetCount(); i++ )
1000 {
1001 screen = screens.GetScreen( i );
1002
1003 wxCHECK2( screen, continue );
1004
1005 // The root screen file name has already been set.
1006 if( screen == Schematic().RootScreen() )
1007 continue;
1008
1009 wxFileName tmp = screen->GetFileName();
1010
1011 // Assume existing sheet files are being reused and do not save them to the new
1012 // path. Maybe in the future, add a user option to copy schematic files to the
1013 // new project path.
1014 if( tmp.FileExists() )
1015 continue;
1016
1017 if( tmp.GetPath().IsEmpty() )
1018 {
1019 tmp.SetPath( newFileName.GetPath() );
1020 }
1021 else if( tmp.GetPath() == fn.GetPath() )
1022 {
1023 tmp.SetPath( newFileName.GetPath() );
1024 }
1025 else if( tmp.GetPath().StartsWith( fn.GetPath() ) )
1026 {
1027 // NOTE: this hasn't been tested because the sheet properties dialog no longer
1028 // allows adding a path specifier in the file name field.
1029 wxString newPath = newFileName.GetPath();
1030 newPath += tmp.GetPath().Right( fn.GetPath().Length() );
1031 tmp.SetPath( newPath );
1032 }
1033
1034 wxLogTrace( tracePathsAndFiles,
1035 wxS( "Moving schematic from '%s' to '%s'." ),
1036 screen->GetFileName(),
1037 tmp.GetFullPath() );
1038
1039 if( !tmp.DirExists() && !tmp.Mkdir() )
1040 {
1041 msg.Printf( _( "Folder '%s' could not be created.\n\n"
1042 "Make sure you have write permissions and try again." ),
1043 newFileName.GetPath() );
1044
1045 wxMessageDialog dlgBadFilePath( this, msg, _( "Error" ),
1046 wxOK | wxICON_EXCLAMATION | wxCENTER );
1047
1048 dlgBadFilePath.ShowModal();
1049 return false;
1050 }
1051
1052 if( saveCopy )
1053 filenameMap[screen] = tmp.GetFullPath();
1054 else
1055 screen->SetFileName( tmp.GetFullPath() );
1056 }
1057
1058 // Attempt to make sheet file name paths relative to the new root schematic path.
1059 SCH_SHEET_LIST sheets = Schematic().GetSheets();
1060
1061 for( SCH_SHEET_PATH& sheet : sheets )
1062 {
1063 if( sheet.Last()->IsRootSheet() )
1064 continue;
1065
1066 sheet.MakeFilePathRelativeToParentSheet();
1067 }
1068 }
1069 else if( !fn.FileExists() )
1070 {
1071 // File doesn't exist yet; true if we just imported something
1072 updateFileHistory = true;
1073 }
1074 else if( !Schematic().GetSheets().IsModified() )
1075 {
1076 return true;
1077 }
1078
1079 if( filenameMap.empty() || !saveCopy )
1080 {
1081 for( size_t i = 0; i < screens.GetCount(); i++ )
1082 filenameMap[screens.GetScreen( i )] = screens.GetScreen( i )->GetFileName();
1083 }
1084
1085 // Warn user on potential file overwrite. This can happen on shared sheets.
1086 wxArrayString overwrittenFiles;
1087 wxArrayString lockedFiles;
1088
1089 for( size_t i = 0; i < screens.GetCount(); i++ )
1090 {
1091 screen = screens.GetScreen( i );
1092
1093 wxCHECK2( screen, continue );
1094
1095 // Convert legacy schematics file name extensions for the new format.
1096 wxFileName tmpFn = filenameMap[screen];
1097
1098 if( !tmpFn.IsOk() )
1099 continue;
1100
1101 if( tmpFn.FileExists() && !tmpFn.IsFileWritable() )
1102 lockedFiles.Add( tmpFn.GetFullPath() );
1103
1104 if( tmpFn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1105 continue;
1106
1108
1109 if( tmpFn.FileExists() )
1110 overwrittenFiles.Add( tmpFn.GetFullPath() );
1111 }
1112
1113 if( !lockedFiles.IsEmpty() )
1114 {
1115 for( const wxString& lockedFile : lockedFiles )
1116 {
1117 if( msg.IsEmpty() )
1118 msg = lockedFile;
1119 else
1120 msg += "\n" + lockedFile;
1121 }
1122
1123 wxRichMessageDialog dlg( this, wxString::Format( _( "Failed to save %s." ),
1124 Schematic().Root().GetFileName() ),
1125 _( "Locked File Warning" ),
1126 wxOK | wxICON_WARNING | wxCENTER );
1127 dlg.SetExtendedMessage( _( "You do not have write permissions to:\n\n" ) + msg );
1128
1129 dlg.ShowModal();
1130 return false;
1131 }
1132
1133 if( !overwrittenFiles.IsEmpty() )
1134 {
1135 for( const wxString& overwrittenFile : overwrittenFiles )
1136 {
1137 if( msg.IsEmpty() )
1138 msg = overwrittenFile;
1139 else
1140 msg += "\n" + overwrittenFile;
1141 }
1142
1143 wxRichMessageDialog dlg( this, _( "Saving will overwrite existing files." ),
1144 _( "Save Warning" ),
1145 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER |
1146 wxICON_EXCLAMATION );
1147 dlg.ShowDetailedText( _( "The following files will be overwritten:\n\n" ) + msg );
1148 dlg.SetOKCancelLabels( wxMessageDialog::ButtonLabel( _( "Overwrite Files" ) ),
1149 wxMessageDialog::ButtonLabel( _( "Abort Project Save" ) ) );
1150
1151 if( dlg.ShowModal() == wxID_CANCEL )
1152 return false;
1153 }
1154
1155 screens.BuildClientSheetPathList();
1156
1157 for( size_t i = 0; i < screens.GetCount(); i++ )
1158 {
1159 screen = screens.GetScreen( i );
1160
1161 wxCHECK2( screen, continue );
1162
1163 // Convert legacy schematics file name extensions for the new format.
1164 wxFileName tmpFn = filenameMap[screen];
1165
1166 if( tmpFn.IsOk() && tmpFn.GetExt() != FILEEXT::KiCadSchematicFileExtension )
1167 {
1168 updateFileHistory = true;
1170
1171 for( EDA_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
1172 {
1173 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1174 wxFileName sheetFileName = sheet->GetFileName();
1175
1176 if( !sheetFileName.IsOk()
1177 || sheetFileName.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1178 continue;
1179
1180 sheetFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
1181 sheet->SetFileName( sheetFileName.GetFullPath() );
1182 UpdateItem( sheet );
1183 }
1184
1185 filenameMap[screen] = tmpFn.GetFullPath();
1186
1187 if( !saveCopy )
1188 screen->SetFileName( tmpFn.GetFullPath() );
1189 }
1190
1191 // Do not save sheet symbols with no valid filename set
1192 if( !tmpFn.IsOk() )
1193 continue;
1194
1195 std::vector<SCH_SHEET_PATH>& sheets = screen->GetClientSheetPaths();
1196
1197 if( sheets.size() == 1 )
1198 screen->SetVirtualPageNumber( 1 );
1199 else
1200 screen->SetVirtualPageNumber( 0 ); // multiple uses; no way to store the real sheet #
1201
1202 // This is a new schematic file so make sure it has a unique ID.
1203 if( !saveCopy && tmpFn.GetFullPath() != screen->GetFileName() )
1204 screen->AssignNewUuid();
1205
1206 success &= saveSchematicFile( screens.GetSheet( i ), tmpFn.GetFullPath() );
1207 }
1208
1209 if( success )
1210 m_autoSaveRequired = false;
1211
1212 // One or more of the modified sheets did not save correctly so update the auto save file.
1213 if( !aSaveAs && !success )
1214 success &= updateAutoSaveFile();
1215
1216 if( aSaveAs && success )
1217 LockFile( Schematic().RootScreen()->GetFileName() );
1218
1219 if( updateFileHistory )
1220 UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
1221
1222 // Save the sheet name map to the project file
1223 std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
1224 sheets.clear();
1225
1226 for( SCH_SHEET_PATH& sheetPath : Schematic().GetSheets() )
1227 {
1228 SCH_SHEET* sheet = sheetPath.Last();
1229
1230 wxCHECK2( sheet, continue );
1231
1232 // Use the schematic UUID for the root sheet.
1233 if( sheet->IsRootSheet() )
1234 {
1235 screen = sheet->GetScreen();
1236
1237 wxCHECK2( screen, continue );
1238
1239 sheets.emplace_back( std::make_pair( screen->GetUuid(), sheet->GetName() ) );
1240 }
1241 else
1242 {
1243 sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
1244 }
1245 }
1246
1247 wxASSERT( filenameMap.count( Schematic().RootScreen() ) );
1248 wxFileName projectPath( filenameMap.at( Schematic().RootScreen() ) );
1249 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1250
1251 if( Prj().IsNullProject() || ( aSaveAs && !saveCopy ) )
1252 {
1253 Prj().SetReadOnly( !createNewProject );
1254 GetSettingsManager()->SaveProjectAs( projectPath.GetFullPath() );
1255 }
1256 else if( saveCopy && createNewProject )
1257 {
1258 GetSettingsManager()->SaveProjectCopy( projectPath.GetFullPath() );
1259 }
1260 else
1261 {
1264 }
1265
1266 if( !Kiface().IsSingle() )
1267 {
1268 WX_STRING_REPORTER backupReporter( &msg );
1269
1270 if( !GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1271 SetStatusText( msg, 0 );
1272 }
1273
1274 updateTitle();
1275
1277 m_infoBar->Dismiss();
1278
1279 return success;
1280}
1281
1282
1284{
1285 wxFileName tmpFileName = Schematic().Root().GetFileName();
1286 wxFileName fn = tmpFileName;
1287 wxFileName tmp;
1288 SCH_SCREENS screens( Schematic().Root() );
1289
1290 // Don't run autosave if content has not been modified
1291 if( !IsContentModified() )
1292 return true;
1293
1294 bool autoSaveOk = true;
1295
1296 if( fn.GetPath().IsEmpty() )
1297 tmp.AssignDir( Prj().GetProjectPath() );
1298 else
1299 tmp.AssignDir( fn.GetPath() );
1300
1301 if( !tmp.IsOk() )
1302 return false;
1303
1304 if( !IsWritable( tmp ) )
1305 return false;
1306
1307 wxString title = GetTitle(); // Save frame title, that can be modified by the save process
1308
1309 for( size_t i = 0; i < screens.GetCount(); i++ )
1310 {
1311 // Only create auto save files for the schematics that have been modified.
1312 if( !screens.GetScreen( i )->IsContentModified() )
1313 continue;
1314
1315 tmpFileName = fn = screens.GetScreen( i )->GetFileName();
1316
1317 // Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
1318 fn.SetName( GetAutoSaveFilePrefix() + fn.GetName() );
1319
1320 if( saveSchematicFile( screens.GetSheet( i ), fn.GetFullPath() ) )
1321 {
1322 // This was only an auto-save, not a real save. Reset the modified flag.
1323 screens.GetScreen( i )->SetContentModified();
1324 }
1325 else
1326 {
1327 autoSaveOk = false;
1328 }
1329 }
1330
1331 if( autoSaveOk && updateAutoSaveFile() )
1332 {
1333 m_autoSaveRequired = false;
1334 m_autoSavePending = false;
1335
1336 if( !Kiface().IsSingle()
1337 && GetSettingsManager()->GetCommonSettings()->m_Backup.backup_on_autosave )
1338 {
1340 }
1341 }
1342
1343 SetTitle( title );
1344
1345 return autoSaveOk;
1346}
1347
1348
1349bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1350 const STRING_UTF8_MAP* aProperties )
1351{
1352 wxFileName filename( aFileName );
1353 wxFileName newfilename;
1354 SCH_SHEET_LIST sheetList = Schematic().GetSheets();
1355 SCH_IO_MGR::SCH_FILE_T fileType = (SCH_IO_MGR::SCH_FILE_T) aFileType;
1356
1357 wxCommandEvent changingEvt( EDA_EVT_SCHEMATIC_CHANGING );
1358 ProcessEventLocally( changingEvt );
1359
1360 switch( fileType )
1361 {
1362 case SCH_IO_MGR::SCH_ALTIUM:
1363 case SCH_IO_MGR::SCH_CADSTAR_ARCHIVE:
1364 case SCH_IO_MGR::SCH_EAGLE:
1365 case SCH_IO_MGR::SCH_LTSPICE:
1366 case SCH_IO_MGR::SCH_EASYEDA:
1367 case SCH_IO_MGR::SCH_EASYEDAPRO:
1368 {
1369 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
1370 wxCHECK_MSG( filename.IsAbsolute(), false,
1371 wxS( "Import schematic: path is not absolute!" ) );
1372
1373 try
1374 {
1375 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
1376 DIALOG_HTML_REPORTER errorReporter( this );
1377 WX_PROGRESS_REPORTER progressReporter( this, _( "Importing Schematic" ), 1 );
1378
1379 PROJECT_CHOOSER_PLUGIN* projectChooserPlugin =
1380 dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() );
1381
1382 if( projectChooserPlugin )
1383 {
1384 projectChooserPlugin->RegisterChooseProjectCallback(
1386 std::placeholders::_1 ) );
1387 }
1388
1389 pi->SetReporter( errorReporter.m_Reporter );
1390 pi->SetProgressReporter( &progressReporter );
1391
1392 SCH_SHEET* loadedSheet =
1393 pi->LoadSchematicFile( aFileName, &Schematic(), nullptr, aProperties );
1394
1395 if( loadedSheet )
1396 {
1397 Schematic().SetRoot( loadedSheet );
1398
1399 if( errorReporter.m_Reporter->HasMessage() )
1400 {
1401 errorReporter.m_Reporter->Flush(); // Build HTML messages
1402 errorReporter.ShowModal();
1403 }
1404
1405 // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works differently
1406 // to KiCad), so set it to an empty one
1408 drawingSheet.SetEmptyLayout();
1409 BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
1410
1411 newfilename.SetPath( Prj().GetProjectPath() );
1412 newfilename.SetName( Prj().GetProjectName() );
1413 newfilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
1414
1415 SetScreen( GetCurrentSheet().LastScreen() );
1416
1417 Schematic().Root().SetFileName( newfilename.GetFullName() );
1418 GetScreen()->SetFileName( newfilename.GetFullPath() );
1420
1422
1423 // Only perform the dangling end test on root sheet.
1425 }
1426 else
1427 {
1428 CreateScreens();
1429 }
1430 }
1431 catch( const IO_ERROR& ioe )
1432 {
1433 // Do not leave g_RootSheet == NULL because it is expected to be
1434 // a valid sheet. Therefore create a dummy empty root sheet and screen.
1435 CreateScreens();
1437
1438 wxString msg = wxString::Format( _( "Error loading schematic '%s'." ), aFileName );
1439 DisplayErrorMessage( this, msg, ioe.What() );
1440
1441 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1442 SetMsgPanel( wxEmptyString, msg );
1443 }
1444 catch( const std::exception& exc )
1445 {
1446 CreateScreens();
1448
1449 wxString msg = wxString::Format( _( "Unhandled exception occurred loading schematic "
1450 "'%s'." ), aFileName );
1451 DisplayErrorMessage( this, msg, exc.what() );
1452
1453 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1454 SetMsgPanel( wxEmptyString, msg );
1455 }
1456
1458
1461 SyncView();
1462
1464
1465 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGED );
1466 ProcessEventLocally( e );
1467
1468 for( wxEvtHandler* listener : m_schematicChangeListeners )
1469 {
1470 wxCHECK2( listener, continue );
1471
1472 // Use the windows variant when handling event messages in case there is any
1473 // special event handler pre and/or post processing specific to windows.
1474 wxWindow* win = dynamic_cast<wxWindow*>( listener );
1475
1476 if( win )
1477 win->HandleWindowEvent( e );
1478 else
1479 listener->SafelyProcessEvent( e );
1480 }
1481
1482 updateTitle();
1483 break;
1484 }
1485
1486 default:
1487 break;
1488 }
1489
1490 return true;
1491}
1492
1493
1495{
1496 SCH_SCREENS screenList( Schematic().Root() );
1497
1498 // Save any currently open and modified project files.
1499 for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
1500 {
1501 SIMULATOR_FRAME* simFrame = (SIMULATOR_FRAME*) Kiway().Player( FRAME_SIMULATOR, false );
1502
1503 // Simulator must be closed before loading another schematic, otherwise it may crash.
1504 // If there are any changes in the simulator the user will be prompted to save them.
1505 if( simFrame && !simFrame->Close() )
1506 return false;
1507
1508 if( screen->IsContentModified() )
1509 {
1510 if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
1511 "Save changes?" ),
1512 [&]() -> bool
1513 {
1514 return SaveProject();
1515 } ) )
1516 {
1517 return false;
1518 }
1519 }
1520 }
1521
1522 return true;
1523}
1524
1525
1527{
1528 wxFileName tmpFn = Prj().GetProjectFullName();
1529 wxFileName autoSaveFileName( tmpFn.GetPath(), getAutoSaveFileName() );
1530
1531 wxLogTrace( traceAutoSave, "Creating auto save file %s", autoSaveFileName.GetFullPath() );
1532
1533 wxCHECK( autoSaveFileName.IsDirWritable(), false );
1534
1535 wxFileName fn;
1536 SCH_SCREENS screens( Schematic().Root() );
1537 std::vector< wxString > autoSavedFiles;
1538
1539 for( size_t i = 0; i < screens.GetCount(); i++ )
1540 {
1541 // Only create auto save files for the schematics that have been modified.
1542 if( !screens.GetScreen( i )->IsContentModified() )
1543 continue;
1544
1545 fn = screens.GetScreen( i )->GetFileName();
1546
1547 // Auto save file name is the normal file name prefixed with GetAutoSavePrefix().
1548 fn.SetName( GetAutoSaveFilePrefix() + fn.GetName() );
1549 autoSavedFiles.emplace_back( fn.GetFullPath() );
1550 }
1551
1552 wxTextFile autoSaveFile( autoSaveFileName.GetFullPath() );
1553
1554 if( autoSaveFileName.FileExists() && !wxRemoveFile( autoSaveFileName.GetFullPath() ) )
1555 {
1556 wxLogTrace( traceAutoSave, "Error removing auto save file %s",
1557 autoSaveFileName.GetFullPath() );
1558
1559 return false;
1560 }
1561
1562 // No modified sheet files to save.
1563 if( autoSavedFiles.empty() )
1564 return true;
1565
1566 if( !autoSaveFile.Create() )
1567 return false;
1568
1569 for( const wxString& fileName : autoSavedFiles )
1570 {
1571 wxLogTrace( traceAutoSave, "Adding auto save file %s to %s",
1572 fileName, autoSaveFileName.GetName() );
1573 autoSaveFile.AddLine( fileName );
1574 }
1575
1576 if( !autoSaveFile.Write() )
1577 return false;
1578
1579 wxLogTrace( traceAutoSave, "Auto save file '%s' written", autoSaveFileName.GetFullName() );
1580
1581 return true;
1582}
1583
1584
1585void removeFile( const wxString& aFilename, wxArrayString& aUnremoved )
1586{
1587 wxLogTrace( traceAutoSave, wxS( "Removing auto save file " ) + aFilename );
1588
1589 if( wxFileExists( aFilename ) && !wxRemoveFile( aFilename ) )
1590 aUnremoved.Add( aFilename );
1591};
1592
1593
1594void SCH_EDIT_FRAME::CheckForAutoSaveFile( const wxFileName& aFileName )
1595{
1596 if( !Pgm().IsGUI() )
1597 return;
1598
1599 wxCHECK_RET( aFileName.IsOk(), wxS( "Invalid file name!" ) );
1600
1601 wxLogTrace( traceAutoSave,
1602 wxS( "Checking for auto save file " ) + aFileName.GetFullPath() );
1603
1604 if( !aFileName.FileExists() )
1605 return;
1606
1607 wxString msg = _(
1608 "Well this is potentially embarrassing!\n"
1609 "It appears that the last time you were editing one or more of the schematic files\n"
1610 "were not saved properly. Do you wish to restore the last saved edits you made?" );
1611
1612 int response = wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxYES_NO | wxICON_QUESTION,
1613 this );
1614
1615 wxTextFile fileList( aFileName.GetFullPath() );
1616
1617 if( !fileList.Open() )
1618 {
1619 msg.Printf( _( "The file '%s' could not be opened.\n"
1620 "Manual recovery of automatically saved files is required." ),
1621 aFileName.GetFullPath() );
1622
1623 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1624 return;
1625 }
1626
1627 if( response == wxYES )
1628 {
1629 wxArrayString unrecoveredFiles;
1630
1631 for( wxString fn = fileList.GetFirstLine(); !fileList.Eof(); fn = fileList.GetNextLine() )
1632 {
1633 wxFileName recoveredFn = fn;
1634 wxString tmp = recoveredFn.GetName();
1635
1636 // Strip "_autosave-" prefix from the auto save file name.
1637 tmp.Replace( GetAutoSaveFilePrefix(), wxS( "" ), false );
1638 recoveredFn.SetName( tmp );
1639
1640 wxFileName backupFn = recoveredFn;
1641
1642 backupFn.SetExt( backupFn.GetExt() + FILEEXT::BackupFileSuffix );
1643
1644 wxLogTrace( traceAutoSave, wxS( "Recovering auto save file:\n"
1645 " Original file: '%s'\n"
1646 " Backup file: '%s'\n"
1647 " Auto save file: '%s'" ),
1648 recoveredFn.GetFullPath(), backupFn.GetFullPath(), fn );
1649
1650 if( !wxFileExists( fn ) )
1651 {
1652 unrecoveredFiles.Add( recoveredFn.GetFullPath() );
1653 }
1654 // Attempt to back up the last schematic file before overwriting it with the auto
1655 // save file.
1656 else if( !wxCopyFile( recoveredFn.GetFullPath(), backupFn.GetFullPath() ) )
1657 {
1658 unrecoveredFiles.Add( recoveredFn.GetFullPath() );
1659 }
1660 // Attempt to replace last saved file with auto save file
1661 else if( !wxRenameFile( fn, recoveredFn.GetFullPath() ) )
1662 {
1663 unrecoveredFiles.Add( recoveredFn.GetFullPath() );
1664 }
1665 }
1666
1667 if( !unrecoveredFiles.IsEmpty() )
1668 {
1669 msg = _( "The following automatically saved file(s) could not be restored\n" );
1670
1671 for( size_t i = 0; i < unrecoveredFiles.GetCount(); i++ )
1672 msg += unrecoveredFiles[i] + wxS( "\n" );
1673
1674 msg += _( "Manual recovery will be required to restore the file(s) above." );
1675 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION,
1676 this );
1677 }
1678
1679 wxArrayString unremovedFiles;
1680 removeFile( aFileName.GetFullPath(), unremovedFiles );
1681
1682 if( !unremovedFiles.IsEmpty() )
1683 {
1684 msg.Printf( _( "The autosave file '%s' could not be removed.\n"
1685 "Manual removal will be required." ),
1686 unremovedFiles[0] );
1687
1688 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1689 }
1690 }
1691 else
1692 {
1693 DeleteAutoSaveFile( aFileName );
1694 }
1695}
1696
1697
1698void SCH_EDIT_FRAME::DeleteAutoSaveFile( const wxFileName& aFileName )
1699{
1700 if( !Pgm().IsGUI() )
1701 return;
1702
1703 wxCHECK_RET( aFileName.IsOk(), wxS( "Invalid file name!" ) );
1704
1705 if( !aFileName.FileExists() )
1706 return;
1707
1708 wxTextFile fileList( aFileName.GetFullPath() );
1709 wxArrayString unremovedFiles;
1710
1711 for( wxString fn = fileList.GetFirstLine(); !fileList.Eof(); fn = fileList.GetNextLine() )
1712 removeFile( fn, unremovedFiles );
1713
1714 removeFile( aFileName.GetFullPath(), unremovedFiles );
1715
1716 if( !unremovedFiles.IsEmpty() )
1717 {
1718 wxString msg = _( "The following automatically saved file(s) could not be removed\n" );
1719
1720 for( size_t i = 0; i < unremovedFiles.GetCount(); i++ )
1721 msg += unremovedFiles[i] + wxS( "\n" );
1722
1723 msg += _( "Manual removal will be required for the file(s) above." );
1724 wxMessageBox( msg, Pgm().App().GetAppDisplayName(), wxOK | wxICON_EXCLAMATION, this );
1725 }
1726}
1727
1728
1730{
1731 static wxString autoSaveFileName( wxS( "#auto_saved_files#" ) );
1732
1733 return autoSaveFileName;
1734}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION zoomFitScreen
Definition: actions.h:120
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.
static wxString GetAutoSaveFilePrefix()
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:85
const KIID m_Uuid
Definition: eda_item.h:482
static TOOL_ACTION move
Definition: ee_actions.h:118
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:432
static REPORTER & GetInstance()
Definition: reporter.cpp:119
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:140
A small class to help profiling.
Definition: profile.h:47
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition: profile.h:103
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:840
CONNECTION_GRAPH * ConnectionGraph() const override
Definition: schematic.h:146
void FixupJunctions()
Add junctions to this schematic where required.
Definition: schematic.cpp:738
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:367
virtual void Revert() override
Definition: sch_commit.cpp:448
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.
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.
void UpdateHierarchyNavigator()
Update the hierarchy navigation tree and history.
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:164
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:165
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:314
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:308
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 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:591
KIWAY Kiway
#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:356
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:39
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 & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:119
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
wxString FileFilter() const
Definition: io_base.cpp:38
Definition for symbol library class.
wxLogTrace helper definitions.
@ SCH_LINE_T
Definition: typeinfo.h:148
@ SCH_SHEET_T
Definition: typeinfo.h:162
@ SCH_BUS_BUS_ENTRY_T
Definition: typeinfo.h:147
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.