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