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