KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_sheet_properties.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) 2009 Wayne Stambaugh <[email protected]>
5 * Copyright (C) 2014-2024 KiCad Developers, see CHANGELOG.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, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
26#include <kiface_base.h>
27#include <wx/string.h>
28#include <wx/log.h>
29#include <wx/tooltip.h>
30#include <common.h>
31#include <confirm.h>
32#include <validators.h>
33#include <wx_filename.h>
36#include <kiplatform/ui.h>
37#include <sch_edit_frame.h>
38#include <sch_sheet.h>
39#include <schematic.h>
40#include <bitmaps.h>
41#include <eeschema_settings.h>
43#include <trace_helpers.h>
45#include "wx/dcclient.h"
46
48 bool* aClearAnnotationNewItems,
49 bool* aUpdateHierarchyNavigator ) :
51 m_frame( aParent ),
52 m_clearAnnotationNewItems( aClearAnnotationNewItems ),
53 m_updateHierarchyNavigator( aUpdateHierarchyNavigator ),
54 m_borderWidth( aParent, m_borderWidthLabel, m_borderWidthCtrl, m_borderWidthUnits ),
55 m_dummySheet( *aSheet ),
56 m_dummySheetNameField( VECTOR2I( -1, -1 ), SHEETNAME, &m_dummySheet )
57{
58 m_sheet = aSheet;
59 m_fields = new FIELDS_GRID_TABLE<SCH_FIELD>( this, aParent, m_grid, m_sheet );
62
63 // Give a bit more room for combobox editors
64 m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
65
67 m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this,
68 [&]( wxCommandEvent& aEvent )
69 {
70 OnAddField( aEvent );
71 } ) );
72 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
73
74 // Show/hide columns according to user's preference
75 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
76 {
77 m_grid->ShowHideColumns( cfg->m_Appearance.edit_sheet_visible_columns );
79 }
80
82 m_infoBar->ShowMessage( _( "Note: individual item colors overridden in Preferences." ) );
83
84 wxSize minSize = m_pageNumberTextCtrl->GetMinSize();
85 int minWidth = m_pageNumberTextCtrl->GetTextExtent( wxT( "XXX.XXX" ) ).GetWidth();
86
87 m_pageNumberTextCtrl->SetMinSize( wxSize( minWidth, minSize.GetHeight() ) );
88
89 wxToolTip::Enable( true );
91
92 // Configure button logos
93 m_bpAdd->SetBitmap( KiBitmapBundle( BITMAPS::small_plus ) );
94 m_bpDelete->SetBitmap( KiBitmapBundle( BITMAPS::small_trash ) );
95 m_bpMoveUp->SetBitmap( KiBitmapBundle( BITMAPS::small_up ) );
96 m_bpMoveDown->SetBitmap( KiBitmapBundle( BITMAPS::small_down ) );
97
98 // Set font sizes
100 m_hierarchicalPath->SetFont( KIUI::GetInfoFont( this ) );
101
102 // wxFormBuilder doesn't include this event...
103 m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
105 nullptr, this );
106}
107
108
110{
111 if( EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() ) )
112 {
113 cfg->m_Appearance.edit_sheet_visible_columns = m_grid->GetShownColumnsAsString();
114 cfg->m_Appearance.edit_sheet_width = GetSize().x;
115 cfg->m_Appearance.edit_sheet_height = GetSize().y;
116 }
117
118 // Prevents crash bug in wxGrid's d'tor
120
121 m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
123 nullptr, this );
124
125 // Delete the GRID_TRICKS.
126 m_grid->PopEventHandler( true );
127}
128
129
131{
132 if( !wxDialog::TransferDataToWindow() )
133 return false;
134
135 // Push a copy of each field into m_updateFields
136 for( SCH_FIELD& field : m_sheet->GetFields() )
137 {
138 SCH_FIELD field_copy( field );
139
140#ifdef __WINDOWS__
141 // Filenames are stored using unix notation
142 if( field_copy.GetId() == SHEETFILENAME )
143 {
144 wxString filename = field_copy.GetText();
145 filename.Replace( wxT( "/" ), wxT( "\\" ) );
146 field_copy.SetText( filename );
147 }
148#endif
149
150 // change offset to be symbol-relative
151 field_copy.Offset( -m_sheet->GetPosition() );
152
153 m_fields->push_back( field_copy );
154 }
155
156 // notify the grid
157 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
158 m_grid->ProcessTableMessage( msg );
160
161 // border width
163
164 // set up color swatches
165 KIGFX::COLOR4D borderColor = m_sheet->GetBorderColor();
166 KIGFX::COLOR4D backgroundColor = m_sheet->GetBackgroundColor();
167
168 m_borderSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
169 m_backgroundSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
170
171 m_borderSwatch->SetSwatchColor( borderColor, false );
172 m_backgroundSwatch->SetSwatchColor( backgroundColor, false );
173
177
180
181 instance.push_back( m_sheet );
182
183 wxString pageNumber;
184
185 if( m_sheet->IsNew() )
186 {
187 // Don't try to be too clever when assigning the next availabe page number. Just use
188 // the number of sheets plus one.
189 pageNumber.Printf( wxT( "%d" ), static_cast<int>( hierarchy.size() ) + 1 );
190 instance.SetPageNumber( pageNumber );
191 }
192 else
193 {
194 pageNumber = instance.GetPageNumber();
195 }
196
197 m_pageNumberTextCtrl->ChangeValue( pageNumber );
198
199 return true;
200}
201
202
204{
205 LIB_ID id;
206
207 if( !m_grid->CommitPendingChanges() || !m_grid->Validate() )
208 return false;
209
210 // Check for missing field names.
211 for( size_t i = SHEET_MANDATORY_FIELDS; i < m_fields->size(); ++i )
212 {
213 SCH_FIELD& field = m_fields->at( i );
214
215 if( field.GetName( false ).empty() && !field.GetText().empty() )
216 {
217 DisplayErrorMessage( this, _( "Fields must have a name." ) );
218
221
222 return false;
223 }
224 }
225
226 return true;
227}
228
229
230static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
231{
232 if( a.GetPosition() != b.GetPosition() )
233 return true;
234
235 if( a.GetHorizJustify() != b.GetHorizJustify() )
236 return true;
237
238 if( a.GetVertJustify() != b.GetVertJustify() )
239 return true;
240
241 if( a.GetTextAngle() != b.GetTextAngle() )
242 return true;
243
244 return false;
245}
246
247
248static bool positioningChanged( FIELDS_GRID_TABLE<SCH_FIELD>* a, std::vector<SCH_FIELD>& b )
249{
250 for( size_t i = 0; i < SHEET_MANDATORY_FIELDS; ++i )
251 {
252 if( positioningChanged( a->at( i ), b.at( i ) ) )
253 return true;
254 }
255
256 return false;
257}
258
259
261{
262 if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
263 return false;
264
265 // Sheet file names can be relative or absolute.
266 wxString sheetFileName = m_fields->at( SHEETFILENAME ).GetText();
267
268 // Ensure filepath is not empty. (In normal use will be caught by grid validators,
269 // but unedited data from existing files can be bad.)
270 if( sheetFileName.IsEmpty() )
271 {
272 DisplayError( this, _( "A sheet must have a valid file name." ) );
273 return false;
274 }
275
276 // Ensure the filename extension is OK. (In normal use will be caught by grid validators,
277 // but unedited data from existing files can be bad.)
278 sheetFileName = EnsureFileExtension( sheetFileName, FILEEXT::KiCadSchematicFileExtension );
279
280 wxFileName fn( sheetFileName );
281 wxString newRelativeFilename = fn.GetFullPath();
282
283 // Inside Eeschema, filenames are stored using unix notation
284 newRelativeFilename.Replace( wxT( "\\" ), wxT( "/" ) );
285
286 wxString oldFilename = m_sheet->GetFields()[ SHEETFILENAME ].GetText();
287 oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
288
289 bool filename_changed = oldFilename != newRelativeFilename;
290
291 if( filename_changed || m_sheet->IsNew() )
292 {
293 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
294
295 wxCHECK( currentScreen, false );
296
297 bool clearFileName = false;
298
299 // This can happen for the root sheet when opening Eeschema in the stand alone mode.
300 if( currentScreen->GetFileName().IsEmpty() )
301 {
302 clearFileName = true;
303 currentScreen->SetFileName( m_frame->Prj().AbsolutePath( wxT( "noname.kicad_sch" ) ) );
304 }
305
306 wxFileName tmp( fn );
307 wxFileName screenFileName = currentScreen->GetFileName();
308
309 if( fn.IsAbsolute() && fn.MakeRelativeTo( screenFileName.GetPath() ) )
310 {
311 wxMessageDialog makeRelDlg( this, _( "Use relative path for sheet file?" ),
312 _( "Sheet File Path" ),
313 wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
314
315 makeRelDlg.SetExtendedMessage( _( "Using relative hierarchical sheet file name paths "
316 "improves schematic portability across systems and "
317 "platforms. Using absolute paths can result in "
318 "portability issues." ) );
319 makeRelDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Use Relative Path" ) ),
320 wxMessageDialog::ButtonLabel( _( "Use Absolute Path" ) ) );
321
322 if( makeRelDlg.ShowModal() == wxID_YES )
323 {
324 wxLogTrace( tracePathsAndFiles, "\n Converted absolute path: '%s'"
325 "\n to relative path: '%s'",
326 tmp.GetPath(),
327 fn.GetPath() );
328 m_fields->at( SHEETFILENAME ).SetText( fn.GetFullPath() );
329 newRelativeFilename = fn.GetFullPath();
330 }
331 }
332
333 if( !onSheetFilenameChanged( newRelativeFilename ) )
334 {
335 if( clearFileName )
336 currentScreen->SetFileName( wxEmptyString );
337
338 return false;
339 }
341 {
343 }
344
345 if( clearFileName )
346 currentScreen->SetFileName( wxEmptyString );
347
348 // One last validity check (and potential repair) just to be sure to be sure
349 SCH_SHEET_LIST repairedList( &m_frame->Schematic().Root(), true );
350 }
351
352 wxString newSheetname = m_fields->at( SHEETNAME ).GetText();
353
354 if( ( newSheetname != m_sheet->GetName() ) && m_updateHierarchyNavigator )
356
357 if( newSheetname.IsEmpty() )
358 newSheetname = _( "Untitled Sheet" );
359
360 m_fields->at( SHEETNAME ).SetText( newSheetname );
361
362 // change all field positions from relative to absolute
363 for( unsigned i = 0; i < m_fields->size(); ++i )
364 m_fields->at( i ).Offset( m_sheet->GetPosition() );
365
368
369 for( int ii = m_fields->GetNumberRows() - 1; ii >= SHEET_MANDATORY_FIELDS; ii-- )
370 {
371 SCH_FIELD& field = m_fields->at( ii );
372 const wxString& fieldName = field.GetCanonicalName();
373
374 if( field.IsEmpty() )
375 m_fields->erase( m_fields->begin() + ii );
376 else if( fieldName.IsEmpty() )
377 field.SetName( _( "untitled" ) );
378 }
379
381
383
384 COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
385
386 if( colorSettings->GetOverrideSchItemColors()
389 {
390 wxPanel temp( this );
391 temp.Hide();
392 PANEL_EESCHEMA_COLOR_SETTINGS prefs( &temp );
393 wxString checkboxLabel = prefs.m_optOverrideColors->GetLabel();
394
395 KIDIALOG dlg( this, _( "Note: item colors are overridden in the current color theme." ),
397 dlg.ShowDetailedText( wxString::Format( _( "To see individual item colors uncheck '%s'\n"
398 "in Preferences > Schematic Editor > Colors." ),
399 checkboxLabel ) );
400 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
401 dlg.ShowModal();
402 }
403
406
408
409 instance.push_back( m_sheet );
410
411 instance.SetPageNumber( m_pageNumberTextCtrl->GetValue() );
412
414
415 // Refresh all sheets in case ordering changed.
416 for( SCH_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
417 m_frame->UpdateItem( item );
418
419 m_frame->OnModify();
420
421 return true;
422}
423
424
425bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilename )
426{
427 wxString msg;
428 wxFileName sheetFileName(
430
431 // Sheet file names are relative to the path of the current sheet. This allows for
432 // nesting of schematic files in subfolders. Screen file names are always absolute.
433 SCHEMATIC& schematic = m_frame->Schematic();
434 SCH_SHEET_LIST fullHierarchy = schematic.GetFullHierarchy();
435 wxFileName screenFileName( sheetFileName );
436 wxFileName tmp( sheetFileName );
437
438 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
439
440 wxCHECK( currentScreen, false );
441
442 // SCH_SCREEN file names are always absolute.
443 wxFileName currentScreenFileName = currentScreen->GetFileName();
444
445 if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
446 currentScreenFileName.GetPath() ) )
447 {
448 msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
449 "'%s'\n"
450 "against parent sheet schematic file path:\n"
451 "'%s'." ),
452 sheetFileName.GetPath(),
453 currentScreenFileName.GetPath() );
454 DisplayError( this, msg );
455 return false;
456 }
457
458 wxString newAbsoluteFilename = screenFileName.GetFullPath();
459
460 // Inside Eeschema, filenames are stored using unix notation
461 newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
462
463 bool renameFile = false;
464 bool loadFromFile = false;
465 bool clearAnnotation = false;
466 bool isExistingSheet = false;
467 SCH_SCREEN* useScreen = nullptr;
468 SCH_SCREEN* oldScreen = nullptr;
469
470 // Search for a schematic file having the same filename already in use in the hierarchy
471 // or on disk, in order to reuse it.
472 if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
473 {
474 loadFromFile = wxFileExists( newAbsoluteFilename );
475
476 wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
477 newAbsoluteFilename,
478 loadFromFile ? "found" : "not found" );
479 }
480
481 if( m_sheet->GetScreen() == nullptr ) // New just created sheet.
482 {
483 if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
484 return false;
485
486 if( useScreen || loadFromFile ) // Load from existing file.
487 {
488 clearAnnotation = true;
489
490 if( !IsOK( this, wxString::Format( _( "'%s' already exists." ),
491 sheetFileName.GetFullName() )
492 + wxT( "\n\n" )
493 + wxString::Format( _( "Link '%s' to this file?" ),
494 newAbsoluteFilename ) ) )
495 {
496 return false;
497 }
498 }
499 else // New file.
500 {
501 m_frame->InitSheet( m_sheet, newAbsoluteFilename );
502 }
503 }
504 else // Existing sheet.
505 {
506 bool isUndoable = true;
507 isExistingSheet = true;
508
509 if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
510 return false;
511
512 // We are always using here a case insensitive comparison to avoid issues
513 // under Windows, although under Unix filenames are case sensitive.
514 // But many users create schematic under both Unix and Windows
515 // **
516 // N.B. 1: aSheet->GetFileName() will return a relative path
517 // aSheet->GetScreen()->GetFileName() returns a full path
518 //
519 // N.B. 2: newFilename uses the unix notation for separator.
520 // so we must use it also to compare the old and new filenames
521 wxString oldAbsoluteFilename = m_sheet->GetScreen()->GetFileName();
522 oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
523
524 if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
525 {
526 // Sheet file name changes cannot be undone.
527 isUndoable = false;
528
529 if( useScreen || loadFromFile ) // Load from existing file.
530 {
531 clearAnnotation = true;
532
533 if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
534 newAbsoluteFilename,
536 sheetFileName.GetFullName() )
537 + wxT( "\n\n" )
538 + _( "This action cannot be undone." ) ) )
539 {
540 return false;
541 }
542
543 if( loadFromFile )
544 m_sheet->SetScreen( nullptr );
545 }
546 else // Save to new file name.
547 {
548 if( m_sheet->GetScreenCount() > 1 )
549 {
550 if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents "
551 "of '%s'?" ),
552 sheetFileName.GetFullName(),
554 + wxT( "\n\n" )
555 + _( "This action cannot be undone." ) ) )
556 {
557 return false;
558 }
559 }
560
561 renameFile = true;
562 }
563 }
564
565 // If we are renaming files, the undo/redo list becomes invalid and must be cleared
566 if( isUndoable )
567 m_frame->SaveCopyInUndoList( m_frame->GetScreen(), m_sheet, UNDO_REDO::CHANGED, false );
568 else
570
571 if( renameFile )
572 {
573 IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
574
575 // If the associated screen is shared by more than one sheet, do not
576 // change the filename of the corresponding screen here.
577 // (a new screen will be created later)
578 // if it is not shared, update the filename
579 if( m_sheet->GetScreenCount() <= 1 )
580 m_sheet->GetScreen()->SetFileName( newAbsoluteFilename );
581
582 try
583 {
584 pi->SaveSchematicFile( newAbsoluteFilename, m_sheet, &schematic );
585 }
586 catch( const IO_ERROR& ioe )
587 {
588 msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ),
589 newAbsoluteFilename );
590 DisplayErrorMessage( this, msg, ioe.What() );
591
592 msg = wxString::Format( _( "Failed to save schematic '%s'" ),
593 newAbsoluteFilename );
594 m_frame->SetMsgPanel( wxEmptyString, msg );
595 return false;
596 }
597
598 // If the associated screen is shared by more than one sheet, remove the
599 // screen and reload the file to a new screen. Failure to do this will trash
600 // the screen reference counting in complex hierarchies.
601 if( m_sheet->GetScreenCount() > 1 )
602 {
603 oldScreen = m_sheet->GetScreen();
604 m_sheet->SetScreen( nullptr );
605 loadFromFile = true;
606 }
607 }
608 }
609
610 SCH_SHEET_PATH& currentSheet = m_frame->GetCurrentSheet();
611
612 if( useScreen )
613 {
614 // Create a temporary sheet for recursion testing to prevent a possible recursion error.
615 std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
616 tmpSheet->GetFields()[SHEETNAME] = m_fields->at( SHEETNAME );
617 tmpSheet->GetFields()[SHEETFILENAME].SetText( sheetFileName.GetFullPath() );
618 tmpSheet->SetScreen( useScreen );
619
620 // No need to check for valid library IDs if we are using an existing screen.
621 if( m_frame->CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
622 return false;
623
624 // It's safe to set the sheet screen now.
625 m_sheet->SetScreen( useScreen );
626 }
627 else if( loadFromFile )
628 {
629 bool restoreSheet = false;
630
631 if( isExistingSheet )
632 {
633 // Temporarily remove the sheet from the current schematic page so that recursion
634 // and symbol library link tests can be performed with the modified sheet settings.
635 restoreSheet = true;
636 currentSheet.LastScreen()->Remove( m_sheet );
637 }
638
639 if( !m_frame->LoadSheetFromFile( m_sheet, &currentSheet, newAbsoluteFilename )
640 || m_frame->CheckSheetForRecursion( m_sheet, &currentSheet ) )
641 {
642 if( restoreSheet )
643 {
644 // If we cleared the previous screen, restore it before returning to the user
645 if( oldScreen )
646 m_sheet->SetScreen( oldScreen );
647
648 currentSheet.LastScreen()->Append( m_sheet );
649 }
650
651 return false;
652 }
653
654 if( restoreSheet )
655 currentSheet.LastScreen()->Append( m_sheet );
656 }
657
659 *m_clearAnnotationNewItems = clearAnnotation;
660
661 // Rebuild the entire connection graph.
663
664 return true;
665}
666
667
669{
670 bool success = true;
671 wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
672 wxControl* control = editor->GetControl();
673 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
674
675 // Short-circuit the validator's more generic "can't be empty" message for the
676 // two mandatory fields:
677 if( event.GetRow() == SHEETNAME && event.GetCol() == FDC_VALUE )
678 {
679 if( textControl && textControl->IsEmpty() )
680 {
681 wxMessageBox( _( "A sheet must have a name." ) );
682 success = false;
683 }
684 }
685 else if( event.GetRow() == SHEETFILENAME && event.GetCol() == FDC_VALUE && textControl )
686 {
687 if( textControl->IsEmpty() )
688 {
689 wxMessageBox( _( "A sheet must have a file specified." ) );
690 success = false;
691 }
692 }
693
694 if( success && control && control->GetValidator() )
695 success = control->GetValidator()->Validate( control );
696
697 if( !success )
698 {
699 event.Veto();
700 m_delayedFocusRow = event.GetRow();
701 m_delayedFocusColumn = event.GetCol();
702 }
703
704 editor->DecRef();
705}
706
707
708void DIALOG_SHEET_PROPERTIES::OnAddField( wxCommandEvent& event )
709{
711 return;
712
713 int fieldID = m_fields->size();
714 SCH_FIELD newField( VECTOR2I( 0, 0 ), fieldID, m_sheet,
716
717 newField.SetTextAngle( m_fields->at( SHEETNAME ).GetTextAngle() );
718
719 m_fields->push_back( newField );
720
721 // notify the grid
722 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
723 m_grid->ProcessTableMessage( msg );
724
725 m_grid->MakeCellVisible( m_fields->size() - 1, 0 );
726 m_grid->SetGridCursor( m_fields->size() - 1, 0 );
727
728 m_grid->EnableCellEditControl();
729 m_grid->ShowCellEditControl();
730}
731
732
733void DIALOG_SHEET_PROPERTIES::OnDeleteField( wxCommandEvent& event )
734{
735 wxArrayInt selectedRows = m_grid->GetSelectedRows();
736
737 if( selectedRows.empty() && m_grid->GetGridCursorRow() >= 0 )
738 selectedRows.push_back( m_grid->GetGridCursorRow() );
739
740 if( selectedRows.empty() )
741 return;
742
743 for( int row : selectedRows )
744 {
745 if( row < SHEET_MANDATORY_FIELDS )
746 {
747 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
749 return;
750 }
751 }
752
753 m_grid->CommitPendingChanges( true /* quiet mode */ );
754
755 // Reverse sort so deleting a row doesn't change the indexes of the other rows.
756 selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
757
758 for( int row : selectedRows )
759 {
760 m_fields->erase( m_fields->begin() + row );
761
762 // notify the grid
763 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
764 m_grid->ProcessTableMessage( msg );
765
766 if( m_grid->GetNumberRows() > 0 )
767 {
768 m_grid->MakeCellVisible( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
769 m_grid->SetGridCursor( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
770 }
771 }
772}
773
774
775void DIALOG_SHEET_PROPERTIES::OnMoveUp( wxCommandEvent& event )
776{
778 return;
779
780 int i = m_grid->GetGridCursorRow();
781
782 if( i > SHEET_MANDATORY_FIELDS )
783 {
784 SCH_FIELD tmp = m_fields->at( (unsigned) i );
785 m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
786 m_fields->insert( m_fields->begin() + i - 1, tmp );
787 m_grid->ForceRefresh();
788
789 m_grid->SetGridCursor( i - 1, m_grid->GetGridCursorCol() );
790 m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
791 }
792 else
793 {
794 wxBell();
795 }
796}
797
798
799void DIALOG_SHEET_PROPERTIES::OnMoveDown( wxCommandEvent& event )
800{
802 return;
803
804 int i = m_grid->GetGridCursorRow();
805
806 if( i >= SHEET_MANDATORY_FIELDS && i < m_grid->GetNumberRows() - 1 )
807 {
808 SCH_FIELD tmp = m_fields->at( (unsigned) i );
809 m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
810 m_fields->insert( m_fields->begin() + i + 1, tmp );
811 m_grid->ForceRefresh();
812
813 m_grid->SetGridCursor( i + 1, m_grid->GetGridCursorCol() );
814 m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
815 }
816 else
817 {
818 wxBell();
819 }
820}
821
822
824{
825 // Account for scroll bars
827
828 m_grid->AutoSizeColumn( 0 );
829 m_grid->SetColSize( 0, std::max( 72, m_grid->GetColSize( 0 ) ) );
830
831 int fixedColsWidth = m_grid->GetColSize( 0 );
832
833 for( int i = 2; i < m_grid->GetNumberCols(); i++ )
834 fixedColsWidth += m_grid->GetColSize( i );
835
836 m_grid->SetColSize( 1, std::max( 120, width - fixedColsWidth ) );
837}
838
839
840void DIALOG_SHEET_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
841{
842 std::bitset<64> shownColumns = m_grid->GetShownColumns();
843
844 if( shownColumns != m_shownColumns )
845 {
846 m_shownColumns = shownColumns;
847
848 if( !m_grid->IsCellEditControlShown() )
850 }
851
852 // Propagate changes in sheetname to displayed hierarchical path
853 wxString path = m_frame->GetCurrentSheet().PathHumanReadable( false );
854
855 if( path.Last() != '/' )
856 path.Append( '/' );
857
858 wxGridCellEditor* editor = m_grid->GetCellEditor( SHEETNAME, FDC_VALUE );
859 wxControl* control = editor->GetControl();
860 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
861 wxString sheetName;
862
863 if( textControl )
864 sheetName = textControl->GetValue();
865 else
866 sheetName = m_grid->GetCellValue( SHEETNAME, FDC_VALUE );
867
869 m_dummySheetNameField.SetText( sheetName );
871
872 editor->DecRef();
873
874 wxClientDC dc( m_hierarchicalPathLabel );
875 int width = m_sizerBottom->GetSize().x - m_stdDialogButtonSizer->GetSize().x
876 - m_hierarchicalPathLabel->GetSize().x
877 - 30;
878
879 path = wxControl::Ellipsize( path, dc, wxELLIPSIZE_START, width, wxELLIPSIZE_FLAGS_NONE );
880
881 if( m_hierarchicalPath->GetLabel() != path )
882 m_hierarchicalPath->SetLabel( path );
883
884 // Handle a delayed focus
885 if( m_delayedFocusRow >= 0 )
886 {
887 m_grid->SetFocus();
888 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
890
891 m_grid->EnableCellEditControl( true );
892 m_grid->ShowCellEditControl();
893
896 }
897}
898
899
900void DIALOG_SHEET_PROPERTIES::OnSizeGrid( wxSizeEvent& event )
901{
902 auto new_size = event.GetSize();
903
904 if( m_size != new_size )
905 {
906 m_size = new_size;
907
909 }
910
911 // Always propagate for a grid repaint (needed if the height changes, as well as width)
912 event.Skip();
913}
914
915
916void DIALOG_SHEET_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
917{
919
920 // Now all widgets have the size fixed, call FinishDialogSettings
922
923 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
924
925 if( cfg && cfg->m_Appearance.edit_sheet_width > 0 && cfg->m_Appearance.edit_sheet_height > 0 )
927
928}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap)
Definition: bitmap.cpp:110
Color settings are a bit different than most of the settings objects in that there can be more than o...
bool GetOverrideSchItemColors() const
COLOR4D GetColor(int aLayer) const
void SetSwatchColor(const KIGFX::COLOR4D &aColor, bool aSendEvent)
Set the current swatch color directly.
KIGFX::COLOR4D GetSwatchColor() const
void SetDefaultColor(const KIGFX::COLOR4D &aColor)
Sets the color that will be chosen with the "Reset to Default" button in the chooser.
void SetSwatchBackground(const KIGFX::COLOR4D &aBackground)
Set the swatch background color.
Class DIALOG_SHEET_PROPERTIES_BASE.
wxStdDialogButtonSizer * m_stdDialogButtonSizer
void OnAddField(wxCommandEvent &event) override
void OnMoveDown(wxCommandEvent &event) override
void OnGridCellChanging(wxGridEvent &event)
void OnDeleteField(wxCommandEvent &event) override
DIALOG_SHEET_PROPERTIES(SCH_EDIT_FRAME *aParent, SCH_SHEET *aSheet, bool *aClearAnnotationNewItems, bool *aUpdateHierarchyNavigator)
bool onSheetFilenameChanged(const wxString &aNewFilename)
void OnSizeGrid(wxSizeEvent &event) override
FIELDS_GRID_TABLE< SCH_FIELD > * m_fields
void OnInitDlg(wxInitDialogEvent &event) override
void OnUpdateUI(wxUpdateUIEvent &event) override
void OnMoveUp(wxCommandEvent &event) override
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
virtual void ClearUndoRedoList()
Clear the undo and redo list using ClearUndoORRedoList()
void SetMsgPanel(const std::vector< MSG_PANEL_ITEM > &aList)
Clear the message panel and populates it with the contents of aList.
bool IsNew() const
Definition: eda_item.h:103
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:131
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:95
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:437
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:161
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:164
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:205
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
int GetNumberRows() override
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:47
@ KD_WARNING
Definition: confirm.h:50
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:56
int ShowModal() override
Definition: confirm.cpp:100
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
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:320
Holds all the data relating to one schematic.
Definition: schematic.h:75
SCH_SHEET_LIST & GetFullHierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:592
SCH_SHEET & Root() const
Definition: schematic.h:105
COLOR_SETTINGS * GetColorSettings(bool aForceRefresh=false) const override
Returns a pointer to the active color theme settings.
Schematic editor (Eeschema) main window.
bool LoadSheetFromFile(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet, const wxString &aFileName)
Load a the KiCad schematic file aFileName into the sheet aSheet.
Definition: sheet.cpp:164
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
bool AllowCaseSensitiveFileNameClashes(const wxString &aSchematicFileName)
Check aSchematicFileName for a potential file name case sensitivity clashes.
Definition: sheet.cpp:691
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:105
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, bool aDirtyConnectivity=true)
Create a copy of the current schematic item, and put it in the undo list.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void RecalculateConnections(SCH_COMMIT *aCommit, SCH_CLEANUP_FLAGS aCleanupFlags)
Generate the connection data for the entire schematic hierarchy.
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aCurrentSheet)
Verify that aSheet will not cause a recursion error in aCurrentSheet.
Definition: sheet.cpp:49
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false, bool aUpdateRtree=false) override
Mark an item for refresh.
void TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:52
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1274
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
Definition: sch_field.cpp:1039
int GetId() const
Definition: sch_field.h:128
bool IsEmpty()
Return true if both the name and value of the field are empty.
Definition: sch_field.h:147
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: sch_field.cpp:1007
void SetName(const wxString &aName)
Definition: sch_field.cpp:986
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:188
void SetText(const wxString &aText) override
Definition: sch_field.cpp:996
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:165
void ClearFieldsAutoplaced()
Definition: sch_item.h:494
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:150
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
const wxString & GetFileName() const
Definition: sch_screen.h:144
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
Definition: sch_screen.cpp:115
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:320
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:119
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:308
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslated=true)
Definition: sch_sheet.cpp:55
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:93
wxString GetName() const
Definition: sch_sheet.h:107
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:728
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:122
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:110
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:378
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
Definition: sch_sheet.cpp:352
int GetScreenCount() const
Return the number of times the associated screen for the sheet is being used.
Definition: sch_sheet.cpp:185
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:162
KIGFX::COLOR4D GetBorderColor() const
Definition: sch_sheet.h:118
void SetBorderWidth(int aWidth)
Definition: sch_sheet.h:116
int GetBorderWidth() const
Definition: sch_sheet.h:115
KIGFX::COLOR4D GetBackgroundColor() const
Definition: sch_sheet.h:121
void SetBitmap(const wxBitmapBundle &aBmp)
virtual long long int GetValue()
Return the current value in Internal Units.
virtual void SetValue(long long int aValue)
Set new value (in Internal Units) for the text field, taking care of units conversion.
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:312
void SetTable(wxGridTableBase *table, bool aTakeOwnership=false)
Hide wxGrid's SetTable() method with one which doesn't mess up the grid column widths when setting th...
Definition: wx_grid.cpp:156
void DestroyTable(wxGridTableBase *aTable)
Work-around for a bug in wxGrid which crashes when deleting the table if the cell edit control was no...
Definition: wx_grid.cpp:268
wxString GetShownColumnsAsString()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:282
std::bitset< 64 > GetShownColumns()
Definition: wx_grid.cpp:301
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:462
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: wx_infobar.cpp:154
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:415
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:360
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:280
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:305
This file is part of the common library.
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
const int minSize
Push and Shove router track width and via size dialog.
#define _(s)
@ FDC_NAME
@ FDC_VALUE
static const std::string KiCadSchematicFileExtension
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
@ LAYER_SCHEMATIC_BACKGROUND
Definition: layer_ids.h:388
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: gtk/ui.cpp:195
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:151
@ GLOBAL_CLEANUP
@ SHEET_MANDATORY_FIELDS
The first 2 are mandatory, and must be instantiated in SCH_SHEET.
Definition: sch_sheet.h:49
@ SHEETNAME
Definition: sch_sheet.h:45
@ SHEETFILENAME
Definition: sch_sheet.h:46
wxLogTrace helper definitions.
@ SCH_SHEET_T
Definition: typeinfo.h:162
Custom text control validator definitions.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:39