KiCad PCB EDA Suite
Loading...
Searching...
No Matches
sheet.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <sch_draw_panel.h>
22#include <common.h>
23#include <confirm.h>
24#include <kiface_base.h>
25#include <project.h>
26#include <math/vector2wx.h>
27#include <string_utils.h>
28#include <trace_helpers.h>
30#include <wx_filename.h>
31#include <tool/tool_manager.h>
32#include <project_sch.h>
33#include <sch_edit_frame.h>
34#include <sch_io/sch_io.h>
35#include <sch_io/sch_io_mgr.h>
37#include <sch_sheet.h>
38#include <sch_sheet_path.h>
39#include <sch_view.h>
40#include <sch_painter.h>
41#include <schematic.h>
43#include <tool/actions.h>
44
45#include <wx/clipbrd.h>
46#include <wx/dcmemory.h>
47#include <wx/log.h>
48#include <wx/msgdlg.h>
49#include <wx/richmsgdlg.h>
50
51#include <advanced_config.h>
52#include <pgm_base.h>
54
56
57
59{
60 wxASSERT( aSheet && aCurrentSheet );
61
62 wxString msg;
63 SCH_SHEET_LIST schematicSheets = Schematic().Hierarchy();
64 SCH_SHEET_LIST loadedSheets( aSheet ); // This is the schematicSheets of the loaded file.
65
66 wxString destFilePath = aCurrentSheet->LastScreen()->GetFileName();
67
68 if( destFilePath.IsEmpty() )
69 {
70 // If file is unsaved then there can't (yet) be any recursion.
71 return false;
72 }
73
74 // SCH_SCREEN object file paths are expected to be absolute. If this assert fires,
75 // something is seriously broken.
76 wxASSERT_MSG( wxFileName( destFilePath ).IsAbsolute(), destFilePath + wxS( " is not absolute" ) );
77
78 if( schematicSheets.TestForRecursion( loadedSheets, destFilePath ) )
79 {
80 msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
81 "has the sheet '%s' or one of its subsheets as a parent somewhere in the "
82 "schematic hierarchy." ),
83 destFilePath );
84 DisplayError( this, msg );
85 return true;
86 }
87
88 return false;
89}
90
91
93{
94 wxASSERT( aSheet && aSheet->GetScreen() );
95
96 wxString msg;
97 SCH_SCREENS newScreens( aSheet );
98
99 if( newScreens.HasNoFullyDefinedLibIds() )
100 {
101 msg.Printf( _( "The schematic '%s' has not had its symbol library links remapped "
102 "to the symbol library table. The project this schematic belongs to "
103 "must first be remapped before it can be imported into the current "
104 "project." ),
105 aSheet->GetScreen()->GetFileName() );
106 DisplayInfoMessage( this, msg );
107 return true;
108 }
109
110 return false;
111}
112
113
114void SCH_EDIT_FRAME::InitSheet( SCH_SHEET* aSheet, const wxString& aNewFilename )
115{
116 SCH_SCREEN* newScreen = new SCH_SCREEN( &Schematic() );
117 aSheet->SetScreen( newScreen );
118 aSheet->GetScreen()->SetContentModified();
119 aSheet->GetScreen()->SetFileName( aNewFilename );
120
122 wxCHECK( cfg, /* void */ );
123
125 newScreen->SetPageSettings( GetScreen()->GetPageSettings() );
126
127 const TITLE_BLOCK& tb1 = GetScreen()->GetTitleBlock();
128 TITLE_BLOCK tb2 = newScreen->GetTitleBlock();
129
131 tb2.SetRevision( tb1.GetRevision() );
132
133 if( cfg->m_PageSettings.export_date )
134 tb2.SetDate( tb1.GetDate() );
135
137 tb2.SetTitle( tb1.GetTitle() );
138
140 tb2.SetCompany( tb1.GetCompany() );
141
143 tb2.SetComment( 0, tb1.GetComment( 0 ) );
144
146 tb2.SetComment( 1, tb1.GetComment( 1 ) );
147
149 tb2.SetComment( 2, tb1.GetComment( 2 ) );
150
152 tb2.SetComment( 3, tb1.GetComment( 3 ) );
153
155 tb2.SetComment( 4, tb1.GetComment( 4 ) );
156
158 tb2.SetComment( 5, tb1.GetComment( 5 ) );
159
161 tb2.SetComment( 6, tb1.GetComment( 6 ) );
162
164 tb2.SetComment( 7, tb1.GetComment( 7 ) );
165
167 tb2.SetComment( 8, tb1.GetComment( 8 ) );
168
169 newScreen->SetTitleBlock( tb2 );
170}
171
172
173bool SCH_EDIT_FRAME::ChangeSheetFile( SCH_SHEET* aSheet, const wxString& aNewFilename,
174 bool* aClearAnnotationNewItems, bool* aIsUndoable,
175 const wxString* aSourceSheetFilename )
176{
177 wxString msg;
178 SCHEMATIC& schematic = Schematic();
179
180 // Resolve text variables before touching disk. The field keeps the raw text for portability.
181 wxFileName sheetFileName( ExpandTextVars( aNewFilename, &schematic.Project() ) );
182 SCH_SCREEN* currentScreen = GetCurrentSheet().LastScreen();
183
184 wxCHECK( currentScreen, false );
185
186 // SCH_SCREEN file names are always absolute.
187 wxFileName currentScreenFileName = currentScreen->GetFileName();
188 wxFileName screenFileName( sheetFileName );
189
190 if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
191 currentScreenFileName.GetPath() ) )
192 {
193 msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
194 "'%s'\n"
195 "against parent sheet schematic file path:\n"
196 "'%s'." ),
197 sheetFileName.GetPath(),
198 currentScreenFileName.GetPath() );
199 DisplayError( this, msg );
200 return false;
201 }
202
203 wxString newAbsoluteFilename = screenFileName.GetFullPath();
204 newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
205
206 if( !AllowCaseSensitiveFileNameClashes( aSheet->GetFileName(), newAbsoluteFilename ) )
207 return false;
208
209 SCH_SHEET_LIST fullHierarchy = schematic.Hierarchy();
210
211 bool renameFile = false;
212 bool loadFromFile = false;
213 bool clearAnnotation = false;
214 bool isExistingSheet = false;
215 SCH_SCREEN* useScreen = nullptr;
216 SCH_SCREEN* oldScreen = nullptr;
217
218 // Search for a schematic file already in use in the hierarchy or on disk
219 if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
220 {
221 loadFromFile = wxFileExists( newAbsoluteFilename );
222
223 wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
224 newAbsoluteFilename,
225 loadFromFile ? "found" : "not found" );
226 }
227
228 if( aSheet->GetScreen() == nullptr )
229 {
230 // New sheet with no screen yet
231 if( useScreen || loadFromFile )
232 {
233 clearAnnotation = true;
234
235 if( !IsOK( this, wxString::Format( _( "'%s' already exists." ),
236 sheetFileName.GetFullName() )
237 + wxT( "\n\n" )
238 + wxString::Format( _( "Link '%s' to this file?" ),
239 newAbsoluteFilename ) ) )
240 {
241 return false;
242 }
243 }
244 else if( aSourceSheetFilename && !aSourceSheetFilename->IsEmpty() )
245 {
246 // Design block / sheet import -- copy source file to destination
247 loadFromFile = true;
248
249 if( !wxCopyFile( *aSourceSheetFilename, newAbsoluteFilename, false ) )
250 {
251 msg.Printf( _( "Failed to copy schematic file '%s' to destination '%s'." ),
252 *aSourceSheetFilename,
253 newAbsoluteFilename );
254 DisplayError( this, msg );
255 return false;
256 }
257 }
258 else
259 {
260 InitSheet( aSheet, newAbsoluteFilename );
261 }
262 }
263 else
264 {
265 // Existing sheet
266 isExistingSheet = true;
267
268 wxString oldAbsoluteFilename = aSheet->GetScreen()->GetFileName();
269 oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
270
271 if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
272 {
273 // Sheet file name changes cannot be undone
274 if( aIsUndoable )
275 *aIsUndoable = false;
276
277 if( useScreen || loadFromFile )
278 {
279 clearAnnotation = true;
280 oldScreen = aSheet->GetScreen();
281
282 if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
283 newAbsoluteFilename,
284 aSheet->GetFileName(),
285 sheetFileName.GetFullName() )
286 + wxT( "\n\n" )
287 + _( "This action cannot be undone." ) ) )
288 {
289 return false;
290 }
291
292 if( loadFromFile )
293 aSheet->SetScreen( nullptr );
294 }
295 else
296 {
297 // Save current content to new file name
298 if( aSheet->GetScreenCount() > 1 )
299 {
300 if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents "
301 "of '%s'?" ),
302 sheetFileName.GetFullName(),
303 aSheet->GetFileName() )
304 + wxT( "\n\n" )
305 + _( "This action cannot be undone." ) ) )
306 {
307 return false;
308 }
309 }
310
311 renameFile = true;
312 }
313 }
314
315 if( renameFile )
316 {
317 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
318
319 // Only update the screen filename when this is the sole user
320 if( aSheet->GetScreenCount() <= 1 )
321 aSheet->GetScreen()->SetFileName( newAbsoluteFilename );
322
323 try
324 {
325 pi->SaveSchematicFile( newAbsoluteFilename, aSheet, &schematic );
326 }
327 catch( const IO_ERROR& ioe )
328 {
329 msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ),
330 newAbsoluteFilename );
331 DisplayErrorMessage( this, msg, ioe.What() );
332
333 msg = wxString::Format( _( "Failed to save schematic '%s'" ),
334 newAbsoluteFilename );
335 SetMsgPanel( wxEmptyString, msg );
336 return false;
337 }
338
339 // Shared screen needs reload to maintain correct reference counting
340 if( aSheet->GetScreenCount() > 1 )
341 {
342 oldScreen = aSheet->GetScreen();
343 aSheet->SetScreen( nullptr );
344 loadFromFile = true;
345 }
346 }
347 }
348
349 SCH_SHEET_PATH& currentSheet = GetCurrentSheet();
350
351 if( useScreen )
352 {
353 // Recursion test with a temporary sheet
354 std::unique_ptr<SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
355 tmpSheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( sheetFileName.GetFullPath() );
356 tmpSheet->SetScreen( useScreen );
357
358 if( CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
359 return false;
360
361 aSheet->SetScreen( useScreen );
362
363 SCH_SHEET_LIST sheetHierarchy( aSheet );
364 sheetHierarchy.AddNewSymbolInstances( currentSheet, Prj().GetProjectName() );
365 sheetHierarchy.AddNewSheetInstances( currentSheet,
366 fullHierarchy.GetLastVirtualPageNumber() );
367 }
368 else if( loadFromFile )
369 {
370 bool restoreSheet = false;
371
372 if( isExistingSheet )
373 {
374 restoreSheet = true;
375 currentSheet.LastScreen()->Remove( aSheet );
376 }
377
378 if( !LoadSheetFromFile( aSheet, &currentSheet, newAbsoluteFilename, false, true )
379 || CheckSheetForRecursion( aSheet, &currentSheet ) )
380 {
381 if( restoreSheet )
382 {
383 if( oldScreen )
384 aSheet->SetScreen( oldScreen );
385
386 currentSheet.LastScreen()->Append( aSheet );
387 }
388
389 return false;
390 }
391
392 if( restoreSheet )
393 currentSheet.LastScreen()->Append( aSheet );
394 }
395
396 if( aClearAnnotationNewItems )
397 *aClearAnnotationNewItems = clearAnnotation;
398
400
401 SCH_SHEET_LIST repairedList;
402 repairedList.BuildSheetList( &schematic.Root(), true );
403
404 return true;
405}
406
407
409 const wxString& aFileName, bool aSkipRecursionCheck,
410 bool aSkipLibCheck )
411{
412 wxASSERT( aSheet && aCurrentSheet );
413
414 wxString msg;
415 wxFileName currentSheetFileName;
416 bool libTableChanged = false;
417
418 SCH_IO_MGR::SCH_FILE_T schFileType = SCH_IO_MGR::GuessPluginTypeFromSchPath( aFileName );
419
420 if( schFileType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
421 schFileType = SCH_IO_MGR::SCH_KICAD;
422
423 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( schFileType ) );
424 std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &Schematic() );
425
426 // This will cause the sheet UUID to be set to the UUID of the aSheet argument. This is
427 // required to ensure all of the sheet paths in any sub-sheets are correctly generated when
428 // using the temporary SCH_SHEET object that the file is loaded into..
429 const_cast<KIID&>( tmpSheet->m_Uuid ) = aSheet->m_Uuid;
430
431 wxFileName fileName( aFileName );
432
433 if( !fileName.IsAbsolute() && !fileName.MakeAbsolute() )
434 {
435 wxFAIL_MSG( wxString::Format( "Cannot make file name '%s' path absolute.", aFileName ) );
436 return false;
437 }
438
439 wxString fullFilename = fileName.GetFullPath();
440
441 try
442 {
443 if( aSheet->GetScreen() != nullptr )
444 {
445 tmpSheet.reset( pi->LoadSchematicFile( fullFilename, &Schematic() ) );
446 }
447 else
448 {
449 tmpSheet->SetFileName( fullFilename );
450 pi->LoadSchematicFile( fullFilename, &Schematic(), tmpSheet.get() );
451 }
452
453 if( !pi->GetError().IsEmpty() )
454 {
455 msg = _( "The entire schematic could not be loaded. Errors occurred attempting "
456 "to load hierarchical sheet schematics." );
457
458 KICAD_MESSAGE_DIALOG msgDlg1( this, msg, _( "Schematic Load Error" ),
459 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
460 wxCENTER | wxICON_QUESTION );
461 msgDlg1.SetOKLabel( wxMessageDialog::ButtonLabel( _( "Use partial schematic" ) ) );
462 msgDlg1.SetExtendedMessage( pi->GetError() );
463
464 if( msgDlg1.ShowModal() == wxID_CANCEL )
465 return false;
466 }
467 }
468 catch( const IO_ERROR& ioe )
469 {
470 msg.Printf( _( "Error loading schematic '%s'." ), fullFilename );
471 DisplayErrorMessage( this, msg, ioe.What() );
472
473 msg.Printf( _( "Failed to load '%s'." ), fullFilename );
474 SetMsgPanel( wxEmptyString, msg );
475
476 return false;
477 }
478
479 // If the loaded schematic is in a different folder from the current project and
480 // it contains hierarchical sheets, the hierarchical sheet paths need to be updated.
481 //
482 // Additionally, we need to make all backing screens absolute paths be in the current project
483 // path not the source path.
484 if( fileName.GetPathWithSep() != Prj().GetProjectPath() )
485 {
486 SCH_SHEET_LIST loadedSheets( tmpSheet.get() );
487
488 for( const SCH_SHEET_PATH& sheetPath : loadedSheets )
489 {
490 // Skip the loaded sheet since the user already determined if the file path should
491 // be relative or absolute.
492 if( sheetPath.size() == 1 )
493 continue;
494
495 wxString lastSheetPath = Prj().GetProjectPath();
496
497 for( unsigned i = 1; i < sheetPath.size(); i++ )
498 {
499 SCH_SHEET* sheet = sheetPath.at( i );
500 wxCHECK2( sheet, continue );
501
502 SCH_SCREEN* screen = sheet->GetScreen();
503 wxCHECK2( screen, continue );
504
505 // Use the screen file name which should always be absolute.
506 wxFileName loadedSheetFileName = screen->GetFileName();
507 wxCHECK2( loadedSheetFileName.IsAbsolute(), continue );
508
509 wxFileName tmp = loadedSheetFileName;
510 wxString sheetFileName;
511
512 if( tmp.MakeRelativeTo( lastSheetPath ) )
513 sheetFileName = tmp.GetFullPath();
514 else
515 sheetFileName = loadedSheetFileName.GetFullPath();
516
517 sheetFileName.Replace( wxT( "\\" ), wxT( "/" ) );
518 sheet->SetFileName( sheetFileName );
519 lastSheetPath = loadedSheetFileName.GetPath();
520 }
521 }
522 }
523
525 LIBRARY_TABLE* projectTable = adapter->ProjectTable().value_or( nullptr );
526
527 SCH_SHEET_LIST loadedSheets( tmpSheet.get() );
529 SCH_SHEET_LIST schematicSheets = Schematic().Hierarchy();
530
531 // Make sure any new sheet changes do not cause any recursion issues.
532 if( !aSkipRecursionCheck && CheckSheetForRecursion( tmpSheet.get(), aCurrentSheet ) )
533 return false;
534
535 if( checkForNoFullyDefinedLibIds( tmpSheet.get() ) )
536 return false;
537
538 // Make a valiant attempt to warn the user of all possible scenarios where there could
539 // be broken symbol library links.
540 wxArrayString names;
541 wxArrayString newLibNames;
542 SCH_SCREENS newScreens( tmpSheet.get() ); // All screens associated with the import.
543 SCH_SCREENS prjScreens( &Schematic().Root() );
544
545 newScreens.GetLibNicknames( names );
546
547 KICAD_MESSAGE_DIALOG::ButtonLabel okButtonLabel( _( "Continue Load" ) );
548 KICAD_MESSAGE_DIALOG::ButtonLabel cancelButtonLabel( _( "Cancel Load" ) );
549
550 // Prior to schematic file format 20221002, all symbol instance data was saved in the root
551 // sheet so loading a hierarchical sheet that is not the root sheet will have no symbol
552 // instance data. Give the user a chance to go back and save the project that contains this
553 // hierarchical sheet so the symbol instance data will be correct on load.
554 if( ( tmpSheet->GetScreen()->GetFileFormatVersionAtLoad() < 20221002 )
555 && tmpSheet->GetScreen()->GetSymbolInstances().empty() )
556 {
557 msg = _( "There are hierarchical sheets in the loaded schematic file from an older "
558 "file version resulting in missing symbol instance data. This will "
559 "result in all of the symbols in the loaded schematic to use either the "
560 "default instance setting or fall back to the library symbol settings. "
561 "Loading the project that uses this schematic file and saving to the "
562 "latest file version will resolve this issue.\n\n"
563 "Do you wish to continue?" );
564 KICAD_MESSAGE_DIALOG msgDlg7( this, msg, _( "Continue Load Schematic" ),
565 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER | wxICON_QUESTION );
566 msgDlg7.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
567
568 if( msgDlg7.ShowModal() == wxID_CANCEL )
569 return false;
570 }
571
572 if( !aSkipLibCheck && !prjScreens.HasSchematic( fullFilename ) )
573 {
574 if( fileName.GetPathWithSep() == Prj().GetProjectPath() )
575 {
576 // A schematic in the current project path that isn't part of the current project.
577 // It's possible the user copied this schematic from another project so the library
578 // links may not be available. Even this is check is no guarantee that all symbol
579 // library links are valid but it's better than nothing.
580 for( const wxString& name : names )
581 {
582 if( !PROJECT_SCH::SymbolLibAdapter( &Prj() )->HasLibrary( name ) )
583 newLibNames.Add( name );
584 }
585
586 if( !newLibNames.IsEmpty() )
587 {
588 msg = _( "There are library names in the selected schematic that are missing "
589 "from the current project library table. This may result in broken "
590 "symbol library references for the loaded schematic.\n\n"
591 "Do you wish to continue?" );
592 KICAD_MESSAGE_DIALOG msgDlg3( this, msg, _( "Continue Load Schematic" ),
593 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
594 wxCENTER | wxICON_QUESTION );
595 msgDlg3.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
596
597 if( msgDlg3.ShowModal() == wxID_CANCEL )
598 return false;
599 }
600 }
601 else if( fileName.GetPathWithSep() != Prj().GetProjectPath() && projectTable )
602 {
603 // A schematic loaded from a path other than the current project path.
604
605 // If there are symbol libraries in the imported schematic that are not in the
606 // symbol library table of this project, there could be a lot of broken symbol
607 // library links. Attempt to add the missing libraries to the project symbol
608 // library table.
609 wxArrayString duplicateLibNames;
610
611 for( const wxString& name : names )
612 {
613 if( !PROJECT_SCH::SymbolLibAdapter( &Prj() )->HasLibrary( name ) )
614 newLibNames.Add( name );
615 else
616 duplicateLibNames.Add( name );
617 }
618
619 wxFileName symLibTableFn( fileName.GetPath(), FILEEXT::SymbolLibraryTableFileName );
621
622 // If there are any new or duplicate libraries, check to see if it's possible that
623 // there could be any missing libraries that would cause broken symbol library links.
624 if( !newLibNames.IsEmpty() || !duplicateLibNames.IsEmpty() )
625 {
626 if( !symLibTableFn.Exists() || !symLibTableFn.IsFileReadable() )
627 {
628 msg = _( "The selected file was created as part of a different project. "
629 "Linking the file to this project may result in missing or "
630 "incorrect symbol library references.\n\n"
631 "Do you wish to continue?" );
632 KICAD_MESSAGE_DIALOG msgDlg4( this, msg, _( "Continue Load Schematic" ),
633 wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxCENTER
634 | wxICON_QUESTION );
635 msgDlg4.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
636
637 if( msgDlg4.ShowModal() == wxID_CANCEL )
638 return false;
639 }
640 else
641 {
642 if( !table.IsOk() )
643 {
644 msg.Printf( _( "Error loading the symbol library table '%s'." ),
645 symLibTableFn.GetFullPath() );
646 DisplayErrorMessage( nullptr, msg, table.ErrorDescription() );
647 return false;
648 }
649 }
650 }
651
652 // Check to see if any of the symbol libraries found in the appended schematic do
653 // not exist in the current project are missing from the appended project symbol
654 // library table.
655 if( !newLibNames.IsEmpty() )
656 {
657 bool missingLibNames = table.Rows().empty();
658
659 if( !missingLibNames )
660 {
661 for( const wxString& newLibName : newLibNames )
662 {
663 if( !table.HasRow( newLibName ) )
664 {
665 missingLibNames = true;
666 break;
667 }
668 }
669 }
670
671 if( missingLibNames )
672 {
673 msg = _( "There are symbol library names in the selected schematic that "
674 "are missing from the selected schematic project library table. "
675 "This may result in broken symbol library references.\n\n"
676 "Do you wish to continue?" );
677 KICAD_MESSAGE_DIALOG msgDlg5( this, msg, _( "Continue Load Schematic" ),
678 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
679 wxCENTER | wxICON_QUESTION );
680 msgDlg5.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
681
682 if( msgDlg5.ShowModal() == wxID_CANCEL )
683 return false;
684 }
685 }
686
687 // The library name already exists in the current project. Check to see if the
688 // duplicate name is the same library in the current project. If it's not, it's
689 // most likely that the symbol library links will be broken.
690 if( !duplicateLibNames.IsEmpty() && !table.Rows().empty() )
691 {
692 bool libNameConflict = false;
693
694 for( const wxString& duplicateLibName : duplicateLibNames )
695 {
696 const LIBRARY_TABLE_ROW* thisRow = nullptr;
697 const LIBRARY_TABLE_ROW* otherRow = nullptr;
698
699 if( adapter->HasLibrary( duplicateLibName ) )
700 thisRow = *adapter->GetRow( duplicateLibName );
701
702 if( table.HasRow( duplicateLibName ) )
703 otherRow = *table.Row( duplicateLibName );
704
705 // It's in the global library table so there is no conflict.
706 if( thisRow && !otherRow )
707 continue;
708
709 if( !thisRow || !otherRow )
710 continue;
711
712 wxFileName otherUriFileName;
713 wxString thisURI = LIBRARY_MANAGER::GetFullURI( thisRow, true );;
714 wxString otherURI = LIBRARY_MANAGER::GetFullURI( otherRow, false );
715
716 if( otherURI.Contains( "${KIPRJMOD}" ) || otherURI.Contains( "$(KIPRJMOD)" ) )
717 {
718 // Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
719 // not expand to a valid symbol library path.
720 otherUriFileName.SetPath( fileName.GetPath() );
721 otherUriFileName.SetFullName( otherURI.AfterLast( '}' ) );
722 otherURI = otherUriFileName.GetFullPath();
723 }
724
725 if( thisURI != otherURI )
726 {
727 libNameConflict = true;
728 break;
729 }
730 }
731
732 if( libNameConflict )
733 {
734 msg = _( "A duplicate library name that references a different library exists "
735 "in the current library table. This conflict cannot be resolved and "
736 "may result in broken symbol library references.\n\n"
737 "Do you wish to continue?" );
738 KICAD_MESSAGE_DIALOG msgDlg6( this, msg, _( "Continue Load Schematic" ),
739 wxOK | wxCANCEL | wxCANCEL_DEFAULT |
740 wxCENTER | wxICON_QUESTION );
741 msgDlg6.SetOKCancelLabels( okButtonLabel, cancelButtonLabel );
742
743 if( msgDlg6.ShowModal() == wxID_CANCEL )
744 return false;
745 }
746 }
747
748 // All (most?) of the possible broken symbol library link cases are covered. Map the
749 // new appended schematic project symbol library table entries to the current project
750 // symbol library table.
751 if( !newLibNames.IsEmpty() && !table.Rows().empty() )
752 {
753 for( const wxString& libName : newLibNames )
754 {
755 if( !table.HasRow( libName ) || adapter->HasLibrary( libName ) )
756 {
757 continue;
758 }
759
760 LIBRARY_TABLE_ROW* row = *table.Row( libName );
761
762 // Don't expand environment variable because KIPRJMOD will not be correct
763 // for a different project.
764 wxString uri = LIBRARY_MANAGER::GetFullURI( row, false );
765 wxFileName newLib;
766
767 if( uri.Contains( "${KIPRJMOD}" ) || uri.Contains( "$(KIPRJMOD)" ) )
768 {
769 // Cannot use relative paths here, "${KIPRJMOD}../path-to-cache-lib" does
770 // not expand to a valid symbol library path.
771 newLib.SetPath( fileName.GetPath() );
772 newLib.SetFullName( uri.AfterLast( '}' ) );
773 uri = newLib.GetFullPath();
774 }
775 else
776 {
777 uri = LIBRARY_MANAGER::GetFullURI( row, true );
778 }
779
780 // Add the library from the imported project to the current project
781 // symbol library table.
782
783 LIBRARY_TABLE_ROW& newRow = projectTable->InsertRow();
784
785 newRow.SetNickname( libName );
786 newRow.SetURI( uri );
787 newRow.SetType( row->Type() );
788 newRow.SetDescription( row->Description() );
789 newRow.SetOptions( row->Options() );
790
791 libTableChanged = true;
792 }
793 }
794 }
795 }
796
797 SCH_SCREEN* newScreen = tmpSheet->GetScreen();
798 wxCHECK_MSG( newScreen, false, "No screen defined for sheet." );
799
800 if( libTableChanged && projectTable )
801 {
802 projectTable->Save().map_error(
803 [&]( const LIBRARY_ERROR& aError )
804 {
805 KICAD_MESSAGE_DIALOG dlg( this, _( "Error saving library table." ), _( "File Save Error" ),
806 wxOK | wxICON_ERROR );
807 dlg.SetExtendedMessage( aError.message );
808 dlg.ShowModal();
809 } );
810 }
811
812 // Make the best attempt to set the symbol instance data for the loaded schematic.
813 if( newScreen->GetFileFormatVersionAtLoad() < 20221002 )
814 {
815 if( !newScreen->GetSymbolInstances().empty() )
816 {
817 // If the loaded schematic is a root sheet for another project, update the symbol
818 // instances.
819 loadedSheets.UpdateSymbolInstanceData( newScreen->GetSymbolInstances());
820 }
821 }
822
823 newScreen->MigrateSimModels();
824
825 // Attempt to create new symbol instances using the instance data loaded above.
826 loadedSheets.AddNewSymbolInstances( *aCurrentSheet, Prj().GetProjectName() );
827
828 // Add new sheet instance data.
829 loadedSheets.AddNewSheetInstances( *aCurrentSheet, schematicSheets.GetLastVirtualPageNumber() );
830
831 // It is finally safe to add or append the imported schematic.
832 if( aSheet->GetScreen() == nullptr )
833 aSheet->SetScreen( newScreen );
834 else
835 aSheet->GetScreen()->Append( newScreen );
836
837 SCH_SCREENS allProjectScreens( &Schematic().Root() );
838 allProjectScreens.ReplaceDuplicateTimeStamps();
839
840 return true;
841}
842
843
845 bool* aIsUndoable, bool* aClearAnnotationNewItems,
846 bool* aUpdateHierarchyNavigator,
847 wxString* aSourceSheetFilename )
848{
849 if( aSheet == nullptr || aHierarchy == nullptr )
850 return false;
851
852 // Get the new texts
853 DIALOG_SHEET_PROPERTIES dlg( this, aSheet, aIsUndoable, aClearAnnotationNewItems,
854 aUpdateHierarchyNavigator, aSourceSheetFilename );
855
856 if( dlg.ShowModal() == wxID_CANCEL )
857 return false;
858
860
861 return true;
862}
863
864
866{
867 wxRect drawArea;
868 BASE_SCREEN* screen = GetScreen();
869
870 drawArea.SetSize( ToWxSize( GetPageSizeIU() ) );
871
872 // Calculate a reasonable dc size, in pixels, and the dc scale to fit
873 // the drawings into the dc size
874 // scale is the ratio resolution (in PPI) / internal units
875 double ppi = 300; // Use 300 pixels per inch to create bitmap images on start
876 double inch2Iu = 1000.0 * schIUScale.IU_PER_MILS;
877 double scale = ppi / inch2Iu;
878
879 wxSize dcsize = drawArea.GetSize();
880
881 int maxdim = std::max( dcsize.x, dcsize.y );
882
883 // the max size in pixels of the bitmap used to build the sheet copy
884 const int maxbitmapsize = 5600;
885
886 while( int( maxdim * scale ) > maxbitmapsize )
887 {
888 ppi = ppi / 1.5;
889 scale = ppi / inch2Iu;
890 }
891
892 dcsize.x *= scale;
893 dcsize.y *= scale;
894
895 // Set draw offset, zoom... to values needed to draw in the memory DC
896 // after saving initial values:
897 VECTOR2I tmp_startvisu = screen->m_StartVisu;
898 VECTOR2I old_org = screen->m_DrawOrg;
899 screen->m_DrawOrg.x = screen->m_DrawOrg.y = 0;
900 screen->m_StartVisu.x = screen->m_StartVisu.y = 0;
901
902 wxMemoryDC dc;
903 wxBitmap image( dcsize );
904 dc.SelectObject( image );
905 dc.Clear();
906
907 GRResetPenAndBrush( &dc );
908 GRForceBlackPen( false );
909 dc.SetUserScale( scale, scale );
910
912
913 cfg->SetPrintDC( &dc );
914
915 // Init the color of the layer actually used to print the drawing sheet:
917
918 cfg->SetDefaultFont( eeconfig()->m_Appearance.default_font );
919
920 try
921 {
922 dc.SetUserScale( 1.0, 1.0 );
923 SCH_PRINTOUT printout( this, wxEmptyString );
924 // Ensure title block will be when printed on clipboard, regardless
925 // the current Cairo print option
926 EESCHEMA_SETTINGS* eecfg = eeconfig();
927 bool print_tb_opt = eecfg->m_Printing.title_block;
928 eecfg->m_Printing.title_block = true;
929 bool success = printout.PrintPage( GetScreen(), cfg->GetPrintDC(), false );
930 eecfg->m_Printing.title_block = print_tb_opt;
931
932 if( !success )
933 wxLogMessage( _( "Cannot create the schematic image") );
934 }
935 catch( ... )
936 {
937 wxLogMessage( "printout internal error" );
938 }
939
940 // Deselect Bitmap from DC before using the bitmap
941 dc.SelectObject( wxNullBitmap );
942
943 {
944 wxLogNull doNotLog; // disable logging of failed clipboard actions
945
946 if( wxTheClipboard->Open() )
947 {
948 // This data objects are held by the clipboard, so do not delete them in the app.
949 wxBitmapDataObject* clipbrd_data = new wxBitmapDataObject( image );
950 wxTheClipboard->SetData( clipbrd_data );
951 wxTheClipboard->Flush(); // Allow data to be available after closing KiCad
952 wxTheClipboard->Close();
953 }
954 }
955
956 GRForceBlackPen( false );
957
958 screen->m_StartVisu = tmp_startvisu;
959 screen->m_DrawOrg = old_org;
960}
961
962
964 const wxString& aSchematicFileName )
965{
966 wxString msg;
968 wxFileName fn = aSchematicFileName;
969
970 wxCHECK( fn.IsAbsolute(), false );
971
972 auto can_cause_issues = [&]() -> bool
973 {
974 wxFileName lhs;
975 wxFileName rhs = aSchematicFileName;
976 wxFileName old = aOldName;
977 wxString oldLower = old.GetFullName().Lower();
978 wxString rhsLower = rhs.GetFullName().Lower();
979 wxString lhsLower;
980
981 size_t count = 0;
982
983 wxCHECK( rhs.IsAbsolute(), false );
984
985 for( SCH_SHEET_PATH& sheet : sheets )
986 {
987 lhs = sheet.LastScreen()->GetFileName();
988
989 if( lhs.GetPath() != rhs.GetPath() )
990 continue;
991
992 lhsLower = lhs.GetFullName().Lower();
993
994 if( lhsLower == rhsLower && lhs.GetFullName() != rhs.GetFullName() )
995 count++;
996 }
997
998 // If we are renaming a sheet that is only used once, then we are not going to cause
999 // a case sensitivity issue.
1000 if( oldLower == rhsLower )
1001 return count > 1;
1002
1003 return count > 0;
1004 };
1005
1006 if( eeconfig()->m_Appearance.show_sheet_filename_case_sensitivity_dialog && can_cause_issues() )
1007 {
1008 msg.Printf( _( "The file name '%s' can cause issues with an existing file name\n"
1009 "already defined in the schematic on systems that support case\n"
1010 "insensitive file names. This will cause issues if you copy this\n"
1011 "project to an operating system that supports case insensitive file\n"
1012 "names.\n\nDo you wish to continue?" ),
1013 fn.GetName() );
1014
1015 wxRichMessageDialog dlg( this, msg, _( "Warning" ),
1016 wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
1017 dlg.ShowCheckBox( _( "Do not show this message again." ) );
1018 dlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Create New Sheet" ) ),
1019 wxMessageDialog::ButtonLabel( _( "Cancel" ) ) );
1020
1021 if( dlg.ShowModal() == wxID_NO )
1022 return false;
1023
1025 !dlg.IsCheckBoxChecked();
1026 }
1027
1028 return true;
1029}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
Handles how to draw a screen (a board, a schematic ...)
Definition base_screen.h:37
VECTOR2I m_DrawOrg
offsets for drawing the circuit on the screen
Definition base_screen.h:84
VECTOR2I m_StartVisu
Coordinates in drawing units of the current view position (upper left corner of device)
Definition base_screen.h:89
void SetContentModified(bool aModified=true)
Definition base_screen.h:55
int ShowModal() override
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
const KIID m_Uuid
Definition eda_item.h:531
PAGE_SETTINGS m_PageSettings
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:348
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()
void SetLayerColor(int aLayer, const COLOR4D &aColor)
Change the color used to draw a layer.
void SetDefaultFont(const wxString &aFont)
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
void SetPrintDC(wxDC *aDC)
Definition kiid.h:44
std::optional< LIBRARY_TABLE * > ProjectTable() const
Retrieves the project library table for this adapter type, or nullopt if one doesn't exist.
bool HasLibrary(const wxString &aNickname, bool aCheckEnabled=false) const
Test for the existence of aNickname in the library tables.
std::optional< LIBRARY_TABLE_ROW * > GetRow(const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH) const
Like LIBRARY_MANAGER::GetRow but filtered to the LIBRARY_TABLE_TYPE of this adapter.
std::optional< wxString > GetFullURI(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, bool aSubstituted=false)
Return the full location specifying URI for the LIB, either in original UI form or in environment var...
void SetOptions(const wxString &aOptions)
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetDescription(const wxString &aDescription)
const wxString & Type() const
void SetURI(const wxString &aUri)
const wxString & Description() const
const wxString & Options() const
LIBRARY_RESULT< void > Save()
LIBRARY_TABLE_ROW & InsertRow()
Builds a new row and inserts it at the end of the table; returning a reference to the row.
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
Holds all the data relating to one schematic.
Definition schematic.h:90
SCH_SHEET_LIST Hierarchy() const
Return the full schematic flattened hierarchical sheet list.
void RefreshHierarchy()
SCH_RENDER_SETTINGS * GetRenderSettings()
const VECTOR2I GetPageSizeIU() const override
Works off of GetPageSettings() to return the size of the paper page in the internal units of this par...
EESCHEMA_SETTINGS * eeconfig() const
const PAGE_INFO & GetPageSettings() const override
bool AllowCaseSensitiveFileNameClashes(const wxString &aOldName, const wxString &aSchematicFileName)
Check aSchematicFileName for a potential file name case sensitivity clashes.
Definition sheet.cpp:963
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void InitSheet(SCH_SHEET *aSheet, const wxString &aNewFilename)
Definition sheet.cpp:114
bool LoadSheetFromFile(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet, const wxString &aFileName, bool aSkipRecursionCheck=false, bool aSkipLibCheck=false)
Load a the KiCad schematic file aFileName into the sheet aSheet.
Definition sheet.cpp:408
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 DrawCurrentSheetToClipboard()
Use the wxWidgets print code to draw an image of the current sheet onto the clipboard.
Definition sheet.cpp:865
bool checkForNoFullyDefinedLibIds(SCH_SHEET *aSheet)
Verify that the symbol library links aSheet and all of its child sheets have been remapped to the sym...
Definition sheet.cpp:92
bool EditSheetProperties(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy, bool *aIsUndoable=nullptr, bool *aClearAnnotationNewItems=nullptr, bool *aUpdateHierarchyNavigator=nullptr, wxString *aSourceSheetFilename=nullptr)
Edit an existing sheet or add a new sheet to the schematic.
Definition sheet.cpp:844
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet)
Verify that aSheet will not cause a recursion error in aCurrentSheet.
Definition sheet.cpp:58
bool ChangeSheetFile(SCH_SHEET *aSheet, const wxString &aNewFilename, bool *aClearAnnotationNewItems=nullptr, bool *aIsUndoable=nullptr, const wxString *aSourceSheetFilename=nullptr)
Change the file backing a schematic sheet.
Definition sheet.cpp:173
static SCH_FILE_T GuessPluginTypeFromSchPath(const wxString &aSchematicPath, int aCtl=0)
Return a plugin type given a schematic using the file extension of aSchematicPath.
Custom print out for printing schematics.
bool PrintPage(SCH_SCREEN *aScreen, wxDC *aDC, bool aForPrinting)
Print the current SCH_SCREEN using a given wxDC.
Container class that holds multiple SCH_SCREEN objects in a hierarchy.
Definition sch_screen.h:746
bool HasNoFullyDefinedLibIds()
Test all of the schematic symbols to see if all LIB_ID objects library nickname is not set.
int ReplaceDuplicateTimeStamps()
Test all sheet and symbol objects in the schematic for duplicate time stamps and replaces them as nec...
bool HasSchematic(const wxString &aSchematicFileName)
Check if one of the schematics in the list of screens is aSchematicFileName.
size_t GetLibNicknames(wxArrayString &aLibNicknames)
Fetch all of the symbol library nicknames into aLibNicknames.
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
Definition sch_screen.h:164
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition sch_screen.h:138
const wxString & GetFileName() const
Definition sch_screen.h:150
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
const std::vector< SCH_SYMBOL_INSTANCE > & GetSymbolInstances() const
Definition sch_screen.h:519
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
int GetFileFormatVersionAtLoad() const
Definition sch_screen.h:135
TITLE_BLOCK & GetTitleBlock()
Definition sch_screen.h:161
void MigrateSimModels()
Migrate any symbols having V6 simulation models to their V7 equivalents.
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void AddNewSymbolInstances(const SCH_SHEET_PATH &aPrefixSheetPath, const wxString &aProjectName)
Attempt to add new symbol instances for all symbols in this list of sheet paths prefixed with aPrefix...
int GetLastVirtualPageNumber() const
void UpdateSymbolInstanceData(const std::vector< SCH_SYMBOL_INSTANCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
void AddNewSheetInstances(const SCH_SHEET_PATH &aPrefixSheetPath, int aLastVirtualPageNumber)
void BuildSheetList(SCH_SHEET *aSheet, bool aCheckIntegrity)
Build the list of sheets and their sheet path from aSheet.
bool TestForRecursion(const SCH_SHEET_LIST &aSrcSheetHierarchy, const wxString &aDestFileName)
Test every SCH_SHEET_PATH in this SCH_SHEET_LIST to verify if adding the sheets stored in aSrcSheetHi...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:376
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:370
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
int GetScreenCount() const
Return the number of times the associated screen for the sheet is being used.
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:37
const wxString & GetCompany() const
Definition title_block.h:92
void SetRevision(const wxString &aRevision)
Definition title_block.h:77
void SetComment(int aIdx, const wxString &aComment)
Definition title_block.h:97
const wxString & GetRevision() const
Definition title_block.h:82
void SetTitle(const wxString &aTitle)
Definition title_block.h:54
const wxString & GetDate() const
Definition title_block.h:72
const wxString & GetComment(int aIdx) const
void SetCompany(const wxString &aCompany)
Definition title_block.h:87
const wxString & GetTitle() const
Definition title_block.h:59
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
Definition title_block.h:67
TOOL_MANAGER * m_toolManager
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:59
The common library.
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition confirm.cpp:245
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
This file is part of the common library.
#define KICAD_MESSAGE_DIALOG
Definition confirm.h:48
#define _(s)
void GRForceBlackPen(bool flagforce)
Definition gr_basic.cpp:159
void GRResetPenAndBrush(wxDC *DC)
Definition gr_basic.cpp:73
static const std::string SymbolLibraryTableFileName
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition io_mgr.h:33
PROJECT & Prj()
Definition kicad.cpp:730
@ LAYER_DRAWINGSHEET
Sheet frame and title block.
Definition layer_ids.h:274
@ LAYER_SCHEMATIC_DRAWINGSHEET
Definition layer_ids.h:494
see class PGM_BASE
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
@ GLOBAL_CLEANUP
Definition schematic.h:79
const int scale
bool title_block
Whether or not to print title block.
wxString message
std::vector< std::vector< std::string > > table
wxLogTrace helper definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
wxSize ToWxSize(const VECTOR2I &aSize)
Definition vector2wx.h:51
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:35