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