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