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