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