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