KiCad PCB EDA Suite
Loading...
Searching...
No Matches
eeschema/files-io.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2013 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 2013-2023 CERN (www.cern.ch)
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
23
24#include <algorithm>
25
26#include <confirm.h>
27#include <common.h>
28#include <connection_graph.h>
30#include <dialog_symbol_remap.h>
32#include <eeschema_settings.h>
33#include <id.h>
34#include <kiface_base.h>
35#include <kiplatform/app.h>
36#include <kiplatform/ui.h>
39#include <local_history.h>
40#include <sch_symbol.h>
41#include <set>
42#include <lockfile.h>
43#include <pgm_base.h>
44#include <core/profile.h>
46#include <project_rescue.h>
47#include <project_sch.h>
50#include <reporter.h>
51#include <richio.h>
52#include <sch_bus_entry.h>
53#include <sch_commit.h>
54#include <sch_edit_frame.h>
56#include <sch_file_versions.h>
57#include <sch_line.h>
58#include <sch_sheet.h>
59#include <sch_sheet_path.h>
60#include <schematic.h>
62#include <sim/simulator_frame.h>
63#include <tool/actions.h>
64#include <tool/tool_manager.h>
67#include <trace_helpers.h>
69#include <widgets/kistatusbar.h>
70#include <widgets/wx_infobar.h>
72#include <local_history.h>
74#include <wx/app.h>
75#include <wx/ffile.h>
76#include <wx/filedlg.h>
77#include <wx/log.h>
78#include <wx/richmsgdlg.h>
79#include <wx/stdpaths.h>
82#include <paths.h>
83#include <wx_filename.h> // For ::ResolvePossibleSymlinks
86
87#include <kiplatform/io.h>
88
91#include "save_project_utils.h"
92
93bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
94{
95 // ensure the splash screen does not obscure any dialog at startup
96 Pgm().HideSplash();
97
98 // implement the pseudo code from KIWAY_PLAYER.h:
99 wxString msg;
100
101 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
102
103 // This is for python:
104 if( aFileSet.size() != 1 )
105 {
106 msg.Printf( "Eeschema:%s() takes only a single filename.", __WXFUNCTION__ );
107 DisplayError( this, msg );
108 return false;
109 }
110
111 wxString fullFileName( aFileSet[0] );
112 wxFileName wx_filename( fullFileName );
113
114 if( !Prj().IsNullProject() )
115 Kiway().LocalHistory().Init( Prj().GetProjectPath() );
116
117 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
118 wxASSERT_MSG( wx_filename.IsAbsolute(), wxS( "Path is not absolute!" ) );
119
120 if( !LockFile( fullFileName ) )
121 {
122 // If project-level lock override was already granted, silently override this file's lock
123 if( Prj().IsLockOverrideGranted() )
124 {
125 m_file_checker->OverrideLock();
126 }
127 else
128 {
129 msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), fullFileName,
130 m_file_checker->GetUsername(), m_file_checker->GetHostname() );
131
132 if( !AskOverrideLock( this, msg ) )
133 return false;
134
135 m_file_checker->OverrideLock();
136 }
137 }
138
139 if( !AskToSaveChanges() )
140 return false;
141
142#ifdef PROFILE
143 PROF_TIMER openFiles( "OpenProjectFile" );
144#endif
145
146 wxFileName pro = fullFileName;
147 pro.SetExt( FILEEXT::ProjectFileExtension );
148
149 bool is_new = !wxFileName::IsFileReadable( fullFileName );
150
151 // If its a non-existent schematic and caller thinks it exists
152 if( is_new && !( aCtl & KICTL_CREATE ) )
153 {
154 // notify user that fullFileName does not exist, ask if user wants to create it.
155 msg.Printf( _( "Schematic '%s' does not exist. Do you wish to create it?" ),
156 fullFileName );
157
158 if( !IsOK( this, msg ) )
159 return false;
160 }
161
162 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGING );
163 ProcessEventLocally( e );
164
165 // unload current project file before loading new
166 {
169 SetScreen( nullptr );
171 }
172
173 SetStatusText( wxEmptyString );
174 m_infoBar->Dismiss();
175
176 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
177 statusBar->ClearWarningMessages( "load" );
178
179 WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Create Schematic" )
180 : _( "Load Schematic" ), 1,
181 PR_CAN_ABORT );
182 WX_STRING_REPORTER loadReporter;
183 LOAD_INFO_REPORTER_SCOPE loadReporterScope( &loadReporter );
184
185 bool differentProject = pro.GetFullPath() != Prj().GetProjectFullName();
186
187 // This is for handling standalone mode schematic changes
188 if( differentProject )
189 {
190 if( !Prj().IsNullProject() )
191 {
194 }
195
196 // disconnect existing project from schematic before we unload the project
197 Schematic().SetProject( nullptr );
198 GetSettingsManager()->UnloadProject( &Prj(), false );
199
200 GetSettingsManager()->LoadProject( pro.GetFullPath() );
201
202 wxFileName legacyPro( pro );
203 legacyPro.SetExt( FILEEXT::LegacyProjectFileExtension );
204
205 // Do not allow saving a project if one doesn't exist. This normally happens if we are
206 // standalone and opening a schematic that has been moved from its project folder.
207 if( !pro.Exists() && !legacyPro.Exists() && !( aCtl & KICTL_CREATE ) )
208 Prj().SetReadOnly();
209 }
210
211 // Crash-recovery: when zip-format autosave is active, look for autosave files newer
212 // than the saved schematic and offer to recover them before any sheet is loaded.
213 if( !is_new )
214 CheckForAutosaveFiles( wx_filename.GetPath(), { FILEEXT::KiCadSchematicFileExtension } );
215
216 // Start a new schematic object now that we sorted out our project
217 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
218
219 SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( fullFileName,
221
222 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
223 {
224 // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
225 // They are already saved in the kiface project object.
226 if( differentProject || !Prj().GetElem( PROJECT::ELEM::LEGACY_SYMBOL_LIBS ) )
227 {
228 // load the libraries here, not in SCH_SCREEN::Draw() which is a context
229 // that will not tolerate DisplayError() dialog since we're already in an
230 // event handler in there.
231 // And when a schematic file is loaded, we need these libs to initialize
232 // some parameters (links to PART LIB, dangling ends ...)
235 }
236 }
237 else
238 {
239 // No legacy symbol libraries including the cache are loaded with the new file format.
241 }
242
243 wxFileName rfn( GetCurrentFileName() );
244 rfn.MakeRelativeTo( Prj().GetProjectPath() );
245 LoadWindowState( rfn.GetFullPath() );
246
247 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Schematic file changes are unsaved" ) );
248
249 if( Kiface().IsSingle() )
250 {
252 }
253
254 if( is_new || schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
255 {
256 newSchematic->CreateDefaultScreens();
257 SetSchematic( newSchematic.release() );
258
259 // mark new, unsaved file as modified.
261 GetScreen()->SetFileName( fullFileName );
262
263 if( schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
264 {
265 msg.Printf( _( "'%s' is not a KiCad schematic file.\nUse File -> Import for "
266 "non-KiCad schematic files." ),
267 fullFileName );
268
269 progressReporter.Hide();
270 DisplayErrorMessage( this, msg );
271 }
272 }
273 else
274 {
275 SetScreen( nullptr );
276
277 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( schFileType ) );
278
279 pi->SetProgressReporter( &progressReporter );
280
281 bool failedLoad = false;
282
283 try
284 {
285 {
286 wxBusyCursor busy;
287 WINDOW_DISABLER raii( this );
288
289 // Check if project file has top-level sheets defined
290 PROJECT_FILE& projectFile = Prj().GetProjectFile();
291 const std::vector<TOP_LEVEL_SHEET_INFO>& topLevelSheets = projectFile.GetTopLevelSheets();
292
293 if( !topLevelSheets.empty() )
294 {
295 std::vector<SCH_SHEET*> loadedSheets;
296
297 // Load each top-level sheet
298 for( const TOP_LEVEL_SHEET_INFO& sheetInfo : topLevelSheets )
299 {
300 wxFileName sheetFileName( Prj().GetProjectPath(), sheetInfo.filename );
301
302 // When loading legacy schematic files, ensure we are referencing the correct extension
303 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
304 sheetFileName.SetExt( FILEEXT::LegacySchematicFileExtension );
305
306 wxString sheetPath = sheetFileName.GetFullPath();
307
308 if( !wxFileName::FileExists( sheetPath ) )
309 {
310 wxLogWarning( wxT( "Top-level sheet file not found: %s" ), sheetPath );
311 continue;
312 }
313
314 SCH_SHEET* sheet = pi->LoadSchematicFile( sheetPath, newSchematic.get() );
315
316 if( sheet )
317 {
318 // Preserve the UUID from the project file, unless it's niluuid which is
319 // just a placeholder meaning "use the UUID from the file"
320 if( sheetInfo.uuid != niluuid )
321 {
322 const_cast<KIID&>( sheet->m_Uuid ) = sheetInfo.uuid;
323 }
324
325 sheet->SetName( sheetInfo.name );
326 loadedSheets.push_back( sheet );
327
328 wxLogTrace( tracePathsAndFiles,
329 wxS( "Loaded top-level sheet '%s' (UUID %s) from %s" ),
330 sheet->GetName(),
331 sheet->m_Uuid.AsString(),
332 sheetPath );
333 }
334 }
335
336 if( !loadedSheets.empty() )
337 {
338 newSchematic->SetTopLevelSheets( loadedSheets );
339 }
340 else
341 {
342 wxLogTrace( tracePathsAndFiles,
343 wxS( "Loaded multi-root schematic with no top-level sheets!" ) );
344 newSchematic->CreateDefaultScreens();
345 }
346 }
347 else
348 {
349 // Legacy single-root format: Load the single root sheet
350 SCH_SHEET* rootSheet = pi->LoadSchematicFile( fullFileName, newSchematic.get() );
351
352 if( rootSheet )
353 {
354 newSchematic->SetTopLevelSheets( { rootSheet } );
355
356 // Make ${SHEETNAME} work on the root sheet until we properly support
357 // naming the root sheet
358 if( SCH_SHEET* topSheet = newSchematic->GetTopLevelSheet() )
359 topSheet->SetName( _( "Root" ) );
360
361 wxLogTrace( tracePathsAndFiles,
362 wxS( "Loaded schematic with root sheet UUID %s" ),
363 rootSheet->m_Uuid.AsString() );
364 wxLogTrace( traceSchCurrentSheet,
365 "After loading: Current sheet path='%s', size=%zu, empty=%d",
366 newSchematic->CurrentSheet().Path().AsString(),
367 newSchematic->CurrentSheet().size(),
368 newSchematic->CurrentSheet().empty() ? 1 : 0 );
369 }
370 else
371 {
372 newSchematic->CreateDefaultScreens();
373 }
374
375 }
376 }
377
378 if( !pi->GetError().IsEmpty() )
379 {
380 DisplayErrorMessage( this, _( "The entire schematic could not be loaded. Errors "
381 "occurred attempting to load hierarchical sheets." ),
382 pi->GetError() );
383 }
384 }
385 catch( const FUTURE_FORMAT_ERROR& ffe )
386 {
387 newSchematic->CreateDefaultScreens();
388 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
389 progressReporter.Hide();
390 DisplayErrorMessage( this, msg, ffe.Problem() );
391
392 failedLoad = true;
393 }
394 catch( const IO_ERROR& ioe )
395 {
396 newSchematic->CreateDefaultScreens();
397 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
398 progressReporter.Hide();
399 DisplayErrorMessage( this, msg, ioe.What() );
400
401 failedLoad = true;
402 }
403 catch( const std::bad_alloc& )
404 {
405 newSchematic->CreateDefaultScreens();
406 msg.Printf( _( "Memory exhausted loading schematic '%s'." ), fullFileName );
407 progressReporter.Hide();
408 DisplayErrorMessage( this, msg, wxEmptyString );
409
410 failedLoad = true;
411 }
412
413 SetSchematic( newSchematic.release() );
414
415 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
416 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
417 // compiled.
418 Raise();
419
420 if( failedLoad )
421 {
422 // Do not leave g_RootSheet == NULL because it is expected to be
423 // a valid sheet. Therefore create a dummy empty root sheet and screen.
426
427 // Show any messages collected before the failure
428 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
429 statusBar->AddWarningMessages( "load", loadReporter.GetMessages() );
430
431 msg.Printf( _( "Failed to load '%s'." ), fullFileName );
432 SetMsgPanel( wxEmptyString, msg );
433
434 return false;
435 }
436
437 // Load project settings after schematic has been set up with the project link, since this will
438 // update some of the needed schematic settings such as drawing defaults
440
441 // It's possible the schematic parser fixed errors due to bugs so warn the user
442 // that the schematic has been fixed (modified).
443 SCH_SHEET_LIST sheetList = Schematic().Hierarchy();
444
445 if( sheetList.IsModified() )
446 {
447 DisplayInfoMessage( this,
448 _( "An error was found when loading the schematic that has "
449 "been automatically fixed. Please save the schematic to "
450 "repair the broken file or it may not be usable with other "
451 "versions of KiCad." ) );
452 }
453
454 if( sheetList.AllSheetPageNumbersEmpty() )
455 sheetList.SetInitialPageNumbers();
456
457 UpdateFileHistory( fullFileName );
458
459 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
460 statusBar->AddWarningMessages( "load", loadReporter.GetMessages() );
461
462 SCH_SCREENS schematic( Schematic().Root() );
463
464 // LIB_ID checks and symbol rescue only apply to the legacy file formats.
465 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
466 {
467 // Convert any legacy bus-bus entries to just be bus wires
468 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
469 {
470 std::vector<SCH_ITEM*> deleted;
471
472 for( SCH_ITEM* item : screen->Items() )
473 {
474 if( item->Type() == SCH_BUS_BUS_ENTRY_T )
475 {
476 SCH_BUS_BUS_ENTRY* entry = static_cast<SCH_BUS_BUS_ENTRY*>( item );
477 std::unique_ptr<SCH_LINE> wire = std::make_unique<SCH_LINE>();
478
479 wire->SetLayer( LAYER_BUS );
480 wire->SetStartPoint( entry->GetPosition() );
481 wire->SetEndPoint( entry->GetEnd() );
482
483 screen->Append( wire.release() );
484 deleted.push_back( item );
485 }
486 }
487
488 for( SCH_ITEM* item : deleted )
489 screen->Remove( item );
490 }
491
492
493 // Convert old projects over to use symbol library table.
494 if( schematic.HasNoFullyDefinedLibIds() )
495 {
496 DIALOG_SYMBOL_REMAP dlgRemap( this );
497
498 dlgRemap.ShowQuasiModal();
499 }
500 else
501 {
502 // Double check to ensure no legacy library list entries have been
503 // added to the project file symbol library list.
504 wxString paths;
505 wxArrayString libNames;
506
507 LEGACY_SYMBOL_LIBS::GetLibNamesAndPaths( &Prj(), &paths, &libNames );
508
509 if( !libNames.IsEmpty() )
510 {
511 if( eeconfig()->m_Appearance.show_illegal_symbol_lib_dialog )
512 {
513 wxRichMessageDialog invalidLibDlg(
514 this,
515 _( "Illegal entry found in project file symbol library list." ),
516 _( "Project Load Warning" ),
517 wxOK | wxCENTER | wxICON_EXCLAMATION );
518 invalidLibDlg.ShowDetailedText(
519 _( "Symbol libraries defined in the project file symbol library "
520 "list are no longer supported and will be removed.\n\n"
521 "This may cause broken symbol library links under certain "
522 "conditions." ) );
523 invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
524 invalidLibDlg.ShowModal();
526 !invalidLibDlg.IsCheckBoxChecked();
527 }
528
529 libNames.Clear();
530 paths.Clear();
531 LEGACY_SYMBOL_LIBS::SetLibNamesAndPaths( &Prj(), paths, libNames );
532 }
533
534 // Check for cache file
535 wxFileName cacheFn( fullFileName );
536 cacheFn.SetName( cacheFn.GetName() + "-cache" );
538 bool cacheExists = cacheFn.FileExists();
539
540 if( cacheExists )
541 {
543 std::optional<LIBRARY_TABLE*> table = adapter->ProjectTable();
544
545 if( table && *table )
546 {
547 wxString nickname = Prj().GetProjectName() + "-cache";
548
549 if( !(*table)->HasRow( nickname ) )
550 {
551 LIBRARY_TABLE_ROW& row = (*table)->InsertRow();
552 row.SetNickname( nickname );
553 row.SetURI( cacheFn.GetFullPath() );
554 row.SetType( SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) );
555 row.SetDescription( _( "Legacy project cache library" ) );
556 (*table)->Save();
557 }
558
559 std::vector<wxString> cacheSymbols = adapter->GetSymbolNames( nickname );
560 std::set<wxString> cacheSymbolSet( cacheSymbols.begin(), cacheSymbols.end() );
561
562 if( !cacheSymbolSet.empty() )
563 {
564 std::vector<wxString> loadedLibs;
565
566 for( const wxString& libName : adapter->GetLibraryNames() )
567 {
568 if( libName == nickname )
569 continue;
570
571 std::optional<LIB_STATUS> status = adapter->GetLibraryStatus( libName );
572
573 if( status && status->load_status == LOAD_STATUS::LOADED )
574 loadedLibs.push_back( libName );
575 }
576
577 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
578 {
579 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
580 {
581 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
582 LIB_ID newId = symbol->GetLibId();
583 UTF8 fullLibName = newId.Format();
584
585 if( cacheSymbolSet.count( fullLibName.wx_str() ) )
586 {
587 bool alreadyExists = false;
588
589 for( const wxString& libName : loadedLibs )
590 {
591 if( adapter->LoadSymbol( libName, fullLibName.wx_str() ) )
592 {
593 alreadyExists = true;
594 break;
595 }
596 }
597
598 if( !alreadyExists )
599 {
600 newId.SetLibNickname( nickname );
601 newId.SetLibItemName( fullLibName );
602 symbol->SetLibId( newId );
603 }
604 }
605 }
606 }
607 }
608 }
609 }
610
611 if( ( !cfg || !cfg->m_RescueNeverShow ) && !cacheExists )
612 {
614 editor->RescueSymbolLibTableProject( false );
615 }
616 }
617
618 // Ensure there is only one legacy library loaded and that it is the cache library.
619 LEGACY_SYMBOL_LIBS* legacyLibs = PROJECT_SCH::LegacySchLibs( &Schematic().Project() );
620
621 if( legacyLibs->GetLibraryCount() == 0 )
622 {
623 wxString extMsg;
624 wxFileName cacheFn = pro;
625
626 wxLogTrace( traceAutoSave, "[SetName dbg] cacheFn BEFORE path='%s' name='%s' full='%s' arg='%s'",
627 cacheFn.GetPath(), cacheFn.GetName(), cacheFn.GetFullPath(), cacheFn.GetName() + "-cache" );
628 cacheFn.SetName( cacheFn.GetName() + "-cache" );
629 wxLogTrace( traceAutoSave, "[SetName dbg] cacheFn AFTER path='%s' name='%s' full='%s'",
630 cacheFn.GetPath(), cacheFn.GetName(), cacheFn.GetFullPath() );
632
633 msg.Printf( _( "The project symbol library cache file '%s' was not found." ),
634 cacheFn.GetFullName() );
635 extMsg = _( "This can result in a broken schematic under certain conditions. "
636 "If the schematic does not have any missing symbols upon opening, "
637 "save it immediately before making any changes to prevent data "
638 "loss. If there are missing symbols, either manual recovery of "
639 "the schematic or recovery of the symbol cache library file and "
640 "reloading the schematic is required." );
641
642 KICAD_MESSAGE_DIALOG dlgMissingCache( this, msg, _( "Warning" ),
643 wxOK | wxCANCEL | wxICON_EXCLAMATION | wxCENTER );
644 dlgMissingCache.SetExtendedMessage( extMsg );
645 dlgMissingCache.SetOKCancelLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Load Without Cache File" ) ),
646 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Abort" ) ) );
647
648 if( dlgMissingCache.ShowModal() == wxID_CANCEL )
649 {
650 Schematic().Reset();
652 return false;
653 }
654 }
655
656 // Update all symbol library links for all sheets.
657 schematic.UpdateSymbolLinks( &loadReporter );
658
659 m_infoBar->RemoveAllButtons();
660 m_infoBar->AddCloseButton();
661 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
662 "It will be converted to the new format when saved." ),
663 wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
664
665 // Legacy schematic can have duplicate time stamps so fix that before converting
666 // to the s-expression format.
667 schematic.ReplaceDuplicateTimeStamps();
668
669 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
670 screen->FixLegacyPowerSymbolMismatches();
671
672 // Allow the schematic to be saved to new file format without making any edits.
673 OnModify();
674 }
675 else // S-expression schematic.
676 {
677 SCH_SCREEN* first_screen = schematic.GetFirst();
678
679 // Skip the first screen as it is a virtual root with no version info.
680 if( first_screen && first_screen->GetFileFormatVersionAtLoad() == 0 )
681 first_screen = schematic.GetNext();
682
683 if( first_screen && first_screen->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
684 {
685 m_infoBar->RemoveAllButtons();
686 m_infoBar->AddCloseButton();
687 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
688 "It will be converted to the new format when saved." ),
689 wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
690 }
691
692 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
694
695 SCH_SCREEN* rootScreen = Schematic().RootScreen();
696
697 // Restore all of the loaded symbol and sheet instances from the root sheet.
698 if( rootScreen && rootScreen->GetFileFormatVersionAtLoad() < 20221002 )
699 sheetList.UpdateSymbolInstanceData( rootScreen->GetSymbolInstances() );
700
701 if( rootScreen && rootScreen->GetFileFormatVersionAtLoad() < 20221110 )
702 sheetList.UpdateSheetInstanceData( rootScreen->GetSheetInstances());
703
704 if( rootScreen && rootScreen->GetFileFormatVersionAtLoad() < 20230221 )
705 for( SCH_SCREEN* screen = schematic.GetFirst(); screen;
706 screen = schematic.GetNext() )
707 screen->FixLegacyPowerSymbolMismatches();
708
709 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
710 screen->MigrateSimModels();
711
713 UpdateVariantSelectionCtrl( Schematic().GetVariantNamesForUI() );
714 }
715
716 // After the schematic is successfully loaded, we load the drawing sheet.
717 // This allows us to use the drawing sheet embedded in the schematic (if any)
718 // instead of the default one.
720
721 wxLogTrace( traceSchCurrentSheet,
722 "Before CheckForMissingSymbolInstances: Current sheet path='%s', size=%zu",
723 GetCurrentSheet().Path().AsString(),
724 GetCurrentSheet().size() );
725
726 // Check must run before pruning so variant data on a stale instance path is migrated
727 // onto the new instance before the orphan is removed.
728 sheetList.CheckForMissingSymbolInstances( Prj().GetProjectName() );
729
730 schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), sheetList );
731 schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), sheetList );
732
734
735 SetScreen( GetCurrentSheet().LastScreen() );
736
737 wxLogTrace( traceSchCurrentSheet,
738 "After SetScreen: Current sheet path='%s', size=%zu",
739 GetCurrentSheet().Path().AsString(),
740 GetCurrentSheet().size() );
741
742 // Migrate conflicting bus definitions
743 // TODO(JE) This should only run once based on schematic file version
744 if( Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() > 0 )
745 {
746 DIALOG_MIGRATE_BUSES dlg( this );
747 dlg.ShowQuasiModal();
748 OnModify();
749 }
750
751 SCH_COMMIT dummy( this );
752
753 progressReporter.Report( _( "Updating connections..." ) );
754 progressReporter.KeepRefreshing();
755
756 RecalculateConnections( &dummy, GLOBAL_CLEANUP, &progressReporter );
757
758 if( schematic.HasSymbolFieldNamesWithWhiteSpace() )
759 {
760 m_infoBar->QueueShowMessage( _( "This schematic contains symbols that have leading "
761 "and/or trailing white space field names." ),
762 wxICON_WARNING );
763 }
764 }
765
766 // Load any exclusions from the project file
768
771
774
775 // Re-create junctions if needed. Eeschema optimizes wires by merging
776 // colinear segments. If a schematic is saved without a valid
777 // cache library or missing installed libraries, this can cause connectivity errors
778 // unless junctions are added.
779 //
780 // TODO: (RFB) This really needs to be put inside the Load() function of the SCH_IO_KICAD_LEGACY
781 // I can't put it right now because of the extra code that is above to convert legacy bus-bus
782 // entries to bus wires
783 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
785
786 SyncView();
788
790
791 UpdateHierarchyNavigator( false, true );
792 CallAfter(
793 [this]()
794 {
795 if( m_netNavigator && m_netNavigator->IsEmpty() )
796 {
798 }
799 } );
800
801 wxCommandEvent changedEvt( EDA_EVT_SCHEMATIC_CHANGED );
802 ProcessEventLocally( changedEvt );
803
804 if( !differentProject )
805 {
806 // If we didn't reload the project, we still need to call ProjectChanged() to ensure
807 // frame-specific initialization happens (like registering the autosave saver).
808 // When running under the project manager, KIWAY::ProjectChanged() was called before
809 // this frame existed, so we need to call our own ProjectChanged() now.
811 }
812
813 for( wxEvtHandler* listener : m_schematicChangeListeners )
814 {
815 wxCHECK2( listener, continue );
816
817 // Use the windows variant when handling event messages in case there is any special
818 // event handler pre and/or post processing specific to windows.
819 wxWindow* win = dynamic_cast<wxWindow*>( listener );
820
821 if( win )
822 win->HandleWindowEvent( e );
823 else
824 listener->SafelyProcessEvent( e );
825 }
826
827 updateTitle();
828 m_toolManager->GetTool<SCH_NAVIGATE_TOOL>()->ResetHistory();
829
830 wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
831
832 if( fn.FileExists() && !fn.IsFileWritable() )
833 {
834 m_infoBar->RemoveAllButtons();
835 m_infoBar->AddCloseButton();
836 m_infoBar->ShowMessage( _( "Schematic is read only." ),
837 wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
838 }
839
840#ifdef PROFILE
841 openFiles.Show();
842#endif
843 // Ensure all items are redrawn (especially the drawing-sheet items):
844 if( GetCanvas() )
845 GetCanvas()->DisplaySheet( GetCurrentSheet().LastScreen() );
846
847 // Trigger a library load to handle any project-specific libraries
848 CallAfter( [&]()
849 {
850 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
851 schface->PreloadLibraries( &Kiway() );
852
854 } );
855
856 m_remoteSymbolPane->BindWebViewLoaded();
857
858 return true;
859}
860
861
863{
864 if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
865 {
866 wxString msg = _( "This operation replaces the contents of the current schematic, "
867 "which will be permanently lost.\n\n"
868 "Do you want to proceed?" );
869
870 if( !IsOK( this, msg ) )
871 return;
872 }
873
874 // Set the project location if none is set or if we are running in standalone mode
875 bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
876 wxString path = wxPathOnly( Prj().GetProjectFullName() );
877
878 wxString fileFiltersStr;
879 wxString allWildcardsStr;
880
881 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
882 {
883 if( fileType == SCH_IO_MGR::SCH_KICAD || fileType == SCH_IO_MGR::SCH_LEGACY )
884 continue; // this is "Import non-KiCad schematic"
885
886 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
887
888 if( !pi )
889 continue;
890
891 const IO_BASE::IO_FILE_DESC& desc = pi->GetSchematicFileDesc();
892
893 if( desc.m_FileExtensions.empty() || !desc.m_CanRead )
894 continue;
895
896 if( !fileFiltersStr.IsEmpty() )
897 fileFiltersStr += wxChar( '|' );
898
899 fileFiltersStr += desc.FileFilter();
900
901 for( const std::string& ext : desc.m_FileExtensions )
902 allWildcardsStr << wxS( "*." ) << formatWildcardExt( ext ) << wxS( ";" );
903 }
904
905 fileFiltersStr = _( "All supported formats" ) + wxS( "|" ) + allWildcardsStr + wxS( "|" )
906 + fileFiltersStr;
907
908 wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFiltersStr,
909 wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
910
911 FILEDLG_IMPORT_NON_KICAD importOptions( eeconfig()->m_System.show_import_issues );
912 dlg.SetCustomizeHook( importOptions );
913
915
916 if( dlg.ShowModal() == wxID_CANCEL )
917 return;
918
920
921 // Don't leave dangling pointers to previously-opened document.
922 m_toolManager->GetTool<SCH_SELECTION_TOOL>()->ClearSelection();
925
926 if( setProject )
927 {
928 Schematic().SetProject( nullptr );
929 GetSettingsManager()->UnloadProject( &Prj(), false );
930
931 // Clear view before destroying schematic as repaints depend on schematic being valid
932 SetScreen( nullptr );
933
934 Schematic().Reset();
935
936 wxFileName projectFn( dlg.GetPath() );
937 projectFn.SetExt( FILEEXT::ProjectFileExtension );
938 GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
939 }
940
941 wxFileName fn = dlg.GetPath();
942
943 if( !fn.IsFileReadable() )
944 {
945 wxLogError( _( "Insufficient permissions to read file '%s'." ), fn.GetFullPath() );
946 return;
947 }
948
949 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN;
950
951 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
952 {
953 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
954
955 if( !pi )
956 continue;
957
958 if( pi->CanReadSchematicFile( fn.GetFullPath() ) )
959 {
960 pluginType = fileType;
961 break;
962 }
963 }
964
965 if( pluginType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
966 {
967 wxLogError( _( "No loader can read the specified file: '%s'." ), fn.GetFullPath() );
969 SetScreen( Schematic().RootScreen() );
970 return;
971 }
972
973 importFile( dlg.GetPath(), pluginType );
974
976}
977
978
979bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSavePath )
980{
981 wxString msg;
982 wxFileName schematicFileName;
983 wxFileName oldFileName;
984 bool success;
985
986 SCH_SCREEN* screen = aSheet->GetScreen();
987
988 wxCHECK( screen, false );
989
990 // Cannot save to nowhere
991 if( aSavePath.IsEmpty() )
992 return false;
993
994 // Construct the name of the file to be saved
995 schematicFileName = Prj().AbsolutePath( aSavePath );
996 oldFileName = schematicFileName;
997
998 // Write through symlinks, don't replace them
999 WX_FILENAME::ResolvePossibleSymlinks( schematicFileName );
1000
1001 if( !schematicFileName.DirExists() )
1002 {
1003 if( !wxMkdir( schematicFileName.GetPath() ) )
1004 {
1005 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
1006 schematicFileName.GetFullPath(),
1007 "Could not create directory: %s" + schematicFileName.GetPath() );
1008 DisplayError( this, msg );
1009
1010 return false;
1011 }
1012 }
1013
1014 if( !IsWritable( schematicFileName ) )
1015 return false;
1016
1017 wxFileName projectFile( schematicFileName );
1018
1019 projectFile.SetExt( FILEEXT::ProjectFileExtension );
1020
1021 if( projectFile.FileExists() )
1022 {
1023 // Save various ERC settings, such as violation severities (which may have been edited
1024 // via the ERC dialog as well as the Schematic Setup dialog), ERC exclusions, etc.
1026 }
1027
1028 // Save
1029 wxLogTrace( traceAutoSave, wxS( "Saving file " ) + schematicFileName.GetFullPath() );
1030
1031 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1032 m_infoBar->Dismiss();
1033
1034 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
1035 schematicFileName.GetFullPath() );
1036
1037 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1038 pluginType = SCH_IO_MGR::SCH_KICAD;
1039
1040 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1041
1042 // On Windows, ensure the target file is writeable by clearing problematic attributes like
1043 // hidden or read-only. This can happen when files are synced via cloud services.
1044 if( schematicFileName.FileExists() )
1045 KIPLATFORM::IO::MakeWriteable( schematicFileName.GetFullPath() );
1046
1047 try
1048 {
1049 pi->SaveSchematicFile( schematicFileName.GetFullPath(), aSheet, &Schematic() );
1050 success = true;
1051 }
1052 catch( const IO_ERROR& ioe )
1053 {
1054 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
1055 schematicFileName.GetFullPath(),
1056 ioe.What() );
1057 DisplayError( this, msg );
1058
1059 success = false;
1060 }
1061
1062 if( success )
1063 {
1064 screen->SetContentModified( false );
1065
1066 msg.Printf( _( "File '%s' saved." ), screen->GetFileName() );
1067 SetStatusText( msg, 0 );
1068 }
1069
1070 return success;
1071}
1072
1073
1074bool PrepareSaveAsFiles( SCHEMATIC& aSchematic, SCH_SCREENS& aScreens,
1075 const wxFileName& aOldRoot, const wxFileName& aNewRoot,
1076 bool aSaveCopy, bool aCopySubsheets, bool aIncludeExternSheets,
1077 std::unordered_map<SCH_SCREEN*, wxString>& aFilenameMap,
1078 wxString& aErrorMsg )
1079{
1080 SCH_SCREEN* screen;
1081
1082 for( size_t i = 0; i < aScreens.GetCount(); i++ )
1083 {
1084 screen = aScreens.GetScreen( i );
1085
1086 wxCHECK2( screen, continue );
1087
1088 if( screen == aSchematic.RootScreen() )
1089 continue;
1090
1091 wxFileName src = screen->GetFileName();
1092
1093 if( !src.IsAbsolute() )
1094 src.MakeAbsolute( aOldRoot.GetPath() );
1095
1096 bool internalSheet = src.GetPath().StartsWith( aOldRoot.GetPath() );
1097
1098 if( aCopySubsheets && ( internalSheet || aIncludeExternSheets ) )
1099 {
1100 wxFileName dest = src;
1101
1102 if( internalSheet && dest.MakeRelativeTo( aOldRoot.GetPath() ) )
1103 dest.MakeAbsolute( aNewRoot.GetPath() );
1104 else
1105 dest.Assign( aNewRoot.GetPath(), dest.GetFullName() );
1106
1107 wxLogTrace( tracePathsAndFiles,
1108 wxS( "Moving schematic from '%s' to '%s'." ),
1109 screen->GetFileName(),
1110 dest.GetFullPath() );
1111
1112 if( !dest.DirExists() && !dest.Mkdir() )
1113 {
1114 aErrorMsg.Printf( _( "Folder '%s' could not be created.\n\n"
1115 "Make sure you have write permissions and try again." ),
1116 dest.GetPath() );
1117 return false;
1118 }
1119
1120 if( aSaveCopy )
1121 aFilenameMap[screen] = dest.GetFullPath();
1122 else
1123 screen->SetFileName( dest.GetFullPath() );
1124 }
1125 else
1126 {
1127 if( aSaveCopy )
1128 aFilenameMap[screen] = wxString();
1129
1130 screen->SetFileName( src.GetFullPath() );
1131 }
1132 }
1133
1134 for( SCH_SHEET_PATH& sheet : aSchematic.Hierarchy() )
1135 {
1136 if( !sheet.Last()->IsTopLevelSheet() )
1137 sheet.MakeFilePathRelativeToParentSheet();
1138 }
1139
1140 return true;
1141}
1142
1144{
1145 wxString msg;
1146 SCH_SCREEN* screen;
1147 SCH_SCREENS screens( Schematic().Root() );
1148 bool saveCopy = aSaveAs && !Kiface().IsSingle();
1149 bool success = true;
1150 bool updateFileHistory = false;
1151 bool createNewProject = false;
1152 bool copySubsheets = false;
1153 bool includeExternSheets = false;
1154
1155 // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
1156 wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
1157 wxFileName fn = fileName;
1158
1159 // Path to save each screen to: will be the stored filename by default, but is overwritten by
1160 // a Save As Copy operation.
1161 std::unordered_map<SCH_SCREEN*, wxString> filenameMap;
1162
1163 // Handle "Save As" and saving a new project/schematic for the first time in standalone
1164 if( Prj().IsNullProject() || aSaveAs )
1165 {
1166 // Null project should only be possible in standalone mode.
1167 wxCHECK( Kiface().IsSingle() || aSaveAs, false );
1168
1169 wxFileName newFileName;
1170 wxFileName savePath( Prj().GetProjectFullName() );
1171
1172 if( !savePath.IsOk() || !savePath.IsDirWritable() )
1173 {
1174 savePath = GetMruPath();
1175
1176 if( !savePath.IsOk() || !savePath.IsDirWritable() )
1178 }
1179
1180 if( savePath.HasExt() )
1181 savePath.SetExt( FILEEXT::KiCadSchematicFileExtension );
1182 else
1183 savePath.SetName( wxEmptyString );
1184
1185 wxFileDialog dlg( this, _( "Schematic Files" ), savePath.GetPath(), savePath.GetFullName(),
1187 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1188
1189 FILEDLG_HOOK_SAVE_PROJECT newProjectHook;
1190
1191 // Add a "Create a project" checkbox in standalone mode and one isn't loaded
1192 if( Kiface().IsSingle() || aSaveAs )
1193 {
1194 dlg.SetCustomizeHook( newProjectHook );
1195 }
1196
1198
1199 if( dlg.ShowModal() == wxID_CANCEL )
1200 return false;
1201
1202 newFileName = EnsureFileExtension( dlg.GetPath(), FILEEXT::KiCadSchematicFileExtension );
1203
1204 if( ( !newFileName.DirExists() && !newFileName.Mkdir() ) ||
1205 !newFileName.IsDirWritable() )
1206 {
1207 msg.Printf( _( "Folder '%s' could not be created.\n\n"
1208 "Make sure you have write permissions and try again." ),
1209 newFileName.GetPath() );
1210
1211 KICAD_MESSAGE_DIALOG dlgBadPath( this, msg, _( "Error" ),
1212 wxOK | wxICON_EXCLAMATION | wxCENTER );
1213
1214 dlgBadPath.ShowModal();
1215 return false;
1216 }
1217
1218 if( newProjectHook.IsAttachedToDialog() )
1219 {
1220 createNewProject = newProjectHook.GetCreateNewProject();
1221 copySubsheets = newProjectHook.GetCopySubsheets();
1222 includeExternSheets = newProjectHook.GetIncludeExternSheets();
1223 }
1224
1225 if( !saveCopy )
1226 {
1227 Schematic().Root().SetFileName( newFileName.GetFullName() );
1228 Schematic().RootScreen()->SetFileName( newFileName.GetFullPath() );
1229 updateFileHistory = true;
1230 }
1231 else
1232 {
1233 filenameMap[Schematic().RootScreen()] = newFileName.GetFullPath();
1234 }
1235
1236 if( !PrepareSaveAsFiles( Schematic(), screens, fn, newFileName, saveCopy,
1237 copySubsheets, includeExternSheets, filenameMap, msg ) )
1238 {
1239 KICAD_MESSAGE_DIALOG dlgBadFilePath( this, msg, _( "Error" ),
1240 wxOK | wxICON_EXCLAMATION | wxCENTER );
1241
1242 dlgBadFilePath.ShowModal();
1243 return false;
1244 }
1245 }
1246 else if( !fn.FileExists() )
1247 {
1248 // File doesn't exist yet; true if we just imported something
1249 updateFileHistory = true;
1250 }
1251 else if( screens.GetFirst() && screens.GetFirst()->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
1252 {
1253 // Allow the user to save un-edited files in new format
1254 }
1255 else if( !IsContentModified() )
1256 {
1257 return true;
1258 }
1259
1260 if( filenameMap.empty() || !saveCopy )
1261 {
1262 for( size_t i = 0; i < screens.GetCount(); i++ )
1263 filenameMap[screens.GetScreen( i )] = screens.GetScreen( i )->GetFileName();
1264 }
1265
1266 // Warn user on potential file overwrite. This can happen on shared sheets.
1267 wxArrayString overwrittenFiles;
1268 wxArrayString lockedFiles;
1269
1270 for( size_t i = 0; i < screens.GetCount(); i++ )
1271 {
1272 screen = screens.GetScreen( i );
1273
1274 wxCHECK2( screen, continue );
1275
1276 // Convert legacy schematics file name extensions for the new format.
1277 wxFileName tmpFn = filenameMap[screen];
1278
1279 if( !tmpFn.IsOk() )
1280 continue;
1281
1282 if( tmpFn.FileExists() && !tmpFn.IsFileWritable() )
1283 lockedFiles.Add( tmpFn.GetFullPath() );
1284
1285 if( tmpFn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1286 continue;
1287
1289
1290 if( tmpFn.FileExists() )
1291 overwrittenFiles.Add( tmpFn.GetFullPath() );
1292 }
1293
1294 if( !lockedFiles.IsEmpty() )
1295 {
1296 for( const wxString& lockedFile : lockedFiles )
1297 {
1298 if( msg.IsEmpty() )
1299 msg = lockedFile;
1300 else
1301 msg += "\n" + lockedFile;
1302 }
1303
1304 wxRichMessageDialog dlg( this, wxString::Format( _( "Failed to save %s." ),
1305 Schematic().Root().GetFileName() ),
1306 _( "Locked File Warning" ),
1307 wxOK | wxICON_WARNING | wxCENTER );
1308 dlg.SetExtendedMessage( _( "You do not have write permissions to:\n\n" ) + msg );
1309
1310 dlg.ShowModal();
1311 return false;
1312 }
1313
1314 if( !overwrittenFiles.IsEmpty() )
1315 {
1316 for( const wxString& overwrittenFile : overwrittenFiles )
1317 {
1318 if( msg.IsEmpty() )
1319 msg = overwrittenFile;
1320 else
1321 msg += "\n" + overwrittenFile;
1322 }
1323
1324 wxRichMessageDialog dlg( this, _( "Saving will overwrite existing files." ),
1325 _( "Save Warning" ),
1326 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER |
1327 wxICON_EXCLAMATION );
1328 dlg.ShowDetailedText( _( "The following files will be overwritten:\n\n" ) + msg );
1329 dlg.SetOKCancelLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Overwrite Files" ) ),
1330 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Abort Project Save" ) ) );
1331
1332 if( dlg.ShowModal() == wxID_CANCEL )
1333 return false;
1334 }
1335
1336 screens.BuildClientSheetPathList();
1337
1338 std::vector<wxString> savedSheetPaths;
1339
1340 for( size_t i = 0; i < screens.GetCount(); i++ )
1341 {
1342 screen = screens.GetScreen( i );
1343
1344 wxCHECK2( screen, continue );
1345
1346 // Convert legacy schematics file name extensions for the new format.
1347 wxFileName tmpFn = filenameMap[screen];
1348
1349 if( tmpFn.IsOk() && tmpFn.GetExt() != FILEEXT::KiCadSchematicFileExtension )
1350 {
1351 updateFileHistory = true;
1353
1354 for( EDA_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
1355 {
1356 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1357 wxFileName sheetFileName = sheet->GetFileName();
1358
1359 if( !sheetFileName.IsOk()
1360 || sheetFileName.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1361 continue;
1362
1363 sheetFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
1364 sheet->SetFileName( sheetFileName.GetFullPath() );
1365 UpdateItem( sheet );
1366 }
1367
1368 filenameMap[screen] = tmpFn.GetFullPath();
1369
1370 if( !saveCopy )
1371 screen->SetFileName( tmpFn.GetFullPath() );
1372 }
1373
1374 // Do not save sheet symbols with no valid filename set
1375 if( !tmpFn.IsOk() )
1376 continue;
1377
1378 std::vector<SCH_SHEET_PATH>& sheets = screen->GetClientSheetPaths();
1379
1380 if( sheets.size() == 1 )
1381 screen->SetVirtualPageNumber( 1 );
1382 else
1383 screen->SetVirtualPageNumber( 0 ); // multiple uses; no way to store the real sheet #
1384
1385 // This is a new schematic file so make sure it has a unique ID.
1386 if( !saveCopy && tmpFn.GetFullPath() != screen->GetFileName() )
1387 screen->AssignNewUuid();
1388
1389 bool savedThisSheet = saveSchematicFile( screens.GetSheet( i ), tmpFn.GetFullPath() );
1390
1391 if( savedThisSheet )
1392 savedSheetPaths.push_back( tmpFn.GetFullPath() );
1393
1394 success &= savedThisSheet;
1395 }
1396
1397 if( success )
1398 {
1399 if( m_autoSaveTimer )
1400 m_autoSaveTimer->Stop();
1401
1402 m_autoSavePending = false;
1403 m_autoSaveRequired = false;
1404 }
1405
1406 if( aSaveAs && success )
1407 LockFile( Schematic().RootScreen()->GetFileName() );
1408
1409 if( updateFileHistory )
1410 UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
1411
1412 // Save the sheet name map to the project file
1413 std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
1414 sheets.clear();
1415
1416 for( SCH_SHEET_PATH& sheetPath : Schematic().Hierarchy() )
1417 {
1418 SCH_SHEET* sheet = sheetPath.Last();
1419
1420 wxCHECK2( sheet, continue );
1421
1422 // Do not save the virtual root sheet
1423 if( !sheet->IsVirtualRootSheet() )
1424 {
1425 sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
1426 }
1427 }
1428
1429 wxASSERT( filenameMap.count( Schematic().RootScreen() ) );
1430 wxFileName projectPath( filenameMap.at( Schematic().RootScreen() ) );
1431 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1432
1433 if( Prj().IsNullProject() || ( aSaveAs && !saveCopy ) )
1434 {
1435 Prj().SetReadOnly( !createNewProject );
1436 GetSettingsManager()->SaveProjectAs( projectPath.GetFullPath() );
1437 }
1438 else if( saveCopy && createNewProject )
1439 {
1440 GetSettingsManager()->SaveProjectCopy( projectPath.GetFullPath() );
1441 }
1442 else
1443 {
1446 }
1447
1448 // Record a full project snapshot so related files (symbols, libs, sheets) are captured.
1449 // Skip when running standalone without a project loaded - the save path can land
1450 // anywhere on the filesystem and there is no project context for a snapshot.
1451 if( success && !Prj().IsNullProject() )
1452 {
1453 Kiway().LocalHistory().RunRegisteredSaversAndCommit( Prj().GetProjectPath(), wxS( "SCH Save" ), wxS( "sch" ) );
1454
1455 // Drop the autosave files for the sheets we just persisted. Scope to those
1456 // sources so other dirty sheets (and any open PCB) keep their autosaves until
1457 // they are saved themselves; otherwise a Save All across editors would lose
1458 // recovery data for files this save did not write.
1459 // RunRegisteredSaversAndCommit above is a no-op when format is ZIP, and
1460 // RemoveAutosaveFiles is conversely a no-op in INCREMENTAL mode.
1461 Kiway().LocalHistory().RemoveAutosaveFiles( Prj().GetProjectPath(), savedSheetPaths );
1462 }
1463
1464 if( !Kiface().IsSingle() )
1465 {
1466 WX_STRING_REPORTER backupReporter;
1467
1468 if( !GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1469 SetStatusText( backupReporter.GetMessages(), 0 );
1470 }
1471
1472 updateTitle();
1473
1474 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1475 m_infoBar->Dismiss();
1476
1477 return success;
1478}
1479
1480
1481bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1482 const std::map<std::string, UTF8>* aProperties )
1483{
1484 wxFileName filename( aFileName );
1485 wxFileName newfilename;
1486 SCH_IO_MGR::SCH_FILE_T fileType = (SCH_IO_MGR::SCH_FILE_T) aFileType;
1487
1488 wxCommandEvent changingEvt( EDA_EVT_SCHEMATIC_CHANGING );
1489 ProcessEventLocally( changingEvt );
1490
1491 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
1492 statusBar->ClearWarningMessages( "load" );
1493
1494 WX_STRING_REPORTER loadReporter;
1495 LOAD_INFO_REPORTER_SCOPE loadReporterScope( &loadReporter );
1496
1497 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
1498
1499 switch( fileType )
1500 {
1501 case SCH_IO_MGR::SCH_ALTIUM:
1502 case SCH_IO_MGR::SCH_CADSTAR_ARCHIVE:
1503 case SCH_IO_MGR::SCH_EAGLE:
1504 case SCH_IO_MGR::SCH_LTSPICE:
1505 case SCH_IO_MGR::SCH_EASYEDA:
1506 case SCH_IO_MGR::SCH_EASYEDAPRO:
1507 case SCH_IO_MGR::SCH_PADS:
1508 case SCH_IO_MGR::SCH_GEDA:
1509 case SCH_IO_MGR::SCH_DIPTRACE:
1510 {
1511 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
1512 // Unless we are passing the files in aproperties, in which case aFileName can be empty.
1513 wxCHECK_MSG( aFileName.IsEmpty() || filename.IsAbsolute(), false,
1514 wxS( "Import schematic: path is not absolute!" ) );
1515
1516 try
1517 {
1518 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
1519 DIALOG_HTML_REPORTER errorReporter( this );
1520 WX_PROGRESS_REPORTER progressReporter( this, _( "Import Schematic" ), 1, PR_CAN_ABORT );
1521
1522 if( PROJECT_CHOOSER_PLUGIN* c_pi = dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() ) )
1523 {
1524 c_pi->RegisterCallback( std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::RunModal,
1525 this, std::placeholders::_1 ) );
1526 }
1527
1528 if( eeconfig()->m_System.show_import_issues )
1529 pi->SetReporter( errorReporter.m_Reporter );
1530 else
1531 pi->SetReporter( &NULL_REPORTER::GetInstance() );
1532
1533 pi->SetProgressReporter( &progressReporter );
1534
1535 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( aFileName, newSchematic.get(), nullptr,
1536 aProperties );
1537
1538 SetSchematic( newSchematic.release() );
1539
1540 if( loadedSheet )
1541 {
1542 std::vector<SCH_SHEET*> topLevelSheets = Schematic().GetTopLevelSheets();
1543 bool loadedIsTopLevel = std::find( topLevelSheets.begin(), topLevelSheets.end(), loadedSheet )
1544 != topLevelSheets.end();
1545 bool loadedIsVirtualRoot = loadedSheet == &Schematic().Root()
1546 || loadedSheet->IsVirtualRootSheet();
1547
1548 // Some importers create the full top-level sheet set themselves. Do not collapse
1549 // that back to the returned sheet.
1550 if( !loadedIsTopLevel && !loadedIsVirtualRoot )
1551 Schematic().SetTopLevelSheets( { loadedSheet } );
1552
1553 if( errorReporter.m_Reporter->HasMessage() )
1554 {
1555 errorReporter.m_Reporter->Flush(); // Build HTML messages
1556 errorReporter.ShowModal();
1557 }
1558
1559 // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works
1560 // differently to KiCad), so set it to an empty one.
1562 drawingSheet.SetEmptyLayout();
1563 BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
1564
1565 newfilename.SetPath( Prj().GetProjectPath() );
1566 newfilename.SetName( Prj().GetProjectName() );
1567 newfilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
1568
1569 SetScreen( Schematic().RootScreen() );
1570
1571 if( SCH_SHEET* topSheet = Schematic().GetTopLevelSheet() )
1572 topSheet->SetFileName( newfilename.GetFullName() );
1573
1574 GetScreen()->SetFileName( newfilename.GetFullPath() );
1576
1577 progressReporter.Report( _( "Updating connections..." ) );
1578
1579 if( !progressReporter.KeepRefreshing() )
1580 THROW_IO_ERROR( _( "File import canceled by user." ) );
1581
1582 RecalculateConnections( nullptr, GLOBAL_CLEANUP, &progressReporter );
1583
1584 // Only perform the dangling end test on root sheet.
1586 }
1587 else
1588 {
1590 }
1591 }
1592 catch( const IO_ERROR& ioe )
1593 {
1594 // Do not leave g_RootSheet == NULL because it is expected to be
1595 // a valid sheet. Therefore create a dummy empty root sheet and screen.
1598
1599 wxString msg = wxString::Format( _( "Error loading schematic '%s'." ), aFileName );
1600 DisplayErrorMessage( this, msg, ioe.What() );
1601
1602 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1603 SetMsgPanel( wxEmptyString, msg );
1604 }
1605 catch( const std::exception& exc )
1606 {
1609
1610 wxString msg = wxString::Format( _( "Unhandled exception occurred loading schematic "
1611 "'%s'." ), aFileName );
1612 DisplayErrorMessage( this, msg, exc.what() );
1613
1614 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1615 SetMsgPanel( wxEmptyString, msg );
1616 }
1617
1620
1623 SyncView();
1624
1625 UpdateHierarchyNavigator( false, true );
1626 UpdateVariantSelectionCtrl( m_schematic->GetVariantNamesForUI() );
1627 SetCurrentVariant( m_schematic->GetCurrentVariant() );
1628
1629 CallAfter(
1630 [this]()
1631 {
1632 if( m_netNavigator && m_netNavigator->IsEmpty() )
1633 {
1635 }
1636 } );
1637
1638 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGED );
1639 ProcessEventLocally( e );
1640
1641 for( wxEvtHandler* listener : m_schematicChangeListeners )
1642 {
1643 wxCHECK2( listener, continue );
1644
1645 // Use the windows variant when handling event messages in case there is any
1646 // special event handler pre and/or post processing specific to windows.
1647 wxWindow* win = dynamic_cast<wxWindow*>( listener );
1648
1649 if( win )
1650 win->HandleWindowEvent( e );
1651 else
1652 listener->SafelyProcessEvent( e );
1653 }
1654
1655 updateTitle();
1656
1657 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
1658 statusBar->AddWarningMessages( "load", loadReporter.GetMessages() );
1659
1660 break;
1661 }
1662
1663 default:
1664 break;
1665 }
1666
1667 return true;
1668}
1669
1670
1672{
1673 SCH_SCREENS screenList( Schematic().Root() );
1674
1675 // Save any currently open and modified project files.
1676 for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
1677 {
1678 SIMULATOR_FRAME* simFrame = (SIMULATOR_FRAME*) Kiway().Player( FRAME_SIMULATOR, false );
1679
1680 // Simulator must be closed before loading another schematic, otherwise it may crash.
1681 // If there are any changes in the simulator the user will be prompted to save them.
1682 if( simFrame && !simFrame->Close() )
1683 return false;
1684
1685 if( screen->IsContentModified() )
1686 {
1687 if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
1688 "Save changes?" ),
1689 [&]() -> bool
1690 {
1691 return SaveProject();
1692 } ) )
1693 {
1694 return false;
1695 }
1696 }
1697 }
1698
1699 return true;
1700}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION zoomFitScreen
Definition actions.h:138
void SetVirtualPageNumber(int aPageNumber)
Definition base_screen.h:72
static wxString m_DrawingSheetFileName
the name of the drawing sheet file, or empty to use the default drawing sheet
Definition base_screen.h:81
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
Class DIALOG_HTML_REPORTER.
WX_HTML_REPORT_BOX * m_Reporter
static std::vector< IMPORT_PROJECT_DESC > RunModal(wxWindow *aParent, const std::vector< IMPORT_PROJECT_DESC > &aProjectDesc)
Create and show a dialog (modal) and returns the data from it after completion.
int ShowModal() override
Handle the graphic items list to draw/plot the frame and title block.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
void LoadWindowState(const wxString &aFileName)
void CheckForAutosaveFiles(const wxString &aProjectPath, const std::vector< wxString > &aExtensions)
Check for autosave files newer than their source files for the given project.
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
SETTINGS_MANAGER * GetSettingsManager() const
WX_INFOBAR * m_infoBar
wxTimer * m_autoSaveTimer
void UpdateFileHistory(const wxString &FullFileName, FILE_HISTORY *aFileHistory=nullptr)
Update the list of recently opened files.
wxString GetMruPath() const
bool IsWritable(const wxFileName &aFileName, bool aVerbose=true)
Check if aFileName can be written.
std::unique_ptr< LOCKFILE > m_file_checker
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
void RefreshCanvas() override
bool LockFile(const wxString &aFileName)
Mark a schematic file as being in use.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
const KIID m_Uuid
Definition eda_item.h:531
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:221
bool GetCreateNewProject() const
Gets the selected state of the copy subsheets option.
bool GetCopySubsheets() const
Gets the selected state of the include external sheets option.
bool GetIncludeExternSheets() 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.
virtual const wxString What() const
A composite of Problem() and Where()
virtual const wxString Problem() const
what was the problem?
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:91
bool IsSingle() const
Is this KIFACE running under single_top?
Definition kiid.h:44
wxString AsString() const
Definition kiid.cpp:242
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:398
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:207
@ FACE_SCH
eeschema DSO
Definition kiway.h:318
LOCAL_HISTORY & LocalHistory()
Return the LOCAL_HISTORY associated with this KIWAY.
Definition kiway.h:422
A collection of #SYMBOL_LIB objects.
static void GetLibNamesAndPaths(PROJECT *aProject, wxString *aPaths, wxArrayString *aNames=nullptr)
static void SetLibNamesAndPaths(PROJECT *aProject, const wxString &aPaths, const wxArrayString &aNames)
std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
std::vector< wxString > GetLibraryNames() const
Returns a list of library nicknames that are available (skips any that failed to load)
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetDescription(const wxString &aDescription)
void SetURI(const wxString &aUri)
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:107
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:96
UTF8 Format() const
Definition lib_id.cpp:115
bool RunRegisteredSaversAndCommit(const wxString &aProjectPath, const wxString &aTitle, const wxString &aTagFileType=wxEmptyString)
Run all registered savers and, if any staged changes differ from HEAD, create a commit.
bool Init(const wxString &aProjectPath)
Initialize the local history repository for the given project path.
void RemoveAutosaveFiles(const wxString &aProjectPath) const
Remove every autosave file under the project at aProjectPath regardless of which source it shadowed.
static REPORTER & GetInstance()
Definition reporter.cpp:120
static wxString GetDefaultUserProjectsPath()
Gets the default path we point users to create projects.
Definition paths.cpp:137
void PreloadDesignBlockLibraries(KIWAY *aKiway)
Starts a background job to preload the global and project design block libraries.
Definition pgm_base.cpp:874
void HideSplash()
Definition pgm_base.cpp:309
A small class to help profiling.
Definition profile.h:46
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition profile.h:103
virtual void Report(const wxString &aMessage) override
Display aMessage in the progress bar dialog.
bool KeepRefreshing(bool aWait=false) override
Update the UI dialog.
Plugin class for import plugins that support choosing a project.
The backing store for a PROJECT, in JSON format.
std::vector< FILE_INFO_PAIR > & GetSheets()
std::vector< TOP_LEVEL_SHEET_INFO > & GetTopLevelSheets()
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
static LEGACY_SYMBOL_LIBS * LegacySchLibs(PROJECT *aProject)
Returns the list of symbol libraries from a legacy (pre-5.x) design This is only used from the remapp...
virtual void SetReadOnly(bool aReadOnly=true)
Definition project.h:160
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:177
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition project.cpp:396
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:195
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:200
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:407
@ LEGACY_SYMBOL_LIBS
Definition project.h:69
Holds all the data relating to one schematic.
Definition schematic.h:90
void Reset()
Initialize this schematic to a blank one, unloading anything existing.
void ResolveERCExclusionsPostUpdate()
Update markers to match recorded exclusions.
void LoadVariants()
This is a throw away method for variant testing.
int FixupJunctionsAfterImport()
Add junctions to this schematic where required.
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
void SetProject(PROJECT *aPrj)
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:201
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
void SetTopLevelSheets(const std::vector< SCH_SHEET * > &aSheets)
SCH_SHEET & Root() const
Definition schematic.h:134
std::vector< SCH_SHEET * > GetTopLevelSheets() const
Get the list of top-level sheets.
SCH_DRAW_PANEL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
void SyncView()
Mark all items for refresh.
EESCHEMA_SETTINGS * eeconfig() const
Class for a bus to bus entry.
VECTOR2I GetPosition() const override
VECTOR2I GetEnd() const
void DisplaySheet(SCH_SCREEN *aScreen)
bool IsContentModified() const override
Get if the current schematic has been modified but not saved.
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.
friend class SCH_EDITOR_CONTROL
void SetCurrentVariant(const wxString &aVariantName)
void UpdateVariantSelectionCtrl(const wxArrayString &aVariantNames)
Update the variant name control on the main toolbar.
std::vector< wxEvtHandler * > m_schematicChangeListeners
PANEL_REMOTE_SYMBOL * m_remoteSymbolPane
SCHEMATIC * m_schematic
The currently loaded schematic.
SCH_SHEET_PATH & GetCurrentSheet() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags, PROGRESS_REPORTER *aProgressReporter=nullptr)
Generate the connection data for the entire schematic hierarchy.
void ProjectChanged() override
Notification event that the project has changed.
SCHEMATIC & Schematic() const
void updateTitle()
Set the main window title bar text.
void SetSchematic(SCHEMATIC *aSchematic)
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 RefreshNetNavigator(const NET_NAVIGATOR_ITEM_DATA *aSelection=nullptr)
void RecomputeIntersheetRefs()
Update the schematic's page reference map for all global labels, and refresh the labels so that they ...
void UpdateHierarchyNavigator(bool aRefreshNetNavigator=true, bool aClear=false)
Update the hierarchy navigation tree and history.
bool importFile(const wxString &aFileName, int aFileType, const std::map< std::string, UTF8 > *aProperties=nullptr)
Load the given filename but sets the path to the current project path.
void LoadDrawingSheet()
Load the drawing sheet file.
void SetSheetNumberAndCount()
Set the m_ScreenNumber and m_NumberOfScreens members for screens.
void ClearRepeatItemsList()
Clear the list of items which are to be repeated with the insert key.
wxGenericTreeCtrl * m_netNavigator
void initScreenZoom()
Initialize the zoom value of the current screen and mark the screen as zoom-initialized.
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
wxString GetCurrentFileName() const override
Get the full filename + path of the currently opened file in the frame.
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
bool SaveProject(bool aSaveAs=false)
Save the currently-open schematic (including its hierarchy) and associated project.
void saveProjectSettings() override
Save any design-related project settings associated with this frame.
static const wxString ShowType(SCH_FILE_T aFileType)
Return a brief name for a plugin, given aFileType enum.
static SCH_FILE_T GuessPluginTypeFromSchPath(const wxString &aSchematicPath, int aCtl=0)
Return a plugin type given a schematic using the file extension of aSchematicPath.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
Handle actions specific to the schematic editor.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:746
SCH_SCREEN * GetNext()
SCH_SCREEN * GetScreen(unsigned int aIndex) const
SCH_SCREEN * GetFirst()
void BuildClientSheetPathList()
Build the list of sheet paths sharing a screen for each screen in use.
size_t GetCount() const
Definition sch_screen.h:751
SCH_SHEET * GetSheet(unsigned int aIndex) const
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:185
void TestDanglingEnds(const SCH_SHEET_PATH *aPath=nullptr, std::function< void(SCH_ITEM *)> *aChangedHandler=nullptr) const
Test all of the connectable objects in the schematic for unused connection points.
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
const wxString & GetFileName() const
Definition sch_screen.h:150
void UpdateLocalLibSymbolLinks()
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic with the local projec...
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
const std::vector< SCH_SYMBOL_INSTANCE > & GetSymbolInstances() const
Definition sch_screen.h:519
int GetFileFormatVersionAtLoad() const
Definition sch_screen.h:135
void AssignNewUuid()
Definition sch_screen.h:531
const std::vector< SCH_SHEET_INSTANCE > & GetSheetInstances() const
Definition sch_screen.h:524
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void UpdateSheetInstanceData(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
void SetInitialPageNumbers()
Set initial sheet page numbers.
bool AllSheetPageNumbersEmpty() const
Check all of the sheet instance for empty page numbers.
bool IsModified() const
Check the entire hierarchy for any modifications.
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void CheckForMissingSymbolInstances(const wxString &aProjectName)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void UpdateAllScreenReferences() const
Update all the symbol references for this sheet path.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:376
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:370
wxString GetName() const
Definition sch_sheet.h:136
void SetName(const wxString &aName)
Definition sch_sheet.h:137
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
bool IsVirtualRootSheet() const
Schematic symbol object.
Definition sch_symbol.h:69
void SetLibId(const LIB_ID &aName)
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:158
void SaveProjectAs(const wxString &aFullPath, PROJECT *aProject=nullptr)
Set the currently loaded project path and saves it (pointers remain valid).
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Save a loaded project.
bool SaveProjectCopy(const wxString &aFullPath, PROJECT *aProject=nullptr)
Save a copy of the current project under the given path.
bool LoadProject(const wxString &aFullPath, bool aSetActive=true)
Load a project or sets up a new project with a specified path.
bool UnloadProject(PROJECT *aProject, bool aSave=true)
Save, unload and unregister the given PROJECT.
The SIMULATOR_FRAME holds the main user-interface for running simulations.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
LIB_SYMBOL * LoadSymbol(const wxString &aNickname, const wxString &aName)
Load a LIB_SYMBOL having aName from the library given by aNickname.
std::vector< wxString > GetSymbolNames(const wxString &aNickname, SYMBOL_TYPE aType=SYMBOL_TYPE::ALL_SYMBOLS)
TOOL_MANAGER * m_toolManager
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition tool_base.h:77
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition utf8.h:67
wxString wx_str() const
Definition utf8.cpp:41
Temporarily disable a window, and then re-enable on destruction.
Definition raii.h:83
static void ResolvePossibleSymlinks(wxFileName &aFilename)
void Flush()
Build the HTML messages page.
bool HasMessage() const override
Returns true if any messages were reported.
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:189
const wxString & GetMessages() const
Definition reporter.cpp:101
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:775
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:38
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
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:146
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
static bool empty(const wxTextEntryBase *aCtrl)
#define _(s)
bool PrepareSaveAsFiles(SCHEMATIC &aSchematic, SCH_SCREENS &aScreens, const wxFileName &aOldRoot, const wxFileName &aNewRoot, bool aSaveCopy, bool aCopySubsheets, bool aIncludeExternSheets, std::unordered_map< SCH_SCREEN *, wxString > &aFilenameMap, wxString &aErrorMsg)
void Reset() override
@ FRAME_SIMULATOR
Definition frame_type.h:34
static const std::string LegacySchematicFileExtension
static const std::string ProjectFileExtension
static const std::string LegacyProjectFileExtension
static const std::string KiCadSchematicFileExtension
static const std::string LegacySymbolLibFileExtension
static wxString KiCadSchematicFileWildcard()
const wxChar *const traceSchCurrentSheet
Flag to enable debug output of current sheet tracking in the schematic editor.
const wxChar *const traceAutoSave
Flag to enable auto save feature debug tracing.
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
PROJECT & Prj()
Definition kicad.cpp:730
KIID niluuid(0)
#define KICTL_CREATE
caller thinks requested project files may not exist.
#define KICTL_KICAD_ONLY
chosen file is from KiCad according to user
@ LAYER_BUS
Definition layer_ids.h:451
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:102
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:77
bool MakeWriteable(const wxString &aFilePath)
Ensures that a file has write permissions.
Definition unix/io.cpp:78
void AllowNetworkFileSystems(wxDialog *aDialog)
Configure a file dialog to show network and virtual file systems.
Definition wxgtk/ui.cpp:448
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
@ GLOBAL_CLEANUP
Definition schematic.h:79
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.
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Container that describes file type info.
Definition io_base.h:43
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition io_base.h:47
bool m_CanRead
Whether the IO can read this file type.
Definition io_base.h:52
wxString FileFilter() const
Definition io_base.cpp:40
Implement a participant in the KIWAY alchemy.
Definition kiway.h:152
virtual void PreloadLibraries(KIWAY *aKiway)
Definition kiway.h:275
Information about a top-level schematic sheet.
std::string path
std::vector< std::vector< std::string > > table
wxLogTrace helper definitions.
@ SCH_SYMBOL_T
Definition typeinfo.h:169
@ SCH_SHEET_T
Definition typeinfo.h:172
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:159
wxString formatWildcardExt(const wxString &aWildcard)
Format wildcard extension to support case sensitive file dialogs.
Definition of file extensions used in Kicad.
#define PR_CAN_ABORT