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