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