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