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