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