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