KiCad PCB EDA Suite
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-2022 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 <confirm.h>
31#include <validators.h>
32#include <wx_filename.h>
35#include <kiplatform/ui.h>
36#include <sch_edit_frame.h>
37#include <sch_sheet.h>
38#include <schematic.h>
39#include <bitmaps.h>
40#include <eeschema_settings.h>
42#include <trace_helpers.h>
44#include "wx/dcclient.h"
45
47 bool* aClearAnnotationNewItems ) :
49 m_frame( aParent ),
50 m_clearAnnotationNewItems( aClearAnnotationNewItems ),
51 m_borderWidth( aParent, m_borderWidthLabel, m_borderWidthCtrl, m_borderWidthUnits ),
52 m_dummySheet( *aSheet ),
53 m_dummySheetNameField( wxDefaultPosition, SHEETNAME, &m_dummySheet )
54{
55 m_sheet = aSheet;
56 m_fields = new FIELDS_GRID_TABLE<SCH_FIELD>( this, aParent, m_grid, m_sheet );
59
60 // Give a bit more room for combobox editors
61 m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
62
64 m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
65 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
66
67 // Show/hide columns according to user's preference
68 auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
69 wxASSERT( cfg );
70
71 if( cfg )
72 {
73 m_shownColumns = cfg->m_Appearance.edit_sheet_visible_columns;
75 }
76
78 m_infoBar->ShowMessage( _( "Note: individual item colors overridden in Preferences." ) );
79
80 wxToolTip::Enable( true );
82
83 // Configure button logos
84 m_bpAdd->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
86 m_bpMoveUp->SetBitmap( KiBitmap( BITMAPS::small_up ) );
88
89 // Set font sizes
91 m_hierarchicalPath->SetFont( KIUI::GetInfoFont( this ) );
92
93 // wxFormBuilder doesn't include this event...
94 m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
96 nullptr, this );
97
99}
100
101
103{
104 auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
105 wxASSERT( cfg );
106
107 if( cfg )
108 cfg->m_Appearance.edit_sheet_visible_columns = m_grid->GetShownColumns();
109
110 // Prevents crash bug in wxGrid's d'tor
112
113 m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
115 nullptr, this );
116
117 // Delete the GRID_TRICKS.
118 m_grid->PopEventHandler( true );
119}
120
121
123{
124 if( !wxDialog::TransferDataToWindow() )
125 return false;
126
127 // Push a copy of each field into m_updateFields
128 for( SCH_FIELD& field : m_sheet->GetFields() )
129 {
130 SCH_FIELD field_copy( field );
131
132#ifdef __WINDOWS__
133 // Filenames are stored using unix notation
134 if( field_copy.GetId() == SHEETFILENAME )
135 {
136 wxString filename = field_copy.GetText();
137 filename.Replace( wxT( "/" ), wxT( "\\" ) );
138 field_copy.SetText( filename );
139 }
140#endif
141
142 // change offset to be symbol-relative
143 field_copy.Offset( -m_sheet->GetPosition() );
144
145 m_fields->push_back( field_copy );
146 }
147
148 // notify the grid
149 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
150 m_grid->ProcessTableMessage( msg );
152
153 // border width
155
156 // set up color swatches
157 KIGFX::COLOR4D borderColor = m_sheet->GetBorderColor();
158 KIGFX::COLOR4D backgroundColor = m_sheet->GetBackgroundColor();
159
160 m_borderSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
161 m_backgroundSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
162
163 m_borderSwatch->SetSwatchColor( borderColor, false );
164 m_backgroundSwatch->SetSwatchColor( backgroundColor, false );
165
169
172
173 instance.push_back( m_sheet );
174
175 wxString nextPageNumber = instance.GetPageNumber();
176
177 m_pageNumberTextCtrl->ChangeValue( nextPageNumber );
178
179 Layout();
180
181 return true;
182}
183
184
186{
187 LIB_ID id;
188
189 if( !m_grid->CommitPendingChanges() || !m_grid->Validate() )
190 return false;
191
192 // Check for missing field names.
193 for( size_t i = SHEET_MANDATORY_FIELDS; i < m_fields->size(); ++i )
194 {
195 SCH_FIELD& field = m_fields->at( i );
196 wxString fieldName = field.GetName( false );
197
198 if( fieldName.IsEmpty() )
199 {
200 DisplayErrorMessage( this, _( "Fields must have a name." ) );
201
204
205 return false;
206 }
207 }
208
209 return true;
210}
211
212
213static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
214{
215 if( a.GetPosition() != b.GetPosition() )
216 return true;
217
218 if( a.GetHorizJustify() != b.GetHorizJustify() )
219 return true;
220
221 if( a.GetVertJustify() != b.GetVertJustify() )
222 return true;
223
224 if( a.GetTextAngle() != b.GetTextAngle() )
225 return true;
226
227 return false;
228}
229
230
231static bool positioningChanged( FIELDS_GRID_TABLE<SCH_FIELD>* a, std::vector<SCH_FIELD>& b )
232{
233 for( size_t i = 0; i < SHEET_MANDATORY_FIELDS; ++i )
234 {
235 if( positioningChanged( a->at( i ), b.at( i ) ) )
236 return true;
237 }
238
239 return false;
240}
241
242
244{
245 if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
246 return false;
247
248 // Sheet file names can be relative or absolute.
249 wxString sheetFileName = m_fields->at( SHEETFILENAME ).GetText();
250
251 // Ensure filepath is not empty. (In normal use will be caught by grid validators,
252 // but unedited data from existing files can be bad.)
253 if( sheetFileName.IsEmpty() )
254 {
255 DisplayError( this, _( "A sheet must have a valid file name." ) );
256 return false;
257 }
258
259 // Ensure the filename extension is OK. In normal use will be caught by grid validators,
260 // but unedited data from existing files can be bad.
261 wxFileName fn( sheetFileName );
262
263 if( fn.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
264 {
265 DisplayError( this, _( "Sheet file must have a '.kicad_sch' extension." ) );
266 return false;
267 }
268
269 wxString newRelativeFilename = fn.GetFullPath();
270
271 // Inside Eeschema, filenames are stored using unix notation
272 newRelativeFilename.Replace( wxT( "\\" ), wxT( "/" ) );
273
274 wxString oldFilename = m_sheet->GetFields()[ SHEETFILENAME ].GetText();
275 oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
276
277 bool filename_changed = oldFilename != newRelativeFilename;
278
279 if( filename_changed || m_sheet->IsNew() )
280 {
281 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
282
283 wxCHECK( currentScreen, false );
284
285 bool clearFileName = false;
286
287 // This can happen for the root sheet when opening Eeschema in the stand alone mode.
288 if( currentScreen->GetFileName().IsEmpty() )
289 {
290 clearFileName = true;
291 currentScreen->SetFileName( m_frame->Prj().AbsolutePath( wxT( "noname.kicad_sch" ) ) );
292 }
293
294 wxFileName tmp( fn );
295 wxFileName screenFileName = currentScreen->GetFileName();
296
297 if( fn.IsAbsolute() && fn.MakeRelativeTo( screenFileName.GetPath() ) )
298 {
299 wxMessageDialog makeRelDlg( this, _( "Use relative path for sheet file?" ),
300 _( "Sheet File Path" ),
301 wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
302
303 makeRelDlg.SetExtendedMessage( _( "Using relative hierarchical sheet file name paths "
304 "improves schematic portability across systems and "
305 "platforms. Using absolute paths can result in "
306 "portability issues." ) );
307 makeRelDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Use Relative Path" ) ),
308 wxMessageDialog::ButtonLabel( _( "Use Absolute Path" ) ) );
309
310 if( makeRelDlg.ShowModal() == wxID_YES )
311 {
312 wxLogTrace( tracePathsAndFiles, "\n Converted absolute path: '%s'"
313 "\n to relative path: '%s'",
314 tmp.GetPath(),
315 fn.GetPath() );
316 m_fields->at( SHEETFILENAME ).SetText( fn.GetFullPath() );
317 newRelativeFilename = fn.GetFullPath();
318 }
319 }
320
321 if( !onSheetFilenameChanged( newRelativeFilename ) )
322 {
323 if( clearFileName )
324 currentScreen->SetFileName( wxEmptyString );
325
326 return false;
327 }
328
329 if( clearFileName )
330 currentScreen->SetFileName( wxEmptyString );
331
332 // One last validity check (and potential repair) just to be sure to be sure
333 SCH_SHEET_LIST repairedList( &m_frame->Schematic().Root(), true );
334 }
335
336 wxString newSheetname = m_fields->at( SHEETNAME ).GetText();
337
338 if( newSheetname.IsEmpty() )
339 newSheetname = _( "Untitled Sheet" );
340
341 m_fields->at( SHEETNAME ).SetText( newSheetname );
342
343 // change all field positions from relative to absolute
344 for( unsigned i = 0; i < m_fields->size(); ++i )
345 m_fields->at( i ).Offset( m_sheet->GetPosition() );
346
349
351
353
354 COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
355
356 if( colorSettings->GetOverrideSchItemColors()
359 {
360 wxPanel temp( this );
361 temp.Hide();
362 PANEL_EESCHEMA_COLOR_SETTINGS prefs( &temp );
363 wxString checkboxLabel = prefs.m_optOverrideColors->GetLabel();
364
365 KIDIALOG dlg( this, _( "Note: item colors are overridden in the current color theme." ),
367 dlg.ShowDetailedText( wxString::Format( _( "To see individual item colors uncheck '%s'\n"
368 "in Preferences > Eeschema > Colors." ),
369 checkboxLabel ) );
370 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
371 dlg.ShowModal();
372 }
373
376
378
379 instance.push_back( m_sheet );
380
381 instance.SetPageNumber( m_pageNumberTextCtrl->GetValue() );
382
384
385 // Refresh all sheets in case ordering changed.
386 for( SCH_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
387 m_frame->UpdateItem( item );
388
389 m_frame->OnModify();
390
391 return true;
392}
393
394
395bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilename )
396{
397 wxString msg;
398
399 // Sheet file names are relative to the path of the current sheet. This allows for
400 // nesting of schematic files in subfolders. Screen file names are always absolute.
401 wxFileName sheetFileName( aNewFilename );
402
403 if( sheetFileName.GetExt().IsEmpty() )
404 {
405 sheetFileName.SetExt( KiCadSchematicFileExtension );
406 }
407 else if( sheetFileName.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
408 {
409 msg = wxString::Format( _( "The file '%s' does not appear to be a valid schematic file." ),
410 sheetFileName.GetFullName() );
411 wxMessageDialog badSchFileDialog( this, msg, _( "Invalid Schematic File" ),
412 wxOK | wxCENTRE | wxICON_EXCLAMATION );
413 badSchFileDialog.ShowModal();
414 return false;
415 }
416
417 SCHEMATIC& schematic = m_frame->Schematic();
418 SCH_SCREEN* rootScreen = schematic.RootScreen();
419 SCH_SHEET_LIST fullHierarchy = schematic.GetFullHierarchy();
420 std::vector<SCH_SHEET_INSTANCE> sheetInstances = fullHierarchy.GetSheetInstances();
421 std::vector<SYMBOL_INSTANCE_REFERENCE> symbolInstances = rootScreen->GetSymbolInstances();
422 wxFileName screenFileName( sheetFileName );
423 wxFileName tmp( sheetFileName );
424
425 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
426
427 wxCHECK( currentScreen, false );
428
429 // SCH_SCREEN file names are always absolute.
430 wxFileName currentScreenFileName = currentScreen->GetFileName();
431
432 if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
433 currentScreenFileName.GetPath() ) )
434 {
435 msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
436 "'%s'\n"
437 "against parent sheet schematic file path:\n"
438 "'%s'." ),
439 sheetFileName.GetPath(),
440 currentScreenFileName.GetPath() );
441 DisplayError( this, msg );
442 return false;
443 }
444
445 wxString newAbsoluteFilename = screenFileName.GetFullPath();
446
447 // Inside Eeschema, filenames are stored using unix notation
448 newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
449
450 bool renameFile = false;
451 bool loadFromFile = false;
452 bool clearAnnotation = false;
453 bool isExistingSheet = false;
454 SCH_SCREEN* useScreen = nullptr;
455 SCH_SCREEN* oldScreen = nullptr;
456
457 // Search for a schematic file having the same filename already in use in the hierarchy
458 // or on disk, in order to reuse it.
459 if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
460 {
461 loadFromFile = wxFileExists( newAbsoluteFilename );
462
463 wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
464 newAbsoluteFilename,
465 loadFromFile ? "found" : "not found" );
466 }
467
468 if( m_sheet->GetScreen() == nullptr ) // New just created sheet.
469 {
470 if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
471 return false;
472
473 if( useScreen || loadFromFile ) // Load from existing file.
474 {
475 clearAnnotation = true;
476
477 if( !IsOK( this, wxString::Format( _( "'%s' already exists." ),
478 sheetFileName.GetFullName() )
479 + wxT( "\n\n" )
480 + wxString::Format( _( "Link '%s' to this file?" ),
481 newAbsoluteFilename ) ) )
482 {
483 return false;
484 }
485 }
486 else // New file.
487 {
488 m_frame->InitSheet( m_sheet, newAbsoluteFilename );
489 }
490 }
491 else // Existing sheet.
492 {
493 bool isUndoable = true;
494 isExistingSheet = true;
495
496 if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
497 return false;
498
499 // We are always using here a case insensitive comparison to avoid issues
500 // under Windows, although under Unix filenames are case sensitive.
501 // But many users create schematic under both Unix and Windows
502 // **
503 // N.B. 1: aSheet->GetFileName() will return a relative path
504 // aSheet->GetScreen()->GetFileName() returns a full path
505 //
506 // N.B. 2: newFilename uses the unix notation for separator.
507 // so we must use it also to compare the old and new filenames
508 wxString oldAbsoluteFilename = m_sheet->GetScreen()->GetFileName();
509 oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
510
511 if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
512 {
513 // Sheet file name changes cannot be undone.
514 isUndoable = false;
515
516 if( useScreen || loadFromFile ) // Load from existing file.
517 {
518 clearAnnotation = true;
519
520 if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
521 newAbsoluteFilename,
523 sheetFileName.GetFullName() )
524 + wxT( "\n\n" )
525 + _( "This action cannot be undone." ) ) )
526 {
527 return false;
528 }
529
530 if( loadFromFile )
531 m_sheet->SetScreen( nullptr );
532 }
533 else // Save to new file name.
534 {
535 if( m_sheet->GetScreenCount() > 1 )
536 {
537 if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents "
538 "of '%s'?" ),
539 sheetFileName.GetFullName(),
541 + wxT( "\n\n" )
542 + _( "This action cannot be undone." ) ) )
543 {
544 return false;
545 }
546 }
547
548 renameFile = true;
549 }
550 }
551
552 // If we are renaming files, the undo/redo list becomes invalid and must be cleared
553 if( isUndoable )
555 else
557
558 if( renameFile )
559 {
560 SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
561
562 // If the associated screen is shared by more than one sheet, do not
563 // change the filename of the corresponding screen here.
564 // (a new screen will be created later)
565 // if it is not shared, update the filename
566 if( m_sheet->GetScreenCount() <= 1 )
567 m_sheet->GetScreen()->SetFileName( newAbsoluteFilename );
568
569 try
570 {
571 pi->Save( newAbsoluteFilename, m_sheet, &schematic );
572 }
573 catch( const IO_ERROR& ioe )
574 {
575 msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ),
576 newAbsoluteFilename );
577 DisplayErrorMessage( this, msg, ioe.What() );
578
579 msg = wxString::Format( _( "Failed to save schematic '%s'" ),
580 newAbsoluteFilename );
581 m_frame->SetMsgPanel( wxEmptyString, msg );
582 return false;
583 }
584
585 // If the associated screen is shared by more than one sheet, remove the
586 // screen and reload the file to a new screen. Failure to do this will trash
587 // the screen reference counting in complex hierarchies.
588 if( m_sheet->GetScreenCount() > 1 )
589 {
590 oldScreen = m_sheet->GetScreen();
591 m_sheet->SetScreen( nullptr );
592 loadFromFile = true;
593 }
594 }
595 }
596
597 SCH_SHEET_PATH& currentSheet = m_frame->GetCurrentSheet();
598
599 if( useScreen )
600 {
601 // Create a temporary sheet for recursion testing to prevent a possible recursion error.
602 std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
603 tmpSheet->GetFields()[SHEETNAME] = m_fields->at( SHEETNAME );
604 tmpSheet->GetFields()[SHEETFILENAME].SetText( sheetFileName.GetFullPath() );
605 tmpSheet->SetScreen( useScreen );
606
607 // No need to check for valid library IDs if we are using an existing screen.
608 if( m_frame->CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
609 return false;
610
611 // It's safe to set the sheet screen now.
612 m_sheet->SetScreen( useScreen );
613 // currentSheet.LastScreen()->Append( m_sheet );
614 }
615 else if( loadFromFile )
616 {
617 bool restoreSheet = false;
618
619 if( isExistingSheet )
620 {
621 // Temporarily remove the sheet from the current schematic page so that recursion
622 // and symbol library link tests can be performed with the modified sheet settings.
623 restoreSheet = true;
624 currentSheet.LastScreen()->Remove( m_sheet );
625 }
626
627 if( !m_frame->LoadSheetFromFile( m_sheet, &currentSheet, newAbsoluteFilename )
628 || m_frame->CheckSheetForRecursion( m_sheet, &currentSheet ) )
629 {
630 if( restoreSheet )
631 {
632 // If we cleared the previous screen, restore it before returning to the user
633 if( oldScreen )
634 m_sheet->SetScreen( oldScreen );
635
636 currentSheet.LastScreen()->Append( m_sheet );
637 }
638
639 return false;
640 }
641
642 if( restoreSheet )
643 currentSheet.LastScreen()->Append( m_sheet );
644
645 // The full hierarchy needs to be reloaded due to the addition of a new sheet.
646 fullHierarchy = schematic.GetFullHierarchy();
647 fullHierarchy.UpdateSheetInstanceData( sheetInstances );
648 fullHierarchy.UpdateSymbolInstanceData( symbolInstances );
649 }
650
652 *m_clearAnnotationNewItems = clearAnnotation;
653
654 return true;
655}
656
657
659{
660 bool success = true;
661 wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
662 wxControl* control = editor->GetControl();
663 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
664
665 // Short-circuit the validator's more generic "can't be empty" message for the
666 // two mandatory fields:
667 if( event.GetRow() == SHEETNAME && event.GetCol() == FDC_VALUE )
668 {
669 if( textControl && textControl->IsEmpty() )
670 {
671 wxMessageBox( _( "A sheet must have a name." ) );
672 success = false;
673 }
674 }
675 else if( event.GetRow() == SHEETFILENAME && event.GetCol() == FDC_VALUE && textControl )
676 {
677 if( textControl->IsEmpty() )
678 {
679 wxMessageBox( _( "A sheet must have a file specified." ) );
680 success = false;
681 }
682 }
683
684 if( success && control && control->GetValidator() )
685 success = control->GetValidator()->Validate( control );
686
687 if( !success )
688 {
689 event.Veto();
690 m_delayedFocusRow = event.GetRow();
691 m_delayedFocusColumn = event.GetCol();
692 }
693
694 editor->DecRef();
695}
696
697
698void DIALOG_SHEET_PROPERTIES::OnAddField( wxCommandEvent& event )
699{
701 return;
702
703 int fieldID = m_fields->size();
704 SCH_FIELD newField( wxPoint( 0, 0 ), fieldID, m_sheet,
706
707 newField.SetTextAngle( m_fields->at( SHEETNAME ).GetTextAngle() );
708
709 m_fields->push_back( newField );
710
711 // notify the grid
712 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
713 m_grid->ProcessTableMessage( msg );
714
715 m_grid->MakeCellVisible( m_fields->size() - 1, 0 );
716 m_grid->SetGridCursor( m_fields->size() - 1, 0 );
717
718 m_grid->EnableCellEditControl();
719 m_grid->ShowCellEditControl();
720}
721
722
723void DIALOG_SHEET_PROPERTIES::OnDeleteField( wxCommandEvent& event )
724{
725 wxArrayInt selectedRows = m_grid->GetSelectedRows();
726
727 if( selectedRows.empty() && m_grid->GetGridCursorRow() >= 0 )
728 selectedRows.push_back( m_grid->GetGridCursorRow() );
729
730 if( selectedRows.empty() )
731 return;
732
733 for( int row : selectedRows )
734 {
735 if( row < SHEET_MANDATORY_FIELDS )
736 {
737 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
739 return;
740 }
741 }
742
743 m_grid->CommitPendingChanges( true /* quiet mode */ );
744
745 // Reverse sort so deleting a row doesn't change the indexes of the other rows.
746 selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
747
748 for( int row : selectedRows )
749 {
750 m_fields->erase( m_fields->begin() + row );
751
752 // notify the grid
753 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
754 m_grid->ProcessTableMessage( msg );
755
756 if( m_grid->GetNumberRows() > 0 )
757 {
758 m_grid->MakeCellVisible( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
759 m_grid->SetGridCursor( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
760 }
761 }
762}
763
764
765void DIALOG_SHEET_PROPERTIES::OnMoveUp( wxCommandEvent& event )
766{
768 return;
769
770 int i = m_grid->GetGridCursorRow();
771
772 if( i > SHEET_MANDATORY_FIELDS )
773 {
774 SCH_FIELD tmp = m_fields->at( (unsigned) i );
775 m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
776 m_fields->insert( m_fields->begin() + i - 1, tmp );
777 m_grid->ForceRefresh();
778
779 m_grid->SetGridCursor( i - 1, m_grid->GetGridCursorCol() );
780 m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
781 }
782 else
783 {
784 wxBell();
785 }
786}
787
788
789void DIALOG_SHEET_PROPERTIES::OnMoveDown( wxCommandEvent& event )
790{
792 return;
793
794 int i = m_grid->GetGridCursorRow();
795
796 if( i >= SHEET_MANDATORY_FIELDS && i < m_grid->GetNumberRows() - 1 )
797 {
798 SCH_FIELD tmp = m_fields->at( (unsigned) i );
799 m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
800 m_fields->insert( m_fields->begin() + i + 1, tmp );
801 m_grid->ForceRefresh();
802
803 m_grid->SetGridCursor( i + 1, m_grid->GetGridCursorCol() );
804 m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
805 }
806 else
807 {
808 wxBell();
809 }
810}
811
812
814{
815 // Account for scroll bars
817
818 m_grid->AutoSizeColumn( 0 );
819 m_grid->SetColSize( 0, std::max( 72, m_grid->GetColSize( 0 ) ) );
820
821 int fixedColsWidth = m_grid->GetColSize( 0 );
822
823 for( int i = 2; i < m_grid->GetNumberCols(); i++ )
824 fixedColsWidth += m_grid->GetColSize( i );
825
826 m_grid->SetColSize( 1, std::max( 120, width - fixedColsWidth ) );
827}
828
829
830void DIALOG_SHEET_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
831{
832 wxString shownColumns = m_grid->GetShownColumns();
833
834 if( shownColumns != m_shownColumns )
835 {
836 m_shownColumns = shownColumns;
837
838 if( !m_grid->IsCellEditControlShown() )
840 }
841
842 // Propagate changes in sheetname to displayed hierarchical path
843 wxString path = m_frame->GetCurrentSheet().PathHumanReadable( false );
844
845 if( path.Last() != '/' )
846 path.Append( '/' );
847
848 wxGridCellEditor* editor = m_grid->GetCellEditor( SHEETNAME, FDC_VALUE );
849 wxControl* control = editor->GetControl();
850 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
851 wxString sheetName;
852
853 if( textControl )
854 sheetName = textControl->GetValue();
855 else
856 sheetName = m_grid->GetCellValue( SHEETNAME, FDC_VALUE );
857
859 m_dummySheetNameField.SetText( sheetName );
861
862 editor->DecRef();
863
864 wxClientDC dc( m_hierarchicalPathLabel );
865 int width = m_sizerBottom->GetSize().x - m_stdDialogButtonSizer->GetSize().x
866 - m_hierarchicalPathLabel->GetSize().x
867 - 30;
868
869 path = wxControl::Ellipsize( path, dc, wxELLIPSIZE_START, width, wxELLIPSIZE_FLAGS_NONE );
870
871 if( m_hierarchicalPath->GetLabel() != path )
872 m_hierarchicalPath->SetLabel( path );
873
874 // Handle a delayed focus
875 if( m_delayedFocusRow >= 0 )
876 {
877 m_grid->SetFocus();
878 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
880
881 m_grid->EnableCellEditControl( true );
882 m_grid->ShowCellEditControl();
883
886 }
887}
888
889
890void DIALOG_SHEET_PROPERTIES::OnSizeGrid( wxSizeEvent& event )
891{
892 auto new_size = event.GetSize();
893
894 if( m_size != new_size )
895 {
896 m_size = new_size;
897
899 }
900
901 // Always propagate for a grid repaint (needed if the height changes, as well as width)
902 event.Skip();
903}
904
905
906void DIALOG_SHEET_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
907{
909
910 // Now all widgets have the size fixed, call FinishDialogSettings
912}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:105
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
DIALOG_SHEET_PROPERTIES(SCH_EDIT_FRAME *aParent, SCH_SHEET *aSheet, bool *aClearAnnotationNewItems)
void OnAddField(wxCommandEvent &event) override
void OnMoveDown(wxCommandEvent &event) override
void OnGridCellChanging(wxGridEvent &event)
void OnDeleteField(wxCommandEvent &event) override
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:120
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:389
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:149
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:152
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:163
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:193
EE_TYPE OfType(KICAD_T aType) const
Definition: sch_rtree.h:238
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
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:46
@ KD_WARNING
Definition: confirm.h:49
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:93
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:305
Holds all the data relating to one schematic.
Definition: schematic.h:61
SCH_SHEET_LIST & GetFullHierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:438
SCH_SCREEN * RootScreen() const
Helper to retrieve the screen of the root sheet.
Definition: schematic.cpp:117
SCH_SHEET & Root() const
Definition: schematic.h:91
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 *aHierarchy, const wxString &aFileName)
Load a the KiCad schematic file aFileName into the sheet aSheet.
Definition: sheet.cpp:105
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:623
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:97
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy)
Verify that aSheet will not cause a recursion error in aHierarchy.
Definition: sheet.cpp:47
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 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:50
wxString GetShownText(int aDepth=0, bool aAllowExtraText=true) const override
Return the string actually shown after processing of the base text.
Definition: sch_field.cpp:169
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1070
int GetId() const
Definition: sch_field.h:116
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: sch_field.cpp:827
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
void ClearFieldsAutoplaced()
Definition: sch_item.h:427
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:535
virtual void Save(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const STRING_UTF8_MAP *aProperties=nullptr)
Write aSchematic to a storage file in a format that this SCH_PLUGIN implementation knows about,...
Definition: sch_plugin.cpp:59
bool Remove(SCH_ITEM *aItem)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:272
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:110
const std::vector< SYMBOL_INSTANCE_REFERENCE > & GetSymbolInstances() const
Definition: sch_screen.h:489
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:145
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
std::vector< SCH_SHEET_INSTANCE > GetSheetInstances() const
Fetch the instance information for all of the sheets in the hiearchy.
void UpdateSheetInstanceData(const std::vector< SCH_SHEET_INSTANCE > &aSheetInstances)
Update all of the sheet instance information using aSheetInstances.
void UpdateSymbolInstanceData(const std::vector< SYMBOL_INSTANCE_REFERENCE > &aSymbolInstances)
Update all of the symbol instance information using aSymbolInstances.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
wxString PathHumanReadable(bool aUseShortRootName=true) const
Return the sheet path in a human readable form made from the sheet names.
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:55
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:113
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:300
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslated=true)
Definition: sch_sheet.cpp:55
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:91
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:707
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:116
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:104
VECTOR2I GetPosition() const override
Definition: sch_sheet.h:366
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
Definition: sch_sheet.cpp:331
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:112
void SetBorderWidth(int aWidth)
Definition: sch_sheet.h:110
int GetBorderWidth() const
Definition: sch_sheet.h:109
KIGFX::COLOR4D GetBackgroundColor() const
Definition: sch_sheet.h:115
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:226
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:95
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:193
wxString GetShownColumns()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:207
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:280
void ShowMessage(const wxString &aMessage, int aFlags=wxICON_INFORMATION) override
Show the info bar with the provided message and icon.
Definition: infobar.cpp:142
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:342
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:299
This file is part of the common library.
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
#define _(s)
@ FDC_NAME
@ FDC_VALUE
const std::string KiCadSchematicFileExtension
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
@ LAYER_SCHEMATIC_BACKGROUND
Definition: layer_ids.h:376
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: gtk/ui.cpp:126
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:144
must_if< error >::control< Rule > control
Definition: sim_serde.h:107
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
@ SHEET_MANDATORY_FIELDS
The first 2 are mandatory, and must be instantiated in SCH_SHEET.
Definition: sch_sheet.h:47
@ SHEETNAME
Definition: sch_sheet.h:43
@ SHEETFILENAME
Definition: sch_sheet.h:44
Functions for manipulating tab traversal in forms and dialogs.
wxLogTrace helper definitions.
@ SCH_SHEET_T
Definition: typeinfo.h:158
Custom text control validator definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition: wx_filename.h:38