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