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>
55#include <sch_draw_panel.h>
57#include <sch_file_versions.h>
58#include <sch_line.h>
59#include <sch_sheet.h>
60#include <sch_sheet_path.h>
61#include <schematic.h>
63#include <sim/simulator_frame.h>
64#include <tool/actions.h>
65#include <tool/tool_manager.h>
68#include <trace_helpers.h>
70#include <widgets/kistatusbar.h>
71#include <widgets/wx_infobar.h>
73#include <local_history.h>
75#include <wx/app.h>
76#include <wx/ffile.h>
77#include <wx/filedlg.h>
78#include <wx/log.h>
79#include <wx/richmsgdlg.h>
80#include <wx/stdpaths.h>
83#include <paths.h>
84#include <wx_filename.h> // For ::ResolvePossibleSymlinks
87
88#include <kiplatform/io.h>
89
92#include "save_project_utils.h"
93
94bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, int aCtl )
95{
96 // ensure the splash screen does not obscure any dialog at startup
97 Pgm().HideSplash();
98
99 // implement the pseudo code from KIWAY_PLAYER.h:
100 wxString msg;
101
102 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
103
104 // This is for python:
105 if( aFileSet.size() != 1 )
106 {
107 msg.Printf( "Eeschema:%s() takes only a single filename.", __WXFUNCTION__ );
108 DisplayError( this, msg );
109 return false;
110 }
111
112 wxString fullFileName( aFileSet[0] );
113 wxFileName wx_filename( fullFileName );
114
115 if( !Prj().IsNullProject() )
116 Kiway().LocalHistory().Init( Prj().GetProjectPath() );
117
118 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
119 wxASSERT_MSG( wx_filename.IsAbsolute(), wxS( "Path is not absolute!" ) );
120
121 if( !LockFile( fullFileName ) )
122 {
123 // If project-level lock override was already granted, silently override this file's lock
124 if( Prj().IsLockOverrideGranted() )
125 {
126 m_file_checker->OverrideLock();
127 }
128 else
129 {
130 msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), fullFileName,
131 m_file_checker->GetUsername(), m_file_checker->GetHostname() );
132
133 if( !AskOverrideLock( this, msg ) )
134 return false;
135
136 m_file_checker->OverrideLock();
137 }
138 }
139
140 if( !AskToSaveChanges() )
141 return false;
142
143#ifdef PROFILE
144 PROF_TIMER openFiles( "OpenProjectFile" );
145#endif
146
147 wxFileName pro = fullFileName;
148 pro.SetExt( FILEEXT::ProjectFileExtension );
149
150 bool is_new = !wxFileName::IsFileReadable( fullFileName );
151
152 // If its a non-existent schematic and caller thinks it exists
153 if( is_new && !( aCtl & KICTL_CREATE ) )
154 {
155 // notify user that fullFileName does not exist, ask if user wants to create it.
156 msg.Printf( _( "Schematic '%s' does not exist. Do you wish to create it?" ),
157 fullFileName );
158
159 if( !IsOK( this, msg ) )
160 return false;
161 }
162
163 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGING );
164 ProcessEventLocally( e );
165
166 // unload current project file before loading new
167 {
170 SetScreen( nullptr );
172 }
173
174 SetStatusText( wxEmptyString );
175 m_infoBar->Dismiss();
176
177 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
178 statusBar->ClearWarningMessages( "load" );
179
180 WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Create Schematic" )
181 : _( "Load Schematic" ), 1,
182 PR_CAN_ABORT );
183 WX_STRING_REPORTER loadReporter;
184 LOAD_INFO_REPORTER_SCOPE loadReporterScope( &loadReporter );
185
186 bool differentProject = pro.GetFullPath() != Prj().GetProjectFullName();
187
188 // This is for handling standalone mode schematic changes
189 if( differentProject )
190 {
191 if( !Prj().IsNullProject() )
192 {
195 }
196
197 // disconnect existing project from schematic before we unload the project
198 Schematic().SetProject( nullptr );
199 GetSettingsManager()->UnloadProject( &Prj(), false );
200
201 GetSettingsManager()->LoadProject( pro.GetFullPath() );
202
203 wxFileName legacyPro( pro );
204 legacyPro.SetExt( FILEEXT::LegacyProjectFileExtension );
205
206 // Do not allow saving a project if one doesn't exist. This normally happens if we are
207 // standalone and opening a schematic that has been moved from its project folder.
208 if( !pro.Exists() && !legacyPro.Exists() && !( aCtl & KICTL_CREATE ) )
209 Prj().SetReadOnly();
210 }
211
212 // Crash-recovery: when zip-format autosave is active, look for autosave files newer
213 // than the saved schematic and offer to recover them before any sheet is loaded.
214 if( !is_new )
215 CheckForAutosaveFiles( wx_filename.GetPath(), { FILEEXT::KiCadSchematicFileExtension } );
216
217 // Start a new schematic object now that we sorted out our project
218 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
219
220 SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( fullFileName,
222
223 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
224 {
225 // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
226 // They are already saved in the kiface project object.
227 if( differentProject || !Prj().GetElem( PROJECT::ELEM::LEGACY_SYMBOL_LIBS ) )
228 {
229 // load the libraries here, not in SCH_SCREEN::Draw() which is a context
230 // that will not tolerate DisplayError() dialog since we're already in an
231 // event handler in there.
232 // And when a schematic file is loaded, we need these libs to initialize
233 // some parameters (links to PART LIB, dangling ends ...)
236 }
237 }
238 else
239 {
240 // No legacy symbol libraries including the cache are loaded with the new file format.
242 }
243
244 wxFileName rfn( GetCurrentFileName() );
245 rfn.MakeRelativeTo( Prj().GetProjectPath() );
246 LoadWindowState( rfn.GetFullPath() );
247
248 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Schematic file changes are unsaved" ) );
249
250 if( Kiface().IsSingle() )
251 {
253 }
254
255 if( is_new || schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
256 {
257 newSchematic->CreateDefaultScreens();
258 SetSchematic( newSchematic.release() );
259
260 // mark new, unsaved file as modified.
262 GetScreen()->SetFileName( fullFileName );
263
264 if( schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
265 {
266 msg.Printf( _( "'%s' is not a KiCad schematic file.\nUse File -> Import for "
267 "non-KiCad schematic files." ),
268 fullFileName );
269
270 progressReporter.Hide();
271 DisplayErrorMessage( this, msg );
272 }
273 }
274 else
275 {
276 SetScreen( nullptr );
277
278 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( schFileType ) );
279
280 pi->SetProgressReporter( &progressReporter );
281
282 bool failedLoad = false;
283
284 try
285 {
286 {
287 wxBusyCursor busy;
288 WINDOW_DISABLER raii( this );
289
290 // Check if project file has top-level sheets defined
291 PROJECT_FILE& projectFile = Prj().GetProjectFile();
292 const std::vector<TOP_LEVEL_SHEET_INFO>& topLevelSheets = projectFile.GetTopLevelSheets();
293
294 if( !topLevelSheets.empty() )
295 {
296 std::vector<SCH_SHEET*> loadedSheets;
297
298 // Load each top-level sheet
299 for( const TOP_LEVEL_SHEET_INFO& sheetInfo : topLevelSheets )
300 {
301 wxFileName sheetFileName( Prj().GetProjectPath(), sheetInfo.filename );
302
303 // When loading legacy schematic files, ensure we are referencing the correct extension
304 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
305 sheetFileName.SetExt( FILEEXT::LegacySchematicFileExtension );
306
307 wxString sheetPath = sheetFileName.GetFullPath();
308
309 if( !wxFileName::FileExists( sheetPath ) )
310 {
311 wxLogWarning( wxT( "Top-level sheet file not found: %s" ), sheetPath );
312 continue;
313 }
314
315 SCH_SHEET* sheet = pi->LoadSchematicFile( sheetPath, newSchematic.get() );
316
317 if( sheet )
318 {
319 // Preserve the UUID from the project file, unless it's niluuid which is
320 // just a placeholder meaning "use the UUID from the file"
321 if( sheetInfo.uuid != niluuid )
322 {
323 const_cast<KIID&>( sheet->m_Uuid ) = sheetInfo.uuid;
324 }
325
326 sheet->SetName( sheetInfo.name );
327 loadedSheets.push_back( sheet );
328
329 wxLogTrace( tracePathsAndFiles,
330 wxS( "Loaded top-level sheet '%s' (UUID %s) from %s" ),
331 sheet->GetName(),
332 sheet->m_Uuid.AsString(),
333 sheetPath );
334 }
335 }
336
337 if( !loadedSheets.empty() )
338 {
339 newSchematic->SetTopLevelSheets( loadedSheets );
340 }
341 else
342 {
343 wxLogTrace( tracePathsAndFiles,
344 wxS( "Loaded multi-root schematic with no top-level sheets!" ) );
345 newSchematic->CreateDefaultScreens();
346 }
347 }
348 else
349 {
350 // Legacy single-root format: Load the single root sheet
351 SCH_SHEET* rootSheet = pi->LoadSchematicFile( fullFileName, newSchematic.get() );
352
353 if( rootSheet )
354 {
355 newSchematic->SetTopLevelSheets( { rootSheet } );
356
357 // Make ${SHEETNAME} work on the root sheet until we properly support
358 // naming the root sheet
359 if( SCH_SHEET* topSheet = newSchematic->GetTopLevelSheet() )
360 topSheet->SetName( _( "Root" ) );
361
362 wxLogTrace( tracePathsAndFiles,
363 wxS( "Loaded schematic with root sheet UUID %s" ),
364 rootSheet->m_Uuid.AsString() );
365 wxLogTrace( traceSchCurrentSheet,
366 "After loading: Current sheet path='%s', size=%zu, empty=%d",
367 newSchematic->CurrentSheet().Path().AsString(),
368 newSchematic->CurrentSheet().size(),
369 newSchematic->CurrentSheet().empty() ? 1 : 0 );
370 }
371 else
372 {
373 newSchematic->CreateDefaultScreens();
374 }
375
376 }
377 }
378
379 if( !pi->GetError().IsEmpty() )
380 {
381 DisplayErrorMessage( this, _( "The entire schematic could not be loaded. Errors "
382 "occurred attempting to load hierarchical sheets." ),
383 pi->GetError() );
384 }
385 }
386 catch( const FUTURE_FORMAT_ERROR& ffe )
387 {
388 newSchematic->CreateDefaultScreens();
389 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
390 progressReporter.Hide();
391 DisplayErrorMessage( this, msg, ffe.Problem() );
392
393 failedLoad = true;
394 }
395 catch( const IO_ERROR& ioe )
396 {
397 newSchematic->CreateDefaultScreens();
398 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
399 progressReporter.Hide();
400 DisplayErrorMessage( this, msg, ioe.What() );
401
402 failedLoad = true;
403 }
404 catch( const std::bad_alloc& )
405 {
406 newSchematic->CreateDefaultScreens();
407 msg.Printf( _( "Memory exhausted loading schematic '%s'." ), fullFileName );
408 progressReporter.Hide();
409 DisplayErrorMessage( this, msg, wxEmptyString );
410
411 failedLoad = true;
412 }
413
414 SetSchematic( newSchematic.release() );
415
416 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
417 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
418 // compiled.
419 Raise();
420
421 if( failedLoad )
422 {
423 // Do not leave g_RootSheet == NULL because it is expected to be
424 // a valid sheet. Therefore create a dummy empty root sheet and screen.
427
428 // Show any messages collected before the failure
429 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
430 statusBar->AddWarningMessages( "load", loadReporter.GetMessages() );
431
432 msg.Printf( _( "Failed to load '%s'." ), fullFileName );
433 SetMsgPanel( wxEmptyString, msg );
434
435 return false;
436 }
437
438 // Load project settings after schematic has been set up with the project link, since this will
439 // update some of the needed schematic settings such as drawing defaults
441
442 SCH_SHEET_LIST sheetList = Schematic().Hierarchy();
443
444 bool repairedPageNumbers = false;
445
446 if( sheetList.AllSheetPageNumbersEmpty() )
447 sheetList.SetInitialPageNumbers();
448 else
449 repairedPageNumbers = sheetList.RepairPageNumbers();
450
451 // It's possible the schematic parser fixed errors due to bugs, or that we reassigned
452 // duplicate or blank sheet page numbers, so warn the user that the schematic has been
453 // fixed (modified).
454 if( sheetList.IsModified() || repairedPageNumbers )
455 {
456 DisplayInfoMessage( this,
457 _( "An error was found when loading the schematic that has "
458 "been automatically fixed. Please save the schematic to "
459 "repair the broken file or it may not be usable with other "
460 "versions of KiCad." ) );
461 }
462
463 UpdateFileHistory( fullFileName );
464
465 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
466 statusBar->AddWarningMessages( "load", loadReporter.GetMessages() );
467
468 SCH_SCREENS schematic( Schematic().Root() );
469
470 // LIB_ID checks and symbol rescue only apply to the legacy file formats.
471 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
472 {
473 // Convert any legacy bus-bus entries to just be bus wires
474 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
475 {
476 std::vector<SCH_ITEM*> deleted;
477
478 for( SCH_ITEM* item : screen->Items() )
479 {
480 if( item->Type() == SCH_BUS_BUS_ENTRY_T )
481 {
482 SCH_BUS_BUS_ENTRY* entry = static_cast<SCH_BUS_BUS_ENTRY*>( item );
483 std::unique_ptr<SCH_LINE> wire = std::make_unique<SCH_LINE>();
484
485 wire->SetLayer( LAYER_BUS );
486 wire->SetStartPoint( entry->GetPosition() );
487 wire->SetEndPoint( entry->GetEnd() );
488
489 screen->Append( wire.release() );
490 deleted.push_back( item );
491 }
492 }
493
494 for( SCH_ITEM* item : deleted )
495 screen->Remove( item );
496 }
497
498
499 // Convert old projects over to use symbol library table.
500 if( schematic.HasNoFullyDefinedLibIds() )
501 {
502 DIALOG_SYMBOL_REMAP dlgRemap( this );
503
504 dlgRemap.ShowQuasiModal();
505 }
506 else
507 {
508 // Double check to ensure no legacy library list entries have been
509 // added to the project file symbol library list.
510 wxString paths;
511 wxArrayString libNames;
512
513 LEGACY_SYMBOL_LIBS::GetLibNamesAndPaths( &Prj(), &paths, &libNames );
514
515 if( !libNames.IsEmpty() )
516 {
517 if( eeconfig()->m_Appearance.show_illegal_symbol_lib_dialog )
518 {
519 wxRichMessageDialog invalidLibDlg(
520 this,
521 _( "Illegal entry found in project file symbol library list." ),
522 _( "Project Load Warning" ),
523 wxOK | wxCENTER | wxICON_EXCLAMATION );
524 invalidLibDlg.ShowDetailedText(
525 _( "Symbol libraries defined in the project file symbol library "
526 "list are no longer supported and will be removed.\n\n"
527 "This may cause broken symbol library links under certain "
528 "conditions." ) );
529 invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
530 invalidLibDlg.ShowModal();
532 !invalidLibDlg.IsCheckBoxChecked();
533 }
534
535 libNames.Clear();
536 paths.Clear();
537 LEGACY_SYMBOL_LIBS::SetLibNamesAndPaths( &Prj(), paths, libNames );
538 }
539
540 // Check for cache file
541 wxFileName cacheFn( fullFileName );
542 cacheFn.SetName( cacheFn.GetName() + "-cache" );
544 bool cacheExists = cacheFn.FileExists();
545
546 if( cacheExists )
547 {
549 std::optional<LIBRARY_TABLE*> table = adapter->ProjectTable();
550
551 if( table && *table )
552 {
553 wxString nickname = Prj().GetProjectName() + "-cache";
554
555 if( !(*table)->HasRow( nickname ) )
556 {
557 LIBRARY_TABLE_ROW& row = (*table)->InsertRow();
558 row.SetNickname( nickname );
559 row.SetURI( cacheFn.GetFullPath() );
560 row.SetType( SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) );
561 row.SetDescription( _( "Legacy project cache library" ) );
562 (*table)->Save();
563 }
564
565 std::vector<wxString> cacheSymbols = adapter->GetSymbolNames( nickname );
566 std::set<wxString> cacheSymbolSet( cacheSymbols.begin(), cacheSymbols.end() );
567
568 if( !cacheSymbolSet.empty() )
569 {
570 std::vector<wxString> loadedLibs;
571
572 for( const wxString& libName : adapter->GetLibraryNames() )
573 {
574 if( libName == nickname )
575 continue;
576
577 std::optional<LIB_STATUS> status = adapter->GetLibraryStatus( libName );
578
579 if( status && status->load_status == LOAD_STATUS::LOADED )
580 loadedLibs.push_back( libName );
581 }
582
583 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
584 {
585 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
586 {
587 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
588 LIB_ID newId = symbol->GetLibId();
589 UTF8 fullLibName = newId.Format();
590
591 if( cacheSymbolSet.count( fullLibName.wx_str() ) )
592 {
593 bool alreadyExists = false;
594
595 for( const wxString& libName : loadedLibs )
596 {
597 if( adapter->LoadSymbol( libName, fullLibName.wx_str() ) )
598 {
599 alreadyExists = true;
600 break;
601 }
602 }
603
604 if( !alreadyExists )
605 {
606 newId.SetLibNickname( nickname );
607 newId.SetLibItemName( fullLibName );
608 symbol->SetLibId( newId );
609 }
610 }
611 }
612 }
613 }
614 }
615 }
616
617 if( ( !cfg || !cfg->m_RescueNeverShow ) && !cacheExists )
618 {
620 editor->RescueSymbolLibTableProject( false );
621 }
622 }
623
624 // Ensure there is only one legacy library loaded and that it is the cache library.
625 LEGACY_SYMBOL_LIBS* legacyLibs = PROJECT_SCH::LegacySchLibs( &Schematic().Project() );
626
627 if( legacyLibs->GetLibraryCount() == 0 )
628 {
629 wxString extMsg;
630 wxFileName cacheFn = pro;
631
632 wxLogTrace( traceAutoSave, "[SetName dbg] cacheFn BEFORE path='%s' name='%s' full='%s' arg='%s'",
633 cacheFn.GetPath(), cacheFn.GetName(), cacheFn.GetFullPath(), cacheFn.GetName() + "-cache" );
634 cacheFn.SetName( cacheFn.GetName() + "-cache" );
635 wxLogTrace( traceAutoSave, "[SetName dbg] cacheFn AFTER path='%s' name='%s' full='%s'",
636 cacheFn.GetPath(), cacheFn.GetName(), cacheFn.GetFullPath() );
638
639 msg.Printf( _( "The project symbol library cache file '%s' was not found." ),
640 cacheFn.GetFullName() );
641 extMsg = _( "This can result in a broken schematic under certain conditions. "
642 "If the schematic does not have any missing symbols upon opening, "
643 "save it immediately before making any changes to prevent data "
644 "loss. If there are missing symbols, either manual recovery of "
645 "the schematic or recovery of the symbol cache library file and "
646 "reloading the schematic is required." );
647
648 KICAD_MESSAGE_DIALOG dlgMissingCache( this, msg, _( "Warning" ),
649 wxOK | wxCANCEL | wxICON_EXCLAMATION | wxCENTER );
650 dlgMissingCache.SetExtendedMessage( extMsg );
651 dlgMissingCache.SetOKCancelLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Load Without Cache File" ) ),
652 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Abort" ) ) );
653
654 if( dlgMissingCache.ShowModal() == wxID_CANCEL )
655 {
656 Schematic().Reset();
658 return false;
659 }
660 }
661
662 // Update all symbol library links for all sheets.
663 schematic.UpdateSymbolLinks( &loadReporter );
664
665 m_infoBar->RemoveAllButtons();
666 m_infoBar->AddCloseButton();
667 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
668 "It will be converted to the new format when saved." ),
669 wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
670
671 // Legacy schematic can have duplicate time stamps so fix that before converting
672 // to the s-expression format.
673 schematic.ReplaceDuplicateTimeStamps();
674
675 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
676 screen->FixLegacyPowerSymbolMismatches();
677
678 // Allow the schematic to be saved to new file format without making any edits.
679 OnModify();
680 }
681 else // S-expression schematic.
682 {
683 SCH_SCREEN* first_screen = schematic.GetFirst();
684
685 // Skip the first screen as it is a virtual root with no version info.
686 if( first_screen && first_screen->GetFileFormatVersionAtLoad() == 0 )
687 first_screen = schematic.GetNext();
688
689 if( first_screen && first_screen->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
690 {
691 m_infoBar->RemoveAllButtons();
692 m_infoBar->AddCloseButton();
693 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
694 "It will be converted to the new format when saved." ),
695 wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
696 }
697
698 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
700
701 SCH_SCREEN* rootScreen = Schematic().RootScreen();
702
703 // Restore all of the loaded symbol and sheet instances from the root sheet.
704 if( rootScreen && rootScreen->GetFileFormatVersionAtLoad() < 20221002 )
705 sheetList.UpdateSymbolInstanceData( rootScreen->GetSymbolInstances() );
706
707 if( rootScreen && rootScreen->GetFileFormatVersionAtLoad() < 20221110 )
708 sheetList.UpdateSheetInstanceData( rootScreen->GetSheetInstances());
709
710 if( rootScreen && rootScreen->GetFileFormatVersionAtLoad() < 20230221 )
711 for( SCH_SCREEN* screen = schematic.GetFirst(); screen;
712 screen = schematic.GetNext() )
713 screen->FixLegacyPowerSymbolMismatches();
714
715 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
716 screen->MigrateSimModels();
717
719 UpdateVariantSelectionCtrl( Schematic().GetVariantNamesForUI() );
720 }
721
722 // After the schematic is successfully loaded, we load the drawing sheet.
723 // This allows us to use the drawing sheet embedded in the schematic (if any)
724 // instead of the default one.
726
727 wxLogTrace( traceSchCurrentSheet,
728 "Before CheckForMissingSymbolInstances: Current sheet path='%s', size=%zu",
729 GetCurrentSheet().Path().AsString(),
730 GetCurrentSheet().size() );
731
732 // Check must run before pruning so variant data on a stale instance path is migrated
733 // onto the new instance before the orphan is removed.
734 sheetList.CheckForMissingSymbolInstances( Prj().GetProjectName() );
735
736 schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), sheetList );
737 schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), sheetList );
738
740
741 SetScreen( GetCurrentSheet().LastScreen() );
742
743 // Repaired page numbers changed in-memory sheet instances; flag the schematic so the
744 // fixed numbering can be saved instead of silently reverting on the next load.
745 if( repairedPageNumbers )
746 OnModify();
747
748 wxLogTrace( traceSchCurrentSheet,
749 "After SetScreen: Current sheet path='%s', size=%zu",
750 GetCurrentSheet().Path().AsString(),
751 GetCurrentSheet().size() );
752
753 SCH_COMMIT dummy( this );
754
755 progressReporter.Report( _( "Updating connections..." ) );
756 progressReporter.KeepRefreshing();
757
758 RecalculateConnections( &dummy, GLOBAL_CLEANUP, &progressReporter );
759
760 // Migrate conflicting bus definitions, but only for files old enough to store them.
761 // The connection graph must be rebuilt first so GetBusesNeedingMigration() can see the
762 // conflicting subgraphs; the earlier Reset() clears them.
763 SCH_SCREEN* schRootScreen = Schematic().RootScreen();
764 int schFileVersion = schRootScreen ? schRootScreen->GetFileFormatVersionAtLoad() : 0;
765
767 schFileVersion, Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() ) )
768 {
769 progressReporter.Hide();
770
771 // The rebuild below frees the subgraphs the dialog caches, and a progress update can
772 // dispatch queued UI events into its still-bound handlers, so destroy the dialog first.
773 {
774 DIALOG_MIGRATE_BUSES dlg( this );
775 dlg.ShowQuasiModal();
776 }
777
778 OnModify();
779 progressReporter.Show();
780
781 // Relabeling the conflicting buses changes connectivity, so rebuild it.
782 RecalculateConnections( &dummy, GLOBAL_CLEANUP, &progressReporter );
783 }
784
785 if( schematic.HasSymbolFieldNamesWithWhiteSpace() )
786 {
787 m_infoBar->QueueShowMessage( _( "This schematic contains symbols that have leading "
788 "and/or trailing white space field names." ),
789 wxICON_WARNING );
790 }
791 }
792
793 // Load any exclusions from the project file
795
798
801
802 // Re-create junctions if needed. Eeschema optimizes wires by merging
803 // colinear segments. If a schematic is saved without a valid
804 // cache library or missing installed libraries, this can cause connectivity errors
805 // unless junctions are added.
806 //
807 // TODO: (RFB) This really needs to be put inside the Load() function of the SCH_IO_KICAD_LEGACY
808 // I can't put it right now because of the extra code that is above to convert legacy bus-bus
809 // entries to bus wires
810 //
811 // A native s-expression schematic written by an older version can drop the junctions implied
812 // by merged colinear wires, so the fixup also runs for pre-current native files. It is limited
813 // to older files because the current version writes those junctions on save; running it on a
814 // current file could silently connect an intentional wire crossing and mask an
815 // ERCE_LABEL_MULTIPLE_WIRES violation. It is idempotent and only adds needed junctions.
816 bool nativeNeedsFixup = schFileType == SCH_IO_MGR::SCH_KICAD
819
820 if( schFileType == SCH_IO_MGR::SCH_LEGACY || nativeNeedsFixup )
822
823 SyncView();
825
827
828 UpdateHierarchyNavigator( false, true );
829 CallAfter(
830 [this]()
831 {
832 if( m_netNavigator && m_netNavigator->IsEmpty() )
833 {
835 }
836 } );
837
838 wxCommandEvent changedEvt( EDA_EVT_SCHEMATIC_CHANGED );
839 ProcessEventLocally( changedEvt );
840
841 if( !differentProject )
842 {
843 // If we didn't reload the project, we still need to call ProjectChanged() to ensure
844 // frame-specific initialization happens (like registering the autosave saver).
845 // When running under the project manager, KIWAY::ProjectChanged() was called before
846 // this frame existed, so we need to call our own ProjectChanged() now.
848 }
849
850 for( wxEvtHandler* listener : m_schematicChangeListeners )
851 {
852 wxCHECK2( listener, continue );
853
854 // Use the windows variant when handling event messages in case there is any special
855 // event handler pre and/or post processing specific to windows.
856 wxWindow* win = dynamic_cast<wxWindow*>( listener );
857
858 if( win )
859 win->HandleWindowEvent( e );
860 else
861 listener->SafelyProcessEvent( e );
862 }
863
864 updateTitle();
865 m_toolManager->GetTool<SCH_NAVIGATE_TOOL>()->ResetHistory();
866
867 wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
868
869 if( fn.FileExists() && !fn.IsFileWritable() )
870 {
871 m_infoBar->RemoveAllButtons();
872 m_infoBar->AddCloseButton();
873 m_infoBar->ShowMessage( _( "Schematic is read only." ),
874 wxICON_WARNING, WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE );
875 }
876
877#ifdef PROFILE
878 openFiles.Show();
879#endif
880 // Ensure all items are redrawn (especially the drawing-sheet items):
881 if( GetCanvas() )
882 GetCanvas()->DisplaySheet( GetCurrentSheet().LastScreen() );
883
884 // Trigger a library load to handle any project-specific libraries
885 CallAfter( [&]()
886 {
887 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
888 schface->PreloadLibraries( &Kiway() );
889
891 } );
892
893 m_remoteSymbolPane->BindWebViewLoaded();
894
895 return true;
896}
897
898
900{
901 if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
902 {
903 wxString msg = _( "This operation replaces the contents of the current schematic, "
904 "which will be permanently lost.\n\n"
905 "Do you want to proceed?" );
906
907 if( !IsOK( this, msg ) )
908 return;
909 }
910
911 // Set the project location if none is set or if we are running in standalone mode
912 bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
913 wxString path = wxPathOnly( Prj().GetProjectFullName() );
914
915 wxString fileFiltersStr;
916 wxString allWildcardsStr;
917
918 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
919 {
920 if( fileType == SCH_IO_MGR::SCH_KICAD || fileType == SCH_IO_MGR::SCH_LEGACY )
921 continue; // this is "Import non-KiCad schematic"
922
923 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
924
925 if( !pi )
926 continue;
927
928 const IO_BASE::IO_FILE_DESC& desc = pi->GetSchematicFileDesc();
929
930 if( desc.m_FileExtensions.empty() || !desc.m_CanRead )
931 continue;
932
933 if( !fileFiltersStr.IsEmpty() )
934 fileFiltersStr += wxChar( '|' );
935
936 fileFiltersStr += desc.FileFilter();
937
938 for( const std::string& ext : desc.m_FileExtensions )
939 allWildcardsStr << wxS( "*." ) << formatWildcardExt( ext ) << wxS( ";" );
940 }
941
942 fileFiltersStr = _( "All supported formats" ) + wxS( "|" ) + allWildcardsStr + wxS( "|" )
943 + fileFiltersStr;
944
945 wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFiltersStr,
946 wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
947
948 FILEDLG_IMPORT_NON_KICAD importOptions( eeconfig()->m_System.show_import_issues );
949 dlg.SetCustomizeHook( importOptions );
950
952
953 if( dlg.ShowModal() == wxID_CANCEL )
954 return;
955
957
958 // Don't leave dangling pointers to previously-opened document.
959 m_toolManager->GetTool<SCH_SELECTION_TOOL>()->ClearSelection();
962
963 if( setProject )
964 {
965 Schematic().SetProject( nullptr );
966 GetSettingsManager()->UnloadProject( &Prj(), false );
967
968 // Clear view before destroying schematic as repaints depend on schematic being valid
969 SetScreen( nullptr );
970
971 Schematic().Reset();
972
973 wxFileName projectFn( dlg.GetPath() );
974 projectFn.SetExt( FILEEXT::ProjectFileExtension );
975 GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
976 }
977
978 wxFileName fn = dlg.GetPath();
979
980 if( !fn.IsFileReadable() )
981 {
982 wxLogError( _( "Insufficient permissions to read file '%s'." ), fn.GetFullPath() );
983 return;
984 }
985
986 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN;
987
988 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
989 {
990 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
991
992 if( !pi )
993 continue;
994
995 if( pi->CanReadSchematicFile( fn.GetFullPath() ) )
996 {
997 pluginType = fileType;
998 break;
999 }
1000 }
1001
1002 if( pluginType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
1003 {
1004 wxLogError( _( "No loader can read the specified file: '%s'." ), fn.GetFullPath() );
1006 SetScreen( Schematic().RootScreen() );
1007 return;
1008 }
1009
1010 importFile( dlg.GetPath(), pluginType );
1011
1012 RefreshCanvas();
1013}
1014
1015
1016bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSavePath )
1017{
1018 wxString msg;
1019 wxFileName schematicFileName;
1020 wxFileName oldFileName;
1021 bool success;
1022
1023 SCH_SCREEN* screen = aSheet->GetScreen();
1024
1025 wxCHECK( screen, false );
1026
1027 // Cannot save to nowhere
1028 if( aSavePath.IsEmpty() )
1029 return false;
1030
1031 // Construct the name of the file to be saved
1032 schematicFileName = Prj().AbsolutePath( aSavePath );
1033 oldFileName = schematicFileName;
1034
1035 // Write through symlinks, don't replace them
1036 WX_FILENAME::ResolvePossibleSymlinks( schematicFileName );
1037
1038 if( !schematicFileName.DirExists() )
1039 {
1040 if( !wxMkdir( schematicFileName.GetPath() ) )
1041 {
1042 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
1043 schematicFileName.GetFullPath(),
1044 "Could not create directory: %s" + schematicFileName.GetPath() );
1045 DisplayError( this, msg );
1046
1047 return false;
1048 }
1049 }
1050
1051 if( !IsWritable( schematicFileName ) )
1052 return false;
1053
1054 wxFileName projectFile( schematicFileName );
1055
1056 projectFile.SetExt( FILEEXT::ProjectFileExtension );
1057
1058 if( projectFile.FileExists() )
1059 {
1060 // Save various ERC settings, such as violation severities (which may have been edited
1061 // via the ERC dialog as well as the Schematic Setup dialog), ERC exclusions, etc.
1063 }
1064
1065 // Save
1066 wxLogTrace( traceAutoSave, wxS( "Saving file " ) + schematicFileName.GetFullPath() );
1067
1068 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1069 m_infoBar->Dismiss();
1070
1071 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
1072 schematicFileName.GetFullPath() );
1073
1074 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1075 pluginType = SCH_IO_MGR::SCH_KICAD;
1076
1077 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1078
1079 // On Windows, ensure the target file is writeable by clearing problematic attributes like
1080 // hidden or read-only. This can happen when files are synced via cloud services.
1081 if( schematicFileName.FileExists() )
1082 KIPLATFORM::IO::MakeWriteable( schematicFileName.GetFullPath() );
1083
1084 try
1085 {
1086 pi->SaveSchematicFile( schematicFileName.GetFullPath(), aSheet, &Schematic() );
1087 success = true;
1088 }
1089 catch( const IO_ERROR& ioe )
1090 {
1091 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
1092 schematicFileName.GetFullPath(),
1093 ioe.What() );
1094 DisplayError( this, msg );
1095
1096 success = false;
1097 }
1098
1099 if( success )
1100 {
1101 screen->SetContentModified( false );
1102
1103 msg.Printf( _( "File '%s' saved." ), screen->GetFileName() );
1104 SetStatusText( msg, 0 );
1105 }
1106
1107 return success;
1108}
1109
1110
1111bool PrepareSaveAsFiles( SCHEMATIC& aSchematic, SCH_SCREENS& aScreens,
1112 const wxFileName& aOldRoot, const wxFileName& aNewRoot,
1113 bool aSaveCopy, bool aCopySubsheets, bool aIncludeExternSheets,
1114 std::unordered_map<SCH_SCREEN*, wxString>& aFilenameMap,
1115 wxString& aErrorMsg )
1116{
1117 SCH_SCREEN* screen;
1118
1119 for( size_t i = 0; i < aScreens.GetCount(); i++ )
1120 {
1121 screen = aScreens.GetScreen( i );
1122
1123 wxCHECK2( screen, continue );
1124
1125 if( screen == aSchematic.RootScreen() )
1126 continue;
1127
1128 wxFileName src = screen->GetFileName();
1129
1130 if( !src.IsAbsolute() )
1131 src.MakeAbsolute( aOldRoot.GetPath() );
1132
1133 bool internalSheet = src.GetPath().StartsWith( aOldRoot.GetPath() );
1134
1135 if( aCopySubsheets && ( internalSheet || aIncludeExternSheets ) )
1136 {
1137 wxFileName dest = src;
1138
1139 if( internalSheet && dest.MakeRelativeTo( aOldRoot.GetPath() ) )
1140 dest.MakeAbsolute( aNewRoot.GetPath() );
1141 else
1142 dest.Assign( aNewRoot.GetPath(), dest.GetFullName() );
1143
1144 wxLogTrace( tracePathsAndFiles,
1145 wxS( "Moving schematic from '%s' to '%s'." ),
1146 screen->GetFileName(),
1147 dest.GetFullPath() );
1148
1149 if( !dest.DirExists() && !dest.Mkdir() )
1150 {
1151 aErrorMsg.Printf( _( "Folder '%s' could not be created.\n\n"
1152 "Make sure you have write permissions and try again." ),
1153 dest.GetPath() );
1154 return false;
1155 }
1156
1157 if( aSaveCopy )
1158 aFilenameMap[screen] = dest.GetFullPath();
1159 else
1160 screen->SetFileName( dest.GetFullPath() );
1161 }
1162 else
1163 {
1164 if( aSaveCopy )
1165 aFilenameMap[screen] = wxString();
1166
1167 screen->SetFileName( src.GetFullPath() );
1168 }
1169 }
1170
1171 for( SCH_SHEET_PATH& sheet : aSchematic.Hierarchy() )
1172 {
1173 if( !sheet.Last()->IsTopLevelSheet() )
1174 sheet.MakeFilePathRelativeToParentSheet();
1175 }
1176
1177 return true;
1178}
1179
1181{
1182 wxString msg;
1183 SCH_SCREEN* screen;
1184 SCH_SCREENS screens( Schematic().Root() );
1185 bool saveCopy = aSaveAs && !Kiface().IsSingle();
1186 bool success = true;
1187 bool updateFileHistory = false;
1188 bool createNewProject = false;
1189 bool copySubsheets = false;
1190 bool includeExternSheets = false;
1191
1192 // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
1193 wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
1194 wxFileName fn = fileName;
1195
1196 // Path to save each screen to: will be the stored filename by default, but is overwritten by
1197 // a Save As Copy operation.
1198 std::unordered_map<SCH_SCREEN*, wxString> filenameMap;
1199
1200 // Handle "Save As" and saving a new project/schematic for the first time in standalone
1201 if( Prj().IsNullProject() || aSaveAs )
1202 {
1203 // Null project should only be possible in standalone mode.
1204 wxCHECK( Kiface().IsSingle() || aSaveAs, false );
1205
1206 wxFileName newFileName;
1207 wxFileName savePath( Prj().GetProjectFullName() );
1208
1209 if( !savePath.IsOk() || !savePath.IsDirWritable() )
1210 {
1211 savePath = GetMruPath();
1212
1213 if( !savePath.IsOk() || !savePath.IsDirWritable() )
1215 }
1216
1217 if( savePath.HasExt() )
1218 savePath.SetExt( FILEEXT::KiCadSchematicFileExtension );
1219 else
1220 savePath.SetName( wxEmptyString );
1221
1222 wxFileDialog dlg( this, _( "Schematic Files" ), savePath.GetPath(), savePath.GetFullName(),
1224 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1225
1226 FILEDLG_HOOK_SAVE_PROJECT newProjectHook;
1227
1228 // Add a "Create a project" checkbox in standalone mode and one isn't loaded
1229 if( Kiface().IsSingle() || aSaveAs )
1230 {
1231 dlg.SetCustomizeHook( newProjectHook );
1232 }
1233
1235
1236 if( dlg.ShowModal() == wxID_CANCEL )
1237 return false;
1238
1239 newFileName = EnsureFileExtension( dlg.GetPath(), FILEEXT::KiCadSchematicFileExtension );
1240
1241 if( ( !newFileName.DirExists() && !newFileName.Mkdir() ) ||
1242 !newFileName.IsDirWritable() )
1243 {
1244 msg.Printf( _( "Folder '%s' could not be created.\n\n"
1245 "Make sure you have write permissions and try again." ),
1246 newFileName.GetPath() );
1247
1248 KICAD_MESSAGE_DIALOG dlgBadPath( this, msg, _( "Error" ),
1249 wxOK | wxICON_EXCLAMATION | wxCENTER );
1250
1251 dlgBadPath.ShowModal();
1252 return false;
1253 }
1254
1255 if( newProjectHook.IsAttachedToDialog() )
1256 {
1257 createNewProject = newProjectHook.GetCreateNewProject();
1258 copySubsheets = newProjectHook.GetCopySubsheets();
1259 includeExternSheets = newProjectHook.GetIncludeExternSheets();
1260 }
1261
1262 if( !saveCopy )
1263 {
1264 Schematic().Root().SetFileName( newFileName.GetFullName() );
1265 Schematic().RootScreen()->SetFileName( newFileName.GetFullPath() );
1266 updateFileHistory = true;
1267 }
1268 else
1269 {
1270 filenameMap[Schematic().RootScreen()] = newFileName.GetFullPath();
1271 }
1272
1273 if( !PrepareSaveAsFiles( Schematic(), screens, fn, newFileName, saveCopy,
1274 copySubsheets, includeExternSheets, filenameMap, msg ) )
1275 {
1276 KICAD_MESSAGE_DIALOG dlgBadFilePath( this, msg, _( "Error" ),
1277 wxOK | wxICON_EXCLAMATION | wxCENTER );
1278
1279 dlgBadFilePath.ShowModal();
1280 return false;
1281 }
1282 }
1283 else if( !fn.FileExists() )
1284 {
1285 // File doesn't exist yet; true if we just imported something
1286 updateFileHistory = true;
1287 }
1288 else if( screens.GetFirst() && screens.GetFirst()->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
1289 {
1290 // Allow the user to save un-edited files in new format
1291 }
1292 else if( !IsContentModified() )
1293 {
1294 return true;
1295 }
1296
1297 if( filenameMap.empty() || !saveCopy )
1298 {
1299 for( size_t i = 0; i < screens.GetCount(); i++ )
1300 filenameMap[screens.GetScreen( i )] = screens.GetScreen( i )->GetFileName();
1301 }
1302
1303 // Warn user on potential file overwrite. This can happen on shared sheets.
1304 wxArrayString overwrittenFiles;
1305 wxArrayString lockedFiles;
1306
1307 for( size_t i = 0; i < screens.GetCount(); i++ )
1308 {
1309 screen = screens.GetScreen( i );
1310
1311 wxCHECK2( screen, continue );
1312
1313 // Convert legacy schematics file name extensions for the new format.
1314 wxFileName tmpFn = filenameMap[screen];
1315
1316 if( !tmpFn.IsOk() )
1317 continue;
1318
1319 if( tmpFn.FileExists() && !tmpFn.IsFileWritable() )
1320 lockedFiles.Add( tmpFn.GetFullPath() );
1321
1322 if( tmpFn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1323 continue;
1324
1326
1327 if( tmpFn.FileExists() )
1328 overwrittenFiles.Add( tmpFn.GetFullPath() );
1329 }
1330
1331 if( !lockedFiles.IsEmpty() )
1332 {
1333 for( const wxString& lockedFile : lockedFiles )
1334 {
1335 if( msg.IsEmpty() )
1336 msg = lockedFile;
1337 else
1338 msg += "\n" + lockedFile;
1339 }
1340
1341 wxRichMessageDialog dlg( this, wxString::Format( _( "Failed to save %s." ),
1342 Schematic().Root().GetFileName() ),
1343 _( "Locked File Warning" ),
1344 wxOK | wxICON_WARNING | wxCENTER );
1345 dlg.SetExtendedMessage( _( "You do not have write permissions to:\n\n" ) + msg );
1346
1347 dlg.ShowModal();
1348 return false;
1349 }
1350
1351 if( !overwrittenFiles.IsEmpty() )
1352 {
1353 for( const wxString& overwrittenFile : overwrittenFiles )
1354 {
1355 if( msg.IsEmpty() )
1356 msg = overwrittenFile;
1357 else
1358 msg += "\n" + overwrittenFile;
1359 }
1360
1361 wxRichMessageDialog dlg( this, _( "Saving will overwrite existing files." ),
1362 _( "Save Warning" ),
1363 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER |
1364 wxICON_EXCLAMATION );
1365 dlg.ShowDetailedText( _( "The following files will be overwritten:\n\n" ) + msg );
1366 dlg.SetOKCancelLabels( KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Overwrite Files" ) ),
1367 KICAD_MESSAGE_DIALOG::ButtonLabel( _( "Abort Project Save" ) ) );
1368
1369 if( dlg.ShowModal() == wxID_CANCEL )
1370 return false;
1371 }
1372
1373 screens.BuildClientSheetPathList();
1374
1375 std::vector<wxString> savedSheetPaths;
1376
1377 for( size_t i = 0; i < screens.GetCount(); i++ )
1378 {
1379 screen = screens.GetScreen( i );
1380
1381 wxCHECK2( screen, continue );
1382
1383 // Convert legacy schematics file name extensions for the new format.
1384 wxFileName tmpFn = filenameMap[screen];
1385
1386 if( tmpFn.IsOk() && tmpFn.GetExt() != FILEEXT::KiCadSchematicFileExtension )
1387 {
1388 updateFileHistory = true;
1390
1391 for( EDA_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
1392 {
1393 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1394 wxFileName sheetFileName = sheet->GetFileName();
1395
1396 if( !sheetFileName.IsOk()
1397 || sheetFileName.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1398 continue;
1399
1400 sheetFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
1401 sheet->SetFileName( sheetFileName.GetFullPath() );
1402 UpdateItem( sheet );
1403 }
1404
1405 filenameMap[screen] = tmpFn.GetFullPath();
1406
1407 if( !saveCopy )
1408 screen->SetFileName( tmpFn.GetFullPath() );
1409 }
1410
1411 // Do not save sheet symbols with no valid filename set
1412 if( !tmpFn.IsOk() )
1413 continue;
1414
1415 std::vector<SCH_SHEET_PATH>& sheets = screen->GetClientSheetPaths();
1416
1417 if( sheets.size() == 1 )
1418 screen->SetVirtualPageNumber( 1 );
1419 else
1420 screen->SetVirtualPageNumber( 0 ); // multiple uses; no way to store the real sheet #
1421
1422 // This is a new schematic file so make sure it has a unique ID.
1423 if( !saveCopy && tmpFn.GetFullPath() != screen->GetFileName() )
1424 screen->AssignNewUuid();
1425
1426 bool savedThisSheet = saveSchematicFile( screens.GetSheet( i ), tmpFn.GetFullPath() );
1427
1428 if( savedThisSheet )
1429 savedSheetPaths.push_back( tmpFn.GetFullPath() );
1430
1431 success &= savedThisSheet;
1432 }
1433
1434 if( success )
1435 {
1436 if( m_autoSaveTimer )
1437 m_autoSaveTimer->Stop();
1438
1439 m_autoSavePending = false;
1440 m_autoSaveRequired = false;
1441 }
1442
1443 if( aSaveAs && success )
1444 LockFile( Schematic().RootScreen()->GetFileName() );
1445
1446 if( updateFileHistory )
1447 UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
1448
1449 // Save the sheet name map to the project file
1450 std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
1451 sheets.clear();
1452
1453 for( SCH_SHEET_PATH& sheetPath : Schematic().Hierarchy() )
1454 {
1455 SCH_SHEET* sheet = sheetPath.Last();
1456
1457 wxCHECK2( sheet, continue );
1458
1459 // Do not save the virtual root sheet
1460 if( !sheet->IsVirtualRootSheet() )
1461 {
1462 sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
1463 }
1464 }
1465
1466 wxASSERT( filenameMap.count( Schematic().RootScreen() ) );
1467 wxFileName projectPath( filenameMap.at( Schematic().RootScreen() ) );
1468 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1469
1470 if( Prj().IsNullProject() || ( aSaveAs && !saveCopy ) )
1471 {
1472 Prj().SetReadOnly( !createNewProject );
1473 GetSettingsManager()->SaveProjectAs( projectPath.GetFullPath() );
1474 }
1475 else if( saveCopy && createNewProject )
1476 {
1477 GetSettingsManager()->SaveProjectCopy( projectPath.GetFullPath() );
1478 }
1479 else
1480 {
1483 }
1484
1485 // Record a full project snapshot so related files (symbols, libs, sheets) are captured.
1486 // Skip when running standalone without a project loaded - the save path can land
1487 // anywhere on the filesystem and there is no project context for a snapshot.
1488 if( success && !Prj().IsNullProject() )
1489 {
1490 Kiway().LocalHistory().RunRegisteredSaversAndCommit( Prj().GetProjectPath(), wxS( "SCH Save" ), wxS( "sch" ) );
1491
1492 // Drop the autosave files for the sheets we just persisted. Scope to those
1493 // sources so other dirty sheets (and any open PCB) keep their autosaves until
1494 // they are saved themselves; otherwise a Save All across editors would lose
1495 // recovery data for files this save did not write.
1496 // RunRegisteredSaversAndCommit above is a no-op when format is ZIP, and
1497 // RemoveAutosaveFiles is conversely a no-op in INCREMENTAL mode.
1498 Kiway().LocalHistory().RemoveAutosaveFiles( Prj().GetProjectPath(), savedSheetPaths );
1499 }
1500
1501 if( !Kiface().IsSingle() )
1502 {
1503 WX_STRING_REPORTER backupReporter;
1504
1505 if( !GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1506 SetStatusText( backupReporter.GetMessages(), 0 );
1507 }
1508
1509 // Restore the virtual page numbers that were modified during save. When saving, screens are
1510 // assigned page number 1 (single use) or 0 (multiple uses) for serialization purposes.
1511 // We restore all screens here, not just the current one, because other code paths (e.g.
1512 // ERC tree model, temporary sheet switches) may read any screen's virtual page number.
1513 for( const SCH_SHEET_PATH& sheet : Schematic().Hierarchy() )
1514 sheet.LastScreen()->SetVirtualPageNumber( sheet.GetVirtualPageNumber() );
1515
1517
1518 if( GetCanvas() && GetCanvas()->GetView() )
1519 {
1521 GetCanvas()->Refresh();
1522 }
1523
1524 updateTitle();
1525
1526 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1527 m_infoBar->Dismiss();
1528
1529 return success;
1530}
1531
1532
1533bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1534 const std::map<std::string, UTF8>* aProperties )
1535{
1536 wxFileName filename( aFileName );
1537 wxFileName newfilename;
1538 SCH_IO_MGR::SCH_FILE_T fileType = (SCH_IO_MGR::SCH_FILE_T) aFileType;
1539
1540 wxCommandEvent changingEvt( EDA_EVT_SCHEMATIC_CHANGING );
1541 ProcessEventLocally( changingEvt );
1542
1543 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
1544 statusBar->ClearWarningMessages( "load" );
1545
1546 WX_STRING_REPORTER loadReporter;
1547 LOAD_INFO_REPORTER_SCOPE loadReporterScope( &loadReporter );
1548
1549 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
1550
1551 switch( fileType )
1552 {
1553 case SCH_IO_MGR::SCH_ALTIUM:
1554 case SCH_IO_MGR::SCH_CADSTAR_ARCHIVE:
1555 case SCH_IO_MGR::SCH_EAGLE:
1556 case SCH_IO_MGR::SCH_LTSPICE:
1557 case SCH_IO_MGR::SCH_EASYEDA:
1558 case SCH_IO_MGR::SCH_EASYEDAPRO:
1559 case SCH_IO_MGR::SCH_PADS:
1560 case SCH_IO_MGR::SCH_GEDA:
1561 case SCH_IO_MGR::SCH_DIPTRACE:
1562 case SCH_IO_MGR::SCH_PCAD:
1563 {
1564 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
1565 // Unless we are passing the files in aproperties, in which case aFileName can be empty.
1566 wxCHECK_MSG( aFileName.IsEmpty() || filename.IsAbsolute(), false,
1567 wxS( "Import schematic: path is not absolute!" ) );
1568
1569 try
1570 {
1571 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
1572 DIALOG_HTML_REPORTER errorReporter( this );
1573 WX_PROGRESS_REPORTER progressReporter( this, _( "Import Schematic" ), 1, PR_CAN_ABORT );
1574
1575 if( PROJECT_CHOOSER_PLUGIN* c_pi = dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() ) )
1576 {
1577 c_pi->RegisterCallback( std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::RunModal,
1578 this, std::placeholders::_1 ) );
1579 }
1580
1581 if( eeconfig()->m_System.show_import_issues )
1582 pi->SetReporter( errorReporter.m_Reporter );
1583 else
1584 pi->SetReporter( &NULL_REPORTER::GetInstance() );
1585
1586 pi->SetProgressReporter( &progressReporter );
1587
1588 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( aFileName, newSchematic.get(), nullptr,
1589 aProperties );
1590
1591 SetSchematic( newSchematic.release() );
1592
1593 if( loadedSheet )
1594 {
1595 std::vector<SCH_SHEET*> topLevelSheets = Schematic().GetTopLevelSheets();
1596 bool loadedIsTopLevel = std::find( topLevelSheets.begin(), topLevelSheets.end(), loadedSheet )
1597 != topLevelSheets.end();
1598 bool loadedIsVirtualRoot = loadedSheet == &Schematic().Root()
1599 || loadedSheet->IsVirtualRootSheet();
1600
1601 // Some importers create the full top-level sheet set themselves. Do not collapse
1602 // that back to the returned sheet.
1603 if( !loadedIsTopLevel && !loadedIsVirtualRoot )
1604 Schematic().SetTopLevelSheets( { loadedSheet } );
1605
1606 if( errorReporter.m_Reporter->HasMessage() )
1607 {
1608 errorReporter.m_Reporter->Flush(); // Build HTML messages
1609 errorReporter.ShowModal();
1610 }
1611
1612 // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works
1613 // differently to KiCad), so set it to an empty one.
1615 drawingSheet.SetEmptyLayout();
1616 BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
1617
1618 newfilename.SetPath( Prj().GetProjectPath() );
1619 newfilename.SetName( Prj().GetProjectName() );
1620 newfilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
1621
1622 SetScreen( Schematic().RootScreen() );
1623
1624 if( SCH_SHEET* topSheet = Schematic().GetTopLevelSheet() )
1625 topSheet->SetFileName( newfilename.GetFullName() );
1626
1627 GetScreen()->SetFileName( newfilename.GetFullPath() );
1629
1630 progressReporter.Report( _( "Updating connections..." ) );
1631
1632 if( !progressReporter.KeepRefreshing() )
1633 THROW_IO_ERROR( _( "File import canceled by user." ) );
1634
1635 RecalculateConnections( nullptr, GLOBAL_CLEANUP, &progressReporter );
1636
1637 // Only perform the dangling end test on root sheet.
1639 }
1640 else
1641 {
1643 }
1644 }
1645 catch( const IO_ERROR& ioe )
1646 {
1647 // Do not leave g_RootSheet == NULL because it is expected to be
1648 // a valid sheet. Therefore create a dummy empty root sheet and screen.
1651
1652 wxString msg = wxString::Format( _( "Error loading schematic '%s'." ), aFileName );
1653 DisplayErrorMessage( this, msg, ioe.What() );
1654
1655 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1656 SetMsgPanel( wxEmptyString, msg );
1657 }
1658 catch( const std::exception& exc )
1659 {
1662
1663 wxString msg = wxString::Format( _( "Unhandled exception occurred loading schematic "
1664 "'%s'." ), aFileName );
1665 DisplayErrorMessage( this, msg, exc.what() );
1666
1667 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1668 SetMsgPanel( wxEmptyString, msg );
1669 }
1670
1673
1676 SyncView();
1677
1678 UpdateHierarchyNavigator( false, true );
1679 UpdateVariantSelectionCtrl( m_schematic->GetVariantNamesForUI() );
1680 SetCurrentVariant( m_schematic->GetCurrentVariant() );
1681
1682 CallAfter(
1683 [this]()
1684 {
1685 if( m_netNavigator && m_netNavigator->IsEmpty() )
1686 {
1688 }
1689 } );
1690
1691 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGED );
1692 ProcessEventLocally( e );
1693
1694 for( wxEvtHandler* listener : m_schematicChangeListeners )
1695 {
1696 wxCHECK2( listener, continue );
1697
1698 // Use the windows variant when handling event messages in case there is any
1699 // special event handler pre and/or post processing specific to windows.
1700 wxWindow* win = dynamic_cast<wxWindow*>( listener );
1701
1702 if( win )
1703 win->HandleWindowEvent( e );
1704 else
1705 listener->SafelyProcessEvent( e );
1706 }
1707
1708 updateTitle();
1709
1710 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
1711 statusBar->AddWarningMessages( "load", loadReporter.GetMessages() );
1712
1713 break;
1714 }
1715
1716 default:
1717 break;
1718 }
1719
1720 return true;
1721}
1722
1723
1725{
1726 SCH_SCREENS screenList( Schematic().Root() );
1727
1728 // Save any currently open and modified project files.
1729 for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
1730 {
1731 SIMULATOR_FRAME* simFrame = (SIMULATOR_FRAME*) Kiway().Player( FRAME_SIMULATOR, false );
1732
1733 // Simulator must be closed before loading another schematic, otherwise it may crash.
1734 // If there are any changes in the simulator the user will be prompted to save them.
1735 if( simFrame && !simFrame->Close() )
1736 return false;
1737
1738 if( screen->IsContentModified() )
1739 {
1740 if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
1741 "Save changes?" ),
1742 [&]() -> bool
1743 {
1744 return SaveProject();
1745 } ) )
1746 {
1747 return false;
1748 }
1749 }
1750 }
1751
1752 return true;
1753}
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.
static bool ShouldPrompt(int aFileFormatVersionAtLoad, size_t aBusesNeedingMigration)
Multiple differently-named labels on a single bus subgraph were only permitted before KiCad 6....
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.
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
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?
void RefreshDrawingSheetPageInfo()
Update the drawing sheet proxy's page number and first-page flag from the current edit frame state.
Definition sch_view.cpp:235
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:124
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
UTF8 Format() const
Definition lib_id.cpp:132
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:899
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
KIGFX::SCH_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
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.
bool RepairPageNumbers()
Assign valid page numbers to sheet paths whose stored page number is missing or collides with an earl...
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:792
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:728
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