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, you may find one here:
21 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22 * or you may search the http://www.gnu.org website for the version 2 license,
23 * or you may write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 */
26
27
28#include <confirm.h>
29#include <common.h>
30#include <connection_graph.h>
32#include <dialog_symbol_remap.h>
34#include <eeschema_settings.h>
35#include <id.h>
36#include <kiface_base.h>
37#include <kiplatform/app.h>
40#include <local_history.h>
41#include <sch_symbol.h>
42#include <set>
43#include <lockfile.h>
44#include <pgm_base.h>
45#include <core/profile.h>
47#include <project_rescue.h>
48#include <project_sch.h>
51#include <reporter.h>
52#include <richio.h>
53#include <sch_bus_entry.h>
54#include <sch_commit.h>
55#include <sch_edit_frame.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 Kiway().LocalHistory().Init( wx_filename.GetPath() );
115
116 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
117 wxASSERT_MSG( wx_filename.IsAbsolute(), wxS( "Path is not absolute!" ) );
118
119 if( !LockFile( fullFileName ) )
120 {
121 msg.Printf( _( "Schematic '%s' is already open by '%s' at '%s'." ), fullFileName,
122 m_file_checker->GetUsername(), m_file_checker->GetHostname() );
123
124 if( !AskOverrideLock( this, msg ) )
125 return false;
126
127 m_file_checker->OverrideLock();
128 }
129
130 if( !AskToSaveChanges() )
131 return false;
132
133#ifdef PROFILE
134 PROF_TIMER openFiles( "OpenProjectFile" );
135#endif
136
137 wxFileName pro = fullFileName;
138 pro.SetExt( FILEEXT::ProjectFileExtension );
139
140 bool is_new = !wxFileName::IsFileReadable( fullFileName );
141
142 // If its a non-existent schematic and caller thinks it exists
143 if( is_new && !( aCtl & KICTL_CREATE ) )
144 {
145 // notify user that fullFileName does not exist, ask if user wants to create it.
146 msg.Printf( _( "Schematic '%s' does not exist. Do you wish to create it?" ),
147 fullFileName );
148
149 if( !IsOK( this, msg ) )
150 return false;
151 }
152
153 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGING );
154 ProcessEventLocally( e );
155
156 // unload current project file before loading new
157 {
160 SetScreen( nullptr );
162 }
163
164 SetStatusText( wxEmptyString );
165 m_infoBar->Dismiss();
166
167 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
168 statusBar->ClearLoadWarningMessages();
169
170 WX_PROGRESS_REPORTER progressReporter( this, is_new ? _( "Create Schematic" )
171 : _( "Load Schematic" ), 1,
172 PR_CAN_ABORT );
173 WX_STRING_REPORTER loadReporter;
174 LOAD_INFO_REPORTER_SCOPE loadReporterScope( &loadReporter );
175
176 bool differentProject = pro.GetFullPath() != Prj().GetProjectFullName();
177
178 // This is for handling standalone mode schematic changes
179 if( differentProject )
180 {
181 if( !Prj().IsNullProject() )
182 {
185 }
186
187 // disconnect existing project from schematic before we unload the project
188 Schematic().SetProject( nullptr );
189 GetSettingsManager()->UnloadProject( &Prj(), false );
190
191 GetSettingsManager()->LoadProject( pro.GetFullPath() );
192
193 wxFileName legacyPro( pro );
194 legacyPro.SetExt( FILEEXT::LegacyProjectFileExtension );
195
196 // Do not allow saving a project if one doesn't exist. This normally happens if we are
197 // standalone and opening a schematic that has been moved from its project folder.
198 if( !pro.Exists() && !legacyPro.Exists() && !( aCtl & KICTL_CREATE ) )
199 Prj().SetReadOnly();
200 }
201
202 // Start a new schematic object now that we sorted out our project
203 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
204
205 SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( fullFileName,
207
208 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
209 {
210 // Don't reload the symbol libraries if we are just launching Eeschema from KiCad again.
211 // They are already saved in the kiface project object.
212 if( differentProject || !Prj().GetElem( PROJECT::ELEM::LEGACY_SYMBOL_LIBS ) )
213 {
214 // load the libraries here, not in SCH_SCREEN::Draw() which is a context
215 // that will not tolerate DisplayError() dialog since we're already in an
216 // event handler in there.
217 // And when a schematic file is loaded, we need these libs to initialize
218 // some parameters (links to PART LIB, dangling ends ...)
221 }
222 }
223 else
224 {
225 // No legacy symbol libraries including the cache are loaded with the new file format.
227 }
228
229 wxFileName rfn( GetCurrentFileName() );
230 rfn.MakeRelativeTo( Prj().GetProjectPath() );
231 LoadWindowState( rfn.GetFullPath() );
232
233 KIPLATFORM::APP::SetShutdownBlockReason( this, _( "Schematic file changes are unsaved" ) );
234
235 if( Kiface().IsSingle() )
236 {
238 }
239
240 if( is_new || schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
241 {
242 newSchematic->CreateDefaultScreens();
243 SetSchematic( newSchematic.release() );
244
245 // mark new, unsaved file as modified.
247 GetScreen()->SetFileName( fullFileName );
248
249 if( schFileType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
250 {
251 msg.Printf( _( "'%s' is not a KiCad schematic file.\nUse File -> Import for "
252 "non-KiCad schematic files." ),
253 fullFileName );
254
255 progressReporter.Hide();
256 DisplayErrorMessage( this, msg );
257 }
258 }
259 else
260 {
261 SetScreen( nullptr );
262
263 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( schFileType ) );
264
265 pi->SetProgressReporter( &progressReporter );
266
267 bool failedLoad = false;
268
269 try
270 {
271 {
272 wxBusyCursor busy;
273 WINDOW_DISABLER raii( this );
274
275 // Check if project file has top-level sheets defined
276 PROJECT_FILE& projectFile = Prj().GetProjectFile();
277 const std::vector<TOP_LEVEL_SHEET_INFO>& topLevelSheets = projectFile.GetTopLevelSheets();
278
279 if( !topLevelSheets.empty() )
280 {
281 std::vector<SCH_SHEET*> loadedSheets;
282
283 // Load each top-level sheet
284 for( const TOP_LEVEL_SHEET_INFO& sheetInfo : topLevelSheets )
285 {
286 wxFileName sheetFileName( Prj().GetProjectPath(), sheetInfo.filename );
287
288 // When loading legacy schematic files, ensure we are referencing the correct extension
289 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
290 sheetFileName.SetExt( FILEEXT::LegacySchematicFileExtension );
291
292 wxString sheetPath = sheetFileName.GetFullPath();
293
294 if( !wxFileName::FileExists( sheetPath ) )
295 {
296 wxLogWarning( wxT( "Top-level sheet file not found: %s" ), sheetPath );
297 continue;
298 }
299
300 SCH_SHEET* sheet = pi->LoadSchematicFile( sheetPath, newSchematic.get() );
301
302 if( sheet )
303 {
304 // Preserve the UUID from the project file, unless it's niluuid which is
305 // just a placeholder meaning "use the UUID from the file"
306 if( sheetInfo.uuid != niluuid )
307 {
308 const_cast<KIID&>( sheet->m_Uuid ) = sheetInfo.uuid;
309 }
310
311 sheet->SetName( sheetInfo.name );
312 loadedSheets.push_back( sheet );
313
314 wxLogTrace( tracePathsAndFiles,
315 wxS( "Loaded top-level sheet '%s' (UUID %s) from %s" ),
316 sheet->GetName(),
317 sheet->m_Uuid.AsString(),
318 sheetPath );
319 }
320 }
321
322 if( !loadedSheets.empty() )
323 {
324 newSchematic->SetTopLevelSheets( loadedSheets );
325 }
326 else
327 {
328 wxLogTrace( tracePathsAndFiles,
329 wxS( "Loaded multi-root schematic with no top-level sheets!" ) );
330 newSchematic->CreateDefaultScreens();
331 }
332 }
333 else
334 {
335 // Legacy single-root format: Load the single root sheet
336 SCH_SHEET* rootSheet = pi->LoadSchematicFile( fullFileName, newSchematic.get() );
337
338 if( rootSheet )
339 {
340 newSchematic->SetTopLevelSheets( { rootSheet } );
341
342 // Make ${SHEETNAME} work on the root sheet until we properly support
343 // naming the root sheet
344 if( SCH_SHEET* topSheet = newSchematic->GetTopLevelSheet() )
345 topSheet->SetName( _( "Root" ) );
346
347 wxLogTrace( tracePathsAndFiles,
348 wxS( "Loaded schematic with root sheet UUID %s" ),
349 rootSheet->m_Uuid.AsString() );
350 wxLogTrace( traceSchCurrentSheet,
351 "After loading: Current sheet path='%s', size=%zu, empty=%d",
352 newSchematic->CurrentSheet().Path().AsString(),
353 newSchematic->CurrentSheet().size(),
354 newSchematic->CurrentSheet().empty() ? 1 : 0 );
355 }
356 else
357 {
358 newSchematic->CreateDefaultScreens();
359 }
360
361 }
362 }
363
364 if( !pi->GetError().IsEmpty() )
365 {
366 DisplayErrorMessage( this, _( "The entire schematic could not be loaded. Errors "
367 "occurred attempting to load hierarchical sheets." ),
368 pi->GetError() );
369 }
370 }
371 catch( const FUTURE_FORMAT_ERROR& ffe )
372 {
373 newSchematic->CreateDefaultScreens();
374 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
375 progressReporter.Hide();
376 DisplayErrorMessage( this, msg, ffe.Problem() );
377
378 failedLoad = true;
379 }
380 catch( const IO_ERROR& ioe )
381 {
382 newSchematic->CreateDefaultScreens();
383 msg.Printf( _( "Error loading schematic '%s'." ), fullFileName );
384 progressReporter.Hide();
385 DisplayErrorMessage( this, msg, ioe.What() );
386
387 failedLoad = true;
388 }
389 catch( const std::bad_alloc& )
390 {
391 newSchematic->CreateDefaultScreens();
392 msg.Printf( _( "Memory exhausted loading schematic '%s'." ), fullFileName );
393 progressReporter.Hide();
394 DisplayErrorMessage( this, msg, wxEmptyString );
395
396 failedLoad = true;
397 }
398
399 SetSchematic( newSchematic.release() );
400
401 // This fixes a focus issue after the progress reporter is done on GTK. It shouldn't
402 // cause any issues on macOS and Windows. If it does, it will have to be conditionally
403 // compiled.
404 Raise();
405
406 if( failedLoad )
407 {
408 // Do not leave g_RootSheet == NULL because it is expected to be
409 // a valid sheet. Therefore create a dummy empty root sheet and screen.
412
413 // Show any messages collected before the failure
414 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
415 statusBar->SetLoadWarningMessages( loadReporter.GetMessages() );
416
417 msg.Printf( _( "Failed to load '%s'." ), fullFileName );
418 SetMsgPanel( wxEmptyString, msg );
419
420 return false;
421 }
422
423 // Load project settings after schematic has been set up with the project link, since this will
424 // update some of the needed schematic settings such as drawing defaults
426
427 // It's possible the schematic parser fixed errors due to bugs so warn the user
428 // that the schematic has been fixed (modified).
429 SCH_SHEET_LIST sheetList = Schematic().Hierarchy();
430
431 if( sheetList.IsModified() )
432 {
433 DisplayInfoMessage( this,
434 _( "An error was found when loading the schematic that has "
435 "been automatically fixed. Please save the schematic to "
436 "repair the broken file or it may not be usable with other "
437 "versions of KiCad." ) );
438 }
439
440 if( sheetList.AllSheetPageNumbersEmpty() )
441 sheetList.SetInitialPageNumbers();
442
443 UpdateFileHistory( fullFileName );
444
445 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
446 statusBar->SetLoadWarningMessages( loadReporter.GetMessages() );
447
448 SCH_SCREENS schematic( Schematic().Root() );
449
450 // LIB_ID checks and symbol rescue only apply to the legacy file formats.
451 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
452 {
453 // Convert any legacy bus-bus entries to just be bus wires
454 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
455 {
456 std::vector<SCH_ITEM*> deleted;
457
458 for( SCH_ITEM* item : screen->Items() )
459 {
460 if( item->Type() == SCH_BUS_BUS_ENTRY_T )
461 {
462 SCH_BUS_BUS_ENTRY* entry = static_cast<SCH_BUS_BUS_ENTRY*>( item );
463 std::unique_ptr<SCH_LINE> wire = std::make_unique<SCH_LINE>();
464
465 wire->SetLayer( LAYER_BUS );
466 wire->SetStartPoint( entry->GetPosition() );
467 wire->SetEndPoint( entry->GetEnd() );
468
469 screen->Append( wire.release() );
470 deleted.push_back( item );
471 }
472 }
473
474 for( SCH_ITEM* item : deleted )
475 screen->Remove( item );
476 }
477
478
479 // Convert old projects over to use symbol library table.
480 if( schematic.HasNoFullyDefinedLibIds() )
481 {
482 DIALOG_SYMBOL_REMAP dlgRemap( this );
483
484 dlgRemap.ShowQuasiModal();
485 }
486 else
487 {
488 // Double check to ensure no legacy library list entries have been
489 // added to the project file symbol library list.
490 wxString paths;
491 wxArrayString libNames;
492
493 LEGACY_SYMBOL_LIBS::GetLibNamesAndPaths( &Prj(), &paths, &libNames );
494
495 if( !libNames.IsEmpty() )
496 {
497 if( eeconfig()->m_Appearance.show_illegal_symbol_lib_dialog )
498 {
499 wxRichMessageDialog invalidLibDlg(
500 this,
501 _( "Illegal entry found in project file symbol library list." ),
502 _( "Project Load Warning" ),
503 wxOK | wxCENTER | wxICON_EXCLAMATION );
504 invalidLibDlg.ShowDetailedText(
505 _( "Symbol libraries defined in the project file symbol library "
506 "list are no longer supported and will be removed.\n\n"
507 "This may cause broken symbol library links under certain "
508 "conditions." ) );
509 invalidLibDlg.ShowCheckBox( _( "Do not show this dialog again." ) );
510 invalidLibDlg.ShowModal();
512 !invalidLibDlg.IsCheckBoxChecked();
513 }
514
515 libNames.Clear();
516 paths.Clear();
517 LEGACY_SYMBOL_LIBS::SetLibNamesAndPaths( &Prj(), paths, libNames );
518 }
519
520 // Check for cache file
521 wxFileName cacheFn( fullFileName );
522 cacheFn.SetName( cacheFn.GetName() + "-cache" );
524 bool cacheExists = cacheFn.FileExists();
525
526 if( cacheExists )
527 {
529 std::optional<LIBRARY_TABLE*> table = adapter->ProjectTable();
530
531 if( table && *table )
532 {
533 wxString nickname = Prj().GetProjectName() + "-cache";
534
535 if( !(*table)->HasRow( nickname ) )
536 {
537 LIBRARY_TABLE_ROW& row = (*table)->InsertRow();
538 row.SetNickname( nickname );
539 row.SetURI( cacheFn.GetFullPath() );
540 row.SetType( SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) );
541 row.SetDescription( _( "Legacy project cache library" ) );
542 (*table)->Save();
543 }
544
545 std::vector<wxString> cacheSymbols = adapter->GetSymbolNames( nickname );
546 std::set<wxString> cacheSymbolSet( cacheSymbols.begin(), cacheSymbols.end() );
547
548 if( !cacheSymbolSet.empty() )
549 {
550 std::vector<wxString> loadedLibs;
551
552 for( const wxString& libName : adapter->GetLibraryNames() )
553 {
554 if( libName == nickname )
555 continue;
556
557 std::optional<LIB_STATUS> status = adapter->GetLibraryStatus( libName );
558
559 if( status && status->load_status == LOAD_STATUS::LOADED )
560 loadedLibs.push_back( libName );
561 }
562
563 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
564 {
565 for( SCH_ITEM* item : screen->Items().OfType( SCH_SYMBOL_T ) )
566 {
567 SCH_SYMBOL* symbol = static_cast<SCH_SYMBOL*>( item );
568 LIB_ID newId = symbol->GetLibId();
569 UTF8 fullLibName = newId.Format();
570
571 if( cacheSymbolSet.count( fullLibName.wx_str() ) )
572 {
573 bool alreadyExists = false;
574
575 for( const wxString& libName : loadedLibs )
576 {
577 if( adapter->LoadSymbol( libName, fullLibName.wx_str() ) )
578 {
579 alreadyExists = true;
580 break;
581 }
582 }
583
584 if( !alreadyExists )
585 {
586 newId.SetLibNickname( nickname );
587 newId.SetLibItemName( fullLibName );
588 symbol->SetLibId( newId );
589 }
590 }
591 }
592 }
593 }
594 }
595 }
596
597 if( ( !cfg || !cfg->m_RescueNeverShow ) && !cacheExists )
598 {
600 editor->RescueSymbolLibTableProject( false );
601 }
602 }
603
604 // Ensure there is only one legacy library loaded and that it is the cache library.
605 LEGACY_SYMBOL_LIBS* legacyLibs = PROJECT_SCH::LegacySchLibs( &Schematic().Project() );
606
607 if( legacyLibs->GetLibraryCount() == 0 )
608 {
609 wxString extMsg;
610 wxFileName cacheFn = pro;
611
612 wxLogTrace( traceAutoSave, "[SetName dbg] cacheFn BEFORE path='%s' name='%s' full='%s' arg='%s'",
613 cacheFn.GetPath(), cacheFn.GetName(), cacheFn.GetFullPath(), cacheFn.GetName() + "-cache" );
614 cacheFn.SetName( cacheFn.GetName() + "-cache" );
615 wxLogTrace( traceAutoSave, "[SetName dbg] cacheFn AFTER path='%s' name='%s' full='%s'",
616 cacheFn.GetPath(), cacheFn.GetName(), cacheFn.GetFullPath() );
618
619 msg.Printf( _( "The project symbol library cache file '%s' was not found." ),
620 cacheFn.GetFullName() );
621 extMsg = _( "This can result in a broken schematic under certain conditions. "
622 "If the schematic does not have any missing symbols upon opening, "
623 "save it immediately before making any changes to prevent data "
624 "loss. If there are missing symbols, either manual recovery of "
625 "the schematic or recovery of the symbol cache library file and "
626 "reloading the schematic is required." );
627
628 wxMessageDialog dlgMissingCache( this, msg, _( "Warning" ),
629 wxOK | wxCANCEL | wxICON_EXCLAMATION | wxCENTER );
630 dlgMissingCache.SetExtendedMessage( extMsg );
631 dlgMissingCache.SetOKCancelLabels(
632 wxMessageDialog::ButtonLabel( _( "Load Without Cache File" ) ),
633 wxMessageDialog::ButtonLabel( _( "Abort" ) ) );
634
635 if( dlgMissingCache.ShowModal() == wxID_CANCEL )
636 {
637 Schematic().Reset();
639 return false;
640 }
641 }
642
643 // Update all symbol library links for all sheets.
644 schematic.UpdateSymbolLinks( &loadReporter );
645
646 m_infoBar->RemoveAllButtons();
647 m_infoBar->AddCloseButton();
648 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
649 "It will be converted to the new format when saved." ),
651
652 // Legacy schematic can have duplicate time stamps so fix that before converting
653 // to the s-expression format.
654 schematic.ReplaceDuplicateTimeStamps();
655
656 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
657 screen->FixLegacyPowerSymbolMismatches();
658
659 // Allow the schematic to be saved to new file format without making any edits.
660 OnModify();
661 }
662 else // S-expression schematic.
663 {
664 SCH_SCREEN* first_screen = schematic.GetFirst();
665
666 // Skip the first screen as it is a virtual root with no version info.
667 if( first_screen->GetFileFormatVersionAtLoad() == 0 )
668 first_screen = schematic.GetNext();
669
670 if( first_screen && first_screen->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
671 {
672 m_infoBar->RemoveAllButtons();
673 m_infoBar->AddCloseButton();
674 m_infoBar->ShowMessage( _( "This file was created by an older version of KiCad. "
675 "It will be converted to the new format when saved." ),
677 }
678
679 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
681
682 // Restore all of the loaded symbol and sheet instances from the root sheet.
683 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221002 )
684 sheetList.UpdateSymbolInstanceData( Schematic().RootScreen()->GetSymbolInstances() );
685
686 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20221110 )
687 sheetList.UpdateSheetInstanceData( Schematic().RootScreen()->GetSheetInstances());
688
689 if( Schematic().RootScreen()->GetFileFormatVersionAtLoad() < 20230221 )
690 for( SCH_SCREEN* screen = schematic.GetFirst(); screen;
691 screen = schematic.GetNext() )
692 screen->FixLegacyPowerSymbolMismatches();
693
694 for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
695 screen->MigrateSimModels();
696
698 UpdateVariantSelectionCtrl( Schematic().GetVariantNamesForUI() );
699 }
700
701 // After the schematic is successfully loaded, we load the drawing sheet.
702 // This allows us to use the drawing sheet embedded in the schematic (if any)
703 // instead of the default one.
705
706 schematic.PruneOrphanedSymbolInstances( Prj().GetProjectName(), sheetList );
707 schematic.PruneOrphanedSheetInstances( Prj().GetProjectName(), sheetList );
708
709 wxLogTrace( traceSchCurrentSheet,
710 "Before CheckForMissingSymbolInstances: Current sheet path='%s', size=%zu",
711 GetCurrentSheet().Path().AsString(),
712 GetCurrentSheet().size() );
713 sheetList.CheckForMissingSymbolInstances( Prj().GetProjectName() );
714
716
717 SetScreen( GetCurrentSheet().LastScreen() );
718
719 wxLogTrace( traceSchCurrentSheet,
720 "After SetScreen: Current sheet path='%s', size=%zu",
721 GetCurrentSheet().Path().AsString(),
722 GetCurrentSheet().size() );
723
724 // Migrate conflicting bus definitions
725 // TODO(JE) This should only run once based on schematic file version
726 if( Schematic().ConnectionGraph()->GetBusesNeedingMigration().size() > 0 )
727 {
728 DIALOG_MIGRATE_BUSES dlg( this );
729 dlg.ShowQuasiModal();
730 OnModify();
731 }
732
733 SCH_COMMIT dummy( this );
734
735 progressReporter.Report( _( "Updating connections..." ) );
736 progressReporter.KeepRefreshing();
737
738 RecalculateConnections( &dummy, GLOBAL_CLEANUP, &progressReporter );
739
740 if( schematic.HasSymbolFieldNamesWithWhiteSpace() )
741 {
742 m_infoBar->QueueShowMessage( _( "This schematic contains symbols that have leading "
743 "and/or trailing white space field names." ),
744 wxICON_WARNING );
745 }
746 }
747
748 // Load any exclusions from the project file
750
753
756
757 // Re-create junctions if needed. Eeschema optimizes wires by merging
758 // colinear segments. If a schematic is saved without a valid
759 // cache library or missing installed libraries, this can cause connectivity errors
760 // unless junctions are added.
761 //
762 // TODO: (RFB) This really needs to be put inside the Load() function of the SCH_IO_KICAD_LEGACY
763 // I can't put it right now because of the extra code that is above to convert legacy bus-bus
764 // entries to bus wires
765 if( schFileType == SCH_IO_MGR::SCH_LEGACY )
767
768 SyncView();
770
772
773 UpdateHierarchyNavigator( false, true );
774
775 wxCommandEvent changedEvt( EDA_EVT_SCHEMATIC_CHANGED );
776 ProcessEventLocally( changedEvt );
777
778 if( !differentProject )
779 {
780 // If we didn't reload the project, we still need to call ProjectChanged() to ensure
781 // frame-specific initialization happens (like registering the autosave saver).
782 // When running under the project manager, KIWAY::ProjectChanged() was called before
783 // this frame existed, so we need to call our own ProjectChanged() now.
785 }
786
787 for( wxEvtHandler* listener : m_schematicChangeListeners )
788 {
789 wxCHECK2( listener, continue );
790
791 // Use the windows variant when handling event messages in case there is any special
792 // event handler pre and/or post processing specific to windows.
793 wxWindow* win = dynamic_cast<wxWindow*>( listener );
794
795 if( win )
796 win->HandleWindowEvent( e );
797 else
798 listener->SafelyProcessEvent( e );
799 }
800
801 updateTitle();
802 m_toolManager->GetTool<SCH_NAVIGATE_TOOL>()->ResetHistory();
803
804 wxFileName fn = Prj().AbsolutePath( GetScreen()->GetFileName() );
805
806 if( fn.FileExists() && !fn.IsFileWritable() )
807 {
808 m_infoBar->RemoveAllButtons();
809 m_infoBar->AddCloseButton();
810 m_infoBar->ShowMessage( _( "Schematic is read only." ),
812 }
813
814#ifdef PROFILE
815 openFiles.Show();
816#endif
817 // Ensure all items are redrawn (especially the drawing-sheet items):
818 if( GetCanvas() )
819 GetCanvas()->DisplaySheet( GetCurrentSheet().LastScreen() );
820
821 // Trigger a library load to handle any project-specific libraries
822 CallAfter( [&]()
823 {
824 KIFACE *schface = Kiway().KiFACE( KIWAY::FACE_SCH );
825 schface->PreloadLibraries( &Kiway() );
826
828 } );
829
830 m_remoteSymbolPane->BindWebViewLoaded();
831
832 return true;
833}
834
835
836void SCH_EDIT_FRAME::OnImportProject( wxCommandEvent& aEvent )
837{
838 if( Schematic().RootScreen() && !Schematic().RootScreen()->Items().empty() )
839 {
840 wxString msg = _( "This operation replaces the contents of the current schematic, "
841 "which will be permanently lost.\n\n"
842 "Do you want to proceed?" );
843
844 if( !IsOK( this, msg ) )
845 return;
846 }
847
848 // Set the project location if none is set or if we are running in standalone mode
849 bool setProject = Prj().GetProjectFullName().IsEmpty() || Kiface().IsSingle();
850 wxString path = wxPathOnly( Prj().GetProjectFullName() );
851
852 wxString fileFiltersStr;
853 wxString allWildcardsStr;
854
855 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
856 {
857 if( fileType == SCH_IO_MGR::SCH_KICAD || fileType == SCH_IO_MGR::SCH_LEGACY )
858 continue; // this is "Import non-KiCad schematic"
859
860 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
861
862 if( !pi )
863 continue;
864
865 const IO_BASE::IO_FILE_DESC& desc = pi->GetSchematicFileDesc();
866
867 if( desc.m_FileExtensions.empty() || !desc.m_CanRead )
868 continue;
869
870 if( !fileFiltersStr.IsEmpty() )
871 fileFiltersStr += wxChar( '|' );
872
873 fileFiltersStr += desc.FileFilter();
874
875 for( const std::string& ext : desc.m_FileExtensions )
876 allWildcardsStr << wxS( "*." ) << formatWildcardExt( ext ) << wxS( ";" );
877 }
878
879 fileFiltersStr = _( "All supported formats" ) + wxS( "|" ) + allWildcardsStr + wxS( "|" )
880 + fileFiltersStr;
881
882 wxFileDialog dlg( this, _( "Import Schematic" ), path, wxEmptyString, fileFiltersStr,
883 wxFD_OPEN | wxFD_FILE_MUST_EXIST ); // TODO
884
885 FILEDLG_IMPORT_NON_KICAD importOptions( eeconfig()->m_System.show_import_issues );
886 dlg.SetCustomizeHook( importOptions );
887
888 if( dlg.ShowModal() == wxID_CANCEL )
889 return;
890
892
893 // Don't leave dangling pointers to previously-opened document.
894 m_toolManager->GetTool<SCH_SELECTION_TOOL>()->ClearSelection();
897
898 if( setProject )
899 {
900 Schematic().SetProject( nullptr );
901 GetSettingsManager()->UnloadProject( &Prj(), false );
902
903 // Clear view before destroying schematic as repaints depend on schematic being valid
904 SetScreen( nullptr );
905
906 Schematic().Reset();
907
908 wxFileName projectFn( dlg.GetPath() );
909 projectFn.SetExt( FILEEXT::ProjectFileExtension );
910 GetSettingsManager()->LoadProject( projectFn.GetFullPath() );
911 }
912
913 wxFileName fn = dlg.GetPath();
914
915 if( !fn.IsFileReadable() )
916 {
917 wxLogError( _( "Insufficient permissions to read file '%s'." ), fn.GetFullPath() );
918 return;
919 }
920
921 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN;
922
923 for( const SCH_IO_MGR::SCH_FILE_T& fileType : SCH_IO_MGR::SCH_FILE_T_vector )
924 {
925 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
926
927 if( !pi )
928 continue;
929
930 if( pi->CanReadSchematicFile( fn.GetFullPath() ) )
931 {
932 pluginType = fileType;
933 break;
934 }
935 }
936
937 if( pluginType == SCH_IO_MGR::SCH_FILE_T::SCH_FILE_UNKNOWN )
938 {
939 wxLogError( _( "No loader can read the specified file: '%s'." ), fn.GetFullPath() );
941 SetScreen( Schematic().RootScreen() );
942 return;
943 }
944
945 importFile( dlg.GetPath(), pluginType );
946
948}
949
950
951bool SCH_EDIT_FRAME::saveSchematicFile( SCH_SHEET* aSheet, const wxString& aSavePath )
952{
953 wxString msg;
954 wxFileName schematicFileName;
955 wxFileName oldFileName;
956 bool success;
957
958 SCH_SCREEN* screen = aSheet->GetScreen();
959
960 wxCHECK( screen, false );
961
962 // Cannot save to nowhere
963 if( aSavePath.IsEmpty() )
964 return false;
965
966 // Construct the name of the file to be saved
967 schematicFileName = Prj().AbsolutePath( aSavePath );
968 oldFileName = schematicFileName;
969
970 // Write through symlinks, don't replace them
971 WX_FILENAME::ResolvePossibleSymlinks( schematicFileName );
972
973 if( !schematicFileName.DirExists() )
974 {
975 if( !wxMkdir( schematicFileName.GetPath() ) )
976 {
977 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
978 schematicFileName.GetFullPath(),
979 "Could not create directory: %s" + schematicFileName.GetPath() );
980 DisplayError( this, msg );
981
982 return false;
983 }
984 }
985
986 if( !IsWritable( schematicFileName ) )
987 return false;
988
989 wxFileName projectFile( schematicFileName );
990
991 projectFile.SetExt( FILEEXT::ProjectFileExtension );
992
993 if( projectFile.FileExists() )
994 {
995 // Save various ERC settings, such as violation severities (which may have been edited
996 // via the ERC dialog as well as the Schematic Setup dialog), ERC exclusions, etc.
998 }
999
1000 // Save
1001 wxLogTrace( traceAutoSave, wxS( "Saving file " ) + schematicFileName.GetFullPath() );
1002
1003 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1004 m_infoBar->Dismiss();
1005
1006 SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromSchPath(
1007 schematicFileName.GetFullPath() );
1008
1009 if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
1010 pluginType = SCH_IO_MGR::SCH_KICAD;
1011
1012 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pluginType ) );
1013
1014 // On Windows, ensure the target file is writeable by clearing problematic attributes like
1015 // hidden or read-only. This can happen when files are synced via cloud services.
1016 if( schematicFileName.FileExists() )
1017 KIPLATFORM::IO::MakeWriteable( schematicFileName.GetFullPath() );
1018
1019 try
1020 {
1021 pi->SaveSchematicFile( schematicFileName.GetFullPath(), aSheet, &Schematic() );
1022 success = true;
1023 }
1024 catch( const IO_ERROR& ioe )
1025 {
1026 msg.Printf( _( "Error saving schematic file '%s'.\n%s" ),
1027 schematicFileName.GetFullPath(),
1028 ioe.What() );
1029 DisplayError( this, msg );
1030
1031 success = false;
1032 }
1033
1034 if( success )
1035 {
1036 screen->SetContentModified( false );
1037
1038 msg.Printf( _( "File '%s' saved." ), screen->GetFileName() );
1039 SetStatusText( msg, 0 );
1040
1041 // Record a full project snapshot so related files (symbols, libs, sheets) are captured.
1042 Kiway().LocalHistory().CommitFullProjectSnapshot( schematicFileName.GetPath(), wxS( "SCH Save" ) );
1043 Kiway().LocalHistory().TagSave( schematicFileName.GetPath(), wxS( "sch" ) );
1044
1045 if( m_autoSaveTimer )
1046 m_autoSaveTimer->Stop();
1047
1048 m_autoSavePending = false;
1049 m_autoSaveRequired = false;
1050 }
1051
1052 return success;
1053}
1054
1055
1056bool PrepareSaveAsFiles( SCHEMATIC& aSchematic, SCH_SCREENS& aScreens,
1057 const wxFileName& aOldRoot, const wxFileName& aNewRoot,
1058 bool aSaveCopy, bool aCopySubsheets, bool aIncludeExternSheets,
1059 std::unordered_map<SCH_SCREEN*, wxString>& aFilenameMap,
1060 wxString& aErrorMsg )
1061{
1062 SCH_SCREEN* screen;
1063
1064 for( size_t i = 0; i < aScreens.GetCount(); i++ )
1065 {
1066 screen = aScreens.GetScreen( i );
1067
1068 wxCHECK2( screen, continue );
1069
1070 if( screen == aSchematic.RootScreen() )
1071 continue;
1072
1073 wxFileName src = screen->GetFileName();
1074
1075 if( !src.IsAbsolute() )
1076 src.MakeAbsolute( aOldRoot.GetPath() );
1077
1078 bool internalSheet = src.GetPath().StartsWith( aOldRoot.GetPath() );
1079
1080 if( aCopySubsheets && ( internalSheet || aIncludeExternSheets ) )
1081 {
1082 wxFileName dest = src;
1083
1084 if( internalSheet && dest.MakeRelativeTo( aOldRoot.GetPath() ) )
1085 dest.MakeAbsolute( aNewRoot.GetPath() );
1086 else
1087 dest.Assign( aNewRoot.GetPath(), dest.GetFullName() );
1088
1089 wxLogTrace( tracePathsAndFiles,
1090 wxS( "Moving schematic from '%s' to '%s'." ),
1091 screen->GetFileName(),
1092 dest.GetFullPath() );
1093
1094 if( !dest.DirExists() && !dest.Mkdir() )
1095 {
1096 aErrorMsg.Printf( _( "Folder '%s' could not be created.\n\n"
1097 "Make sure you have write permissions and try again." ),
1098 dest.GetPath() );
1099 return false;
1100 }
1101
1102 if( aSaveCopy )
1103 aFilenameMap[screen] = dest.GetFullPath();
1104 else
1105 screen->SetFileName( dest.GetFullPath() );
1106 }
1107 else
1108 {
1109 if( aSaveCopy )
1110 aFilenameMap[screen] = wxString();
1111
1112 screen->SetFileName( src.GetFullPath() );
1113 }
1114 }
1115
1116 for( SCH_SHEET_PATH& sheet : aSchematic.Hierarchy() )
1117 {
1118 if( !sheet.Last()->IsTopLevelSheet() )
1119 sheet.MakeFilePathRelativeToParentSheet();
1120 }
1121
1122 return true;
1123}
1124
1126{
1127 wxString msg;
1128 SCH_SCREEN* screen;
1129 SCH_SCREENS screens( Schematic().Root() );
1130 bool saveCopy = aSaveAs && !Kiface().IsSingle();
1131 bool success = true;
1132 bool updateFileHistory = false;
1133 bool createNewProject = false;
1134 bool copySubsheets = false;
1135 bool includeExternSheets = false;
1136
1137 // I want to see it in the debugger, show me the string! Can't do that with wxFileName.
1138 wxString fileName = Prj().AbsolutePath( Schematic().Root().GetFileName() );
1139 wxFileName fn = fileName;
1140
1141 // Path to save each screen to: will be the stored filename by default, but is overwritten by
1142 // a Save As Copy operation.
1143 std::unordered_map<SCH_SCREEN*, wxString> filenameMap;
1144
1145 // Handle "Save As" and saving a new project/schematic for the first time in standalone
1146 if( Prj().IsNullProject() || aSaveAs )
1147 {
1148 // Null project should only be possible in standalone mode.
1149 wxCHECK( Kiface().IsSingle() || aSaveAs, false );
1150
1151 wxFileName newFileName;
1152 wxFileName savePath( Prj().GetProjectFullName() );
1153
1154 if( !savePath.IsOk() || !savePath.IsDirWritable() )
1155 {
1156 savePath = GetMruPath();
1157
1158 if( !savePath.IsOk() || !savePath.IsDirWritable() )
1160 }
1161
1162 if( savePath.HasExt() )
1163 savePath.SetExt( FILEEXT::KiCadSchematicFileExtension );
1164 else
1165 savePath.SetName( wxEmptyString );
1166
1167 wxFileDialog dlg( this, _( "Schematic Files" ), savePath.GetPath(), savePath.GetFullName(),
1169 wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
1170
1171 FILEDLG_HOOK_SAVE_PROJECT newProjectHook;
1172
1173 // Add a "Create a project" checkbox in standalone mode and one isn't loaded
1174 if( Kiface().IsSingle() || aSaveAs )
1175 {
1176 dlg.SetCustomizeHook( newProjectHook );
1177 }
1178
1179 if( dlg.ShowModal() == wxID_CANCEL )
1180 return false;
1181
1182 newFileName = EnsureFileExtension( dlg.GetPath(), FILEEXT::KiCadSchematicFileExtension );
1183
1184 if( ( !newFileName.DirExists() && !newFileName.Mkdir() ) ||
1185 !newFileName.IsDirWritable() )
1186 {
1187 msg.Printf( _( "Folder '%s' could not be created.\n\n"
1188 "Make sure you have write permissions and try again." ),
1189 newFileName.GetPath() );
1190
1191 wxMessageDialog dlgBadPath( this, msg, _( "Error" ),
1192 wxOK | wxICON_EXCLAMATION | wxCENTER );
1193
1194 dlgBadPath.ShowModal();
1195 return false;
1196 }
1197
1198 if( newProjectHook.IsAttachedToDialog() )
1199 {
1200 createNewProject = newProjectHook.GetCreateNewProject();
1201 copySubsheets = newProjectHook.GetCopySubsheets();
1202 includeExternSheets = newProjectHook.GetIncludeExternSheets();
1203 }
1204
1205 if( !saveCopy )
1206 {
1207 Schematic().Root().SetFileName( newFileName.GetFullName() );
1208 Schematic().RootScreen()->SetFileName( newFileName.GetFullPath() );
1209 updateFileHistory = true;
1210 }
1211 else
1212 {
1213 filenameMap[Schematic().RootScreen()] = newFileName.GetFullPath();
1214 }
1215
1216 if( !PrepareSaveAsFiles( Schematic(), screens, fn, newFileName, saveCopy,
1217 copySubsheets, includeExternSheets, filenameMap, msg ) )
1218 {
1219 wxMessageDialog dlgBadFilePath( this, msg, _( "Error" ),
1220 wxOK | wxICON_EXCLAMATION | wxCENTER );
1221
1222 dlgBadFilePath.ShowModal();
1223 return false;
1224 }
1225 }
1226 else if( !fn.FileExists() )
1227 {
1228 // File doesn't exist yet; true if we just imported something
1229 updateFileHistory = true;
1230 }
1231 else if( screens.GetFirst() && screens.GetFirst()->GetFileFormatVersionAtLoad() < SEXPR_SCHEMATIC_FILE_VERSION )
1232 {
1233 // Allow the user to save un-edited files in new format
1234 }
1235 else if( !IsContentModified() )
1236 {
1237 return true;
1238 }
1239
1240 if( filenameMap.empty() || !saveCopy )
1241 {
1242 for( size_t i = 0; i < screens.GetCount(); i++ )
1243 filenameMap[screens.GetScreen( i )] = screens.GetScreen( i )->GetFileName();
1244 }
1245
1246 // Warn user on potential file overwrite. This can happen on shared sheets.
1247 wxArrayString overwrittenFiles;
1248 wxArrayString lockedFiles;
1249
1250 for( size_t i = 0; i < screens.GetCount(); i++ )
1251 {
1252 screen = screens.GetScreen( i );
1253
1254 wxCHECK2( screen, continue );
1255
1256 // Convert legacy schematics file name extensions for the new format.
1257 wxFileName tmpFn = filenameMap[screen];
1258
1259 if( !tmpFn.IsOk() )
1260 continue;
1261
1262 if( tmpFn.FileExists() && !tmpFn.IsFileWritable() )
1263 lockedFiles.Add( tmpFn.GetFullPath() );
1264
1265 if( tmpFn.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1266 continue;
1267
1269
1270 if( tmpFn.FileExists() )
1271 overwrittenFiles.Add( tmpFn.GetFullPath() );
1272 }
1273
1274 if( !lockedFiles.IsEmpty() )
1275 {
1276 for( const wxString& lockedFile : lockedFiles )
1277 {
1278 if( msg.IsEmpty() )
1279 msg = lockedFile;
1280 else
1281 msg += "\n" + lockedFile;
1282 }
1283
1284 wxRichMessageDialog dlg( this, wxString::Format( _( "Failed to save %s." ),
1285 Schematic().Root().GetFileName() ),
1286 _( "Locked File Warning" ),
1287 wxOK | wxICON_WARNING | wxCENTER );
1288 dlg.SetExtendedMessage( _( "You do not have write permissions to:\n\n" ) + msg );
1289
1290 dlg.ShowModal();
1291 return false;
1292 }
1293
1294 if( !overwrittenFiles.IsEmpty() )
1295 {
1296 for( const wxString& overwrittenFile : overwrittenFiles )
1297 {
1298 if( msg.IsEmpty() )
1299 msg = overwrittenFile;
1300 else
1301 msg += "\n" + overwrittenFile;
1302 }
1303
1304 wxRichMessageDialog dlg( this, _( "Saving will overwrite existing files." ),
1305 _( "Save Warning" ),
1306 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER |
1307 wxICON_EXCLAMATION );
1308 dlg.ShowDetailedText( _( "The following files will be overwritten:\n\n" ) + msg );
1309 dlg.SetOKCancelLabels( wxMessageDialog::ButtonLabel( _( "Overwrite Files" ) ),
1310 wxMessageDialog::ButtonLabel( _( "Abort Project Save" ) ) );
1311
1312 if( dlg.ShowModal() == wxID_CANCEL )
1313 return false;
1314 }
1315
1316 screens.BuildClientSheetPathList();
1317
1318 for( size_t i = 0; i < screens.GetCount(); i++ )
1319 {
1320 screen = screens.GetScreen( i );
1321
1322 wxCHECK2( screen, continue );
1323
1324 // Convert legacy schematics file name extensions for the new format.
1325 wxFileName tmpFn = filenameMap[screen];
1326
1327 if( tmpFn.IsOk() && tmpFn.GetExt() != FILEEXT::KiCadSchematicFileExtension )
1328 {
1329 updateFileHistory = true;
1331
1332 for( EDA_ITEM* item : screen->Items().OfType( SCH_SHEET_T ) )
1333 {
1334 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( item );
1335 wxFileName sheetFileName = sheet->GetFileName();
1336
1337 if( !sheetFileName.IsOk()
1338 || sheetFileName.GetExt() == FILEEXT::KiCadSchematicFileExtension )
1339 continue;
1340
1341 sheetFileName.SetExt( FILEEXT::KiCadSchematicFileExtension );
1342 sheet->SetFileName( sheetFileName.GetFullPath() );
1343 UpdateItem( sheet );
1344 }
1345
1346 filenameMap[screen] = tmpFn.GetFullPath();
1347
1348 if( !saveCopy )
1349 screen->SetFileName( tmpFn.GetFullPath() );
1350 }
1351
1352 // Do not save sheet symbols with no valid filename set
1353 if( !tmpFn.IsOk() )
1354 continue;
1355
1356 std::vector<SCH_SHEET_PATH>& sheets = screen->GetClientSheetPaths();
1357
1358 if( sheets.size() == 1 )
1359 screen->SetVirtualPageNumber( 1 );
1360 else
1361 screen->SetVirtualPageNumber( 0 ); // multiple uses; no way to store the real sheet #
1362
1363 // This is a new schematic file so make sure it has a unique ID.
1364 if( !saveCopy && tmpFn.GetFullPath() != screen->GetFileName() )
1365 screen->AssignNewUuid();
1366
1367 success &= saveSchematicFile( screens.GetSheet( i ), tmpFn.GetFullPath() );
1368 }
1369
1370 if( success )
1371 m_autoSaveRequired = false;
1372
1373 if( aSaveAs && success )
1374 LockFile( Schematic().RootScreen()->GetFileName() );
1375
1376 if( updateFileHistory )
1377 UpdateFileHistory( Schematic().RootScreen()->GetFileName() );
1378
1379 // Save the sheet name map to the project file
1380 std::vector<FILE_INFO_PAIR>& sheets = Prj().GetProjectFile().GetSheets();
1381 sheets.clear();
1382
1383 for( SCH_SHEET_PATH& sheetPath : Schematic().Hierarchy() )
1384 {
1385 SCH_SHEET* sheet = sheetPath.Last();
1386
1387 wxCHECK2( sheet, continue );
1388
1389 // Do not save the virtual root sheet
1390 if( !sheet->IsVirtualRootSheet() )
1391 {
1392 sheets.emplace_back( std::make_pair( sheet->m_Uuid, sheet->GetName() ) );
1393 }
1394 }
1395
1396 wxASSERT( filenameMap.count( Schematic().RootScreen() ) );
1397 wxFileName projectPath( filenameMap.at( Schematic().RootScreen() ) );
1398 projectPath.SetExt( FILEEXT::ProjectFileExtension );
1399
1400 if( Prj().IsNullProject() || ( aSaveAs && !saveCopy ) )
1401 {
1402 Prj().SetReadOnly( !createNewProject );
1403 GetSettingsManager()->SaveProjectAs( projectPath.GetFullPath() );
1404 }
1405 else if( saveCopy && createNewProject )
1406 {
1407 GetSettingsManager()->SaveProjectCopy( projectPath.GetFullPath() );
1408 }
1409 else
1410 {
1413 }
1414
1415 if( !Kiface().IsSingle() )
1416 {
1417 WX_STRING_REPORTER backupReporter;
1418
1419 if( !GetSettingsManager()->TriggerBackupIfNeeded( backupReporter ) )
1420 SetStatusText( backupReporter.GetMessages(), 0 );
1421 }
1422
1423 updateTitle();
1424
1425 if( m_infoBar->GetMessageType() == WX_INFOBAR::MESSAGE_TYPE::OUTDATED_SAVE )
1426 m_infoBar->Dismiss();
1427
1428 return success;
1429}
1430
1431
1432bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
1433 const std::map<std::string, UTF8>* aProperties )
1434{
1435 wxFileName filename( aFileName );
1436 wxFileName newfilename;
1437 SCH_IO_MGR::SCH_FILE_T fileType = (SCH_IO_MGR::SCH_FILE_T) aFileType;
1438
1439 wxCommandEvent changingEvt( EDA_EVT_SCHEMATIC_CHANGING );
1440 ProcessEventLocally( changingEvt );
1441
1442 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
1443 statusBar->ClearLoadWarningMessages();
1444
1445 WX_STRING_REPORTER loadReporter;
1446 LOAD_INFO_REPORTER_SCOPE loadReporterScope( &loadReporter );
1447
1448 std::unique_ptr<SCHEMATIC> newSchematic = std::make_unique<SCHEMATIC>( &Prj() );
1449
1450 switch( fileType )
1451 {
1452 case SCH_IO_MGR::SCH_ALTIUM:
1453 case SCH_IO_MGR::SCH_CADSTAR_ARCHIVE:
1454 case SCH_IO_MGR::SCH_EAGLE:
1455 case SCH_IO_MGR::SCH_LTSPICE:
1456 case SCH_IO_MGR::SCH_EASYEDA:
1457 case SCH_IO_MGR::SCH_EASYEDAPRO:
1458 {
1459 // We insist on caller sending us an absolute path, if it does not, we say it's a bug.
1460 // Unless we are passing the files in aproperties, in which case aFileName can be empty.
1461 wxCHECK_MSG( aFileName.IsEmpty() || filename.IsAbsolute(), false,
1462 wxS( "Import schematic: path is not absolute!" ) );
1463
1464 try
1465 {
1466 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( fileType ) );
1467 DIALOG_HTML_REPORTER errorReporter( this );
1468 WX_PROGRESS_REPORTER progressReporter( this, _( "Import Schematic" ), 1, PR_CAN_ABORT );
1469
1470 if( PROJECT_CHOOSER_PLUGIN* c_pi = dynamic_cast<PROJECT_CHOOSER_PLUGIN*>( pi.get() ) )
1471 {
1472 c_pi->RegisterCallback( std::bind( DIALOG_IMPORT_CHOOSE_PROJECT::RunModal,
1473 this, std::placeholders::_1 ) );
1474 }
1475
1476 if( eeconfig()->m_System.show_import_issues )
1477 pi->SetReporter( errorReporter.m_Reporter );
1478 else
1479 pi->SetReporter( &NULL_REPORTER::GetInstance() );
1480
1481 pi->SetProgressReporter( &progressReporter );
1482
1483 SCH_SHEET* loadedSheet = pi->LoadSchematicFile( aFileName, newSchematic.get(), nullptr,
1484 aProperties );
1485
1486 SetSchematic( newSchematic.release() );
1487
1488 if( loadedSheet )
1489 {
1490 Schematic().SetTopLevelSheets( { loadedSheet } );
1491
1492 if( errorReporter.m_Reporter->HasMessage() )
1493 {
1494 errorReporter.m_Reporter->Flush(); // Build HTML messages
1495 errorReporter.ShowModal();
1496 }
1497
1498 // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works
1499 // differently to KiCad), so set it to an empty one.
1501 drawingSheet.SetEmptyLayout();
1502 BASE_SCREEN::m_DrawingSheetFileName = "empty.kicad_wks";
1503
1504 newfilename.SetPath( Prj().GetProjectPath() );
1505 newfilename.SetName( Prj().GetProjectName() );
1506 newfilename.SetExt( FILEEXT::KiCadSchematicFileExtension );
1507
1508 SetScreen( Schematic().RootScreen() );
1509
1510 if( SCH_SHEET* topSheet = Schematic().GetTopLevelSheet() )
1511 topSheet->SetFileName( newfilename.GetFullName() );
1512
1513 GetScreen()->SetFileName( newfilename.GetFullPath() );
1515
1516 progressReporter.Report( _( "Updating connections..." ) );
1517
1518 if( !progressReporter.KeepRefreshing() )
1519 THROW_IO_ERROR( _( "File import canceled by user." ) );
1520
1521 RecalculateConnections( nullptr, GLOBAL_CLEANUP, &progressReporter );
1522
1523 // Only perform the dangling end test on root sheet.
1525 }
1526 else
1527 {
1529 }
1530 }
1531 catch( const IO_ERROR& ioe )
1532 {
1533 // Do not leave g_RootSheet == NULL because it is expected to be
1534 // a valid sheet. Therefore create a dummy empty root sheet and screen.
1537
1538 wxString msg = wxString::Format( _( "Error loading schematic '%s'." ), aFileName );
1539 DisplayErrorMessage( this, msg, ioe.What() );
1540
1541 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1542 SetMsgPanel( wxEmptyString, msg );
1543 }
1544 catch( const std::exception& exc )
1545 {
1548
1549 wxString msg = wxString::Format( _( "Unhandled exception occurred loading schematic "
1550 "'%s'." ), aFileName );
1551 DisplayErrorMessage( this, msg, exc.what() );
1552
1553 msg.Printf( _( "Failed to load '%s'." ), aFileName );
1554 SetMsgPanel( wxEmptyString, msg );
1555 }
1556
1559
1562 SyncView();
1563
1564 UpdateHierarchyNavigator( false, true );
1565
1566 wxCommandEvent e( EDA_EVT_SCHEMATIC_CHANGED );
1567 ProcessEventLocally( e );
1568
1569 for( wxEvtHandler* listener : m_schematicChangeListeners )
1570 {
1571 wxCHECK2( listener, continue );
1572
1573 // Use the windows variant when handling event messages in case there is any
1574 // special event handler pre and/or post processing specific to windows.
1575 wxWindow* win = dynamic_cast<wxWindow*>( listener );
1576
1577 if( win )
1578 win->HandleWindowEvent( e );
1579 else
1580 listener->SafelyProcessEvent( e );
1581 }
1582
1583 updateTitle();
1584
1585 if( KISTATUSBAR* statusBar = dynamic_cast<KISTATUSBAR*>( GetStatusBar() ) )
1586 statusBar->SetLoadWarningMessages( loadReporter.GetMessages() );
1587
1588 break;
1589 }
1590
1591 default:
1592 break;
1593 }
1594
1595 return true;
1596}
1597
1598
1600{
1601 SCH_SCREENS screenList( Schematic().Root() );
1602
1603 // Save any currently open and modified project files.
1604 for( SCH_SCREEN* screen = screenList.GetFirst(); screen; screen = screenList.GetNext() )
1605 {
1606 SIMULATOR_FRAME* simFrame = (SIMULATOR_FRAME*) Kiway().Player( FRAME_SIMULATOR, false );
1607
1608 // Simulator must be closed before loading another schematic, otherwise it may crash.
1609 // If there are any changes in the simulator the user will be prompted to save them.
1610 if( simFrame && !simFrame->Close() )
1611 return false;
1612
1613 if( screen->IsContentModified() )
1614 {
1615 if( !HandleUnsavedChanges( this, _( "The current schematic has been modified. "
1616 "Save changes?" ),
1617 [&]() -> bool
1618 {
1619 return SaveProject();
1620 } ) )
1621 {
1622 return false;
1623 }
1624 }
1625 }
1626
1627 return true;
1628}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
static TOOL_ACTION zoomFitScreen
Definition actions.h:142
void SetVirtualPageNumber(int aPageNumber)
Definition base_screen.h:76
static wxString m_DrawingSheetFileName
the name of the drawing sheet file, or empty to use the default drawing sheet
Definition base_screen.h:85
void SetContentModified(bool aModified=true)
Definition base_screen.h:59
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)
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:98
const KIID m_Uuid
Definition eda_item.h:522
EE_TYPE OfType(KICAD_T aType) const
Definition sch_rtree.h:241
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:95
bool IsSingle() const
Is this KIFACE running under single_top?
Definition kiid.h:49
wxString AsString() const
Definition kiid.cpp:246
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition kiway.cpp:403
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:206
@ FACE_SCH
eeschema DSO
Definition kiway.h:301
LOCAL_HISTORY & LocalHistory()
Return the LOCAL_HISTORY associated with this KIWAY.
Definition kiway.h:406
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< 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:49
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:111
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:100
UTF8 Format() const
Definition lib_id.cpp:119
bool TagSave(const wxString &aProjectPath, const wxString &aFileType)
Tag a manual save in the local history repository.
bool Init(const wxString &aProjectPath)
Initialize the local history repository for the given project path.
bool CommitFullProjectSnapshot(const wxString &aProjectPath, const wxString &aTitle)
Commit a snapshot of the entire project directory (excluding the .history directory and ignored trans...
static REPORTER & GetInstance()
Definition reporter.cpp:97
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:893
void HideSplash()
Definition pgm_base.cpp:305
A small class to help profiling.
Definition profile.h:49
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition profile.h:105
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:163
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:161
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition project.cpp:380
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:179
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:199
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:391
@ LEGACY_SYMBOL_LIBS
Definition project.h:72
Holds all the data relating to one schematic.
Definition schematic.h:88
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.
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
void FixupJunctionsAfterImport()
Add junctions to this schematic where required.
void SetProject(PROJECT *aPrj)
CONNECTION_GRAPH * ConnectionGraph() const
Definition schematic.h:199
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:132
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 UpdateVariantSelectionCtrl(const wxArrayString &aVariantNames)
Update the variant name control on the main toolbar.
std::vector< wxEvtHandler * > m_schematicChangeListeners
PANEL_REMOTE_SYMBOL * m_remoteSymbolPane
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 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.
void initScreenZoom()
Initialize the zoom value of the current screen and mark the screen as zoom-initialized.
void OnImportProject(wxCommandEvent &event)
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:167
Handle actions specific to the schematic editor.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:747
SCH_SCREEN * GetNext()
SCH_SCREEN * GetScreen(unsigned int aIndex) const
void UpdateSymbolLinks(REPORTER *aReporter=nullptr)
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in the full schematic.
SCH_SCREEN * GetFirst()
void PruneOrphanedSheetInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
void BuildClientSheetPathList()
Build the list of sheet paths sharing a screen for each screen in use.
bool HasSymbolFieldNamesWithWhiteSpace() const
size_t GetCount() const
Definition sch_screen.h:752
void PruneOrphanedSymbolInstances(const wxString &aProjectName, const SCH_SHEET_LIST &aValidSheetPaths)
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
SCH_SHEET * GetSheet(unsigned int aIndex) const
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
void ClearDrawingState()
Clear the state flags of all the items in the screen.
std::vector< SCH_SHEET_PATH > & GetClientSheetPaths()
Return the number of times this screen is used.
Definition sch_screen.h:187
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:118
const wxString & GetFileName() const
Definition sch_screen.h:153
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.
int GetFileFormatVersionAtLoad() const
Definition sch_screen.h:138
void AssignNewUuid()
Definition sch_screen.h:533
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:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:382
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:376
wxString GetName() const
Definition sch_sheet.h:142
void SetName(const wxString &aName)
Definition sch_sheet.h:143
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
bool IsVirtualRootSheet() const
Schematic symbol object.
Definition sch_symbol.h:76
void SetLibId(const LIB_ID &aName)
const LIB_ID & GetLibId() const override
Definition sch_symbol.h:165
void SaveProjectAs(const wxString &aFullPath, PROJECT *aProject=nullptr)
Set the currently loaded project path and saves it (pointers remain valid).
void SaveProjectCopy(const wxString &aFullPath, PROJECT *aProject=nullptr)
Save a copy of the current project under the given path.
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Save a loaded project.
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)
std::optional< LIB_STATUS > GetLibraryStatus(const wxString &aNickname) const override
Returns the status of a loaded library, or nullopt if the library hasn't been loaded (yet)
TOOL_MANAGER * m_toolManager
@ SUPERMODEL_RELOAD
For schematics, the entire schematic changed, not just the sheet.
Definition tool_base.h:81
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
Definition utf8.h:71
wxString wx_str() const
Definition utf8.cpp:45
Temporarily disable a window, and then re-enable on destruction.
Definition raii.h:87
static void ResolvePossibleSymlinks(wxFileName &aFilename)
void Flush()
Build the HTML messages page.
bool HasMessage() const override
Returns true if any messages were reported.
@ OUTDATED_SAVE
OUTDATED_SAVE Messages that should be cleared on save.
Definition wx_infobar.h:96
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:191
const wxString & GetMessages() const
Definition reporter.cpp:78
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:628
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:42
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:230
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:131
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
This file is part of the common library.
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:38
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:637
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:453
File locking utilities.
void SetShutdownBlockReason(wxWindow *aWindow, const wxString &aReason)
Sets the block reason why the window/application is preventing OS shutdown.
Definition unix/app.cpp:90
bool RegisterApplicationRestart(const wxString &aCommandLine)
Registers the application for restart with the OS with the given command line string to pass as args.
Definition unix/app.cpp:65
bool MakeWriteable(const wxString &aFilePath)
Ensures that a file has write permissions.
Definition unix/io.cpp:70
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:77
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:155
virtual void PreloadLibraries(KIWAY *aKiway)
Definition kiway.h:258
Information about a top-level schematic sheet.
std::string path
wxLogTrace helper definitions.
@ SCH_SYMBOL_T
Definition typeinfo.h:176
@ SCH_SHEET_T
Definition typeinfo.h:179
@ SCH_BUS_BUS_ENTRY_T
Definition typeinfo.h:166
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