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