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( KiBitmap( BITMAPS::small_plus ) );
92 m_bpDelete->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
93 m_bpMoveUp->SetBitmap( KiBitmap( BITMAPS::small_up ) );
94 m_bpMoveDown->SetBitmap( KiBitmap( 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 wxString fieldName = field.GetName( false );
213
214 if( fieldName.IsEmpty() )
215 {
216 DisplayErrorMessage( this, _( "Fields must have a name." ) );
217
220
221 return false;
222 }
223 }
224
225 return true;
226}
227
228
229static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
230{
231 if( a.GetPosition() != b.GetPosition() )
232 return true;
233
234 if( a.GetHorizJustify() != b.GetHorizJustify() )
235 return true;
236
237 if( a.GetVertJustify() != b.GetVertJustify() )
238 return true;
239
240 if( a.GetTextAngle() != b.GetTextAngle() )
241 return true;
242
243 return false;
244}
245
246
247static bool positioningChanged( FIELDS_GRID_TABLE<SCH_FIELD>* a, std::vector<SCH_FIELD>& b )
248{
249 for( size_t i = 0; i < SHEET_MANDATORY_FIELDS; ++i )
250 {
251 if( positioningChanged( a->at( i ), b.at( i ) ) )
252 return true;
253 }
254
255 return false;
256}
257
258
260{
261 if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
262 return false;
263
264 // Sheet file names can be relative or absolute.
265 wxString sheetFileName = m_fields->at( SHEETFILENAME ).GetText();
266
267 // Ensure filepath is not empty. (In normal use will be caught by grid validators,
268 // but unedited data from existing files can be bad.)
269 if( sheetFileName.IsEmpty() )
270 {
271 DisplayError( this, _( "A sheet must have a valid file name." ) );
272 return false;
273 }
274
275 // Ensure the filename extension is OK. (In normal use will be caught by grid validators,
276 // but unedited data from existing files can be bad.)
277 sheetFileName = EnsureFileExtension( sheetFileName, KiCadSchematicFileExtension );
278
279 wxFileName fn( sheetFileName );
280 wxString newRelativeFilename = fn.GetFullPath();
281
282 // Inside Eeschema, filenames are stored using unix notation
283 newRelativeFilename.Replace( wxT( "\\" ), wxT( "/" ) );
284
285 wxString oldFilename = m_sheet->GetFields()[ SHEETFILENAME ].GetText();
286 oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
287
288 bool filename_changed = oldFilename != newRelativeFilename;
289
290 if( filename_changed || m_sheet->IsNew() )
291 {
292 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
293
294 wxCHECK( currentScreen, false );
295
296 bool clearFileName = false;
297
298 // This can happen for the root sheet when opening Eeschema in the stand alone mode.
299 if( currentScreen->GetFileName().IsEmpty() )
300 {
301 clearFileName = true;
302 currentScreen->SetFileName( m_frame->Prj().AbsolutePath( wxT( "noname.kicad_sch" ) ) );
303 }
304
305 wxFileName tmp( fn );
306 wxFileName screenFileName = currentScreen->GetFileName();
307
308 if( fn.IsAbsolute() && fn.MakeRelativeTo( screenFileName.GetPath() ) )
309 {
310 wxMessageDialog makeRelDlg( this, _( "Use relative path for sheet file?" ),
311 _( "Sheet File Path" ),
312 wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION | wxCENTER );
313
314 makeRelDlg.SetExtendedMessage( _( "Using relative hierarchical sheet file name paths "
315 "improves schematic portability across systems and "
316 "platforms. Using absolute paths can result in "
317 "portability issues." ) );
318 makeRelDlg.SetYesNoLabels( wxMessageDialog::ButtonLabel( _( "Use Relative Path" ) ),
319 wxMessageDialog::ButtonLabel( _( "Use Absolute Path" ) ) );
320
321 if( makeRelDlg.ShowModal() == wxID_YES )
322 {
323 wxLogTrace( tracePathsAndFiles, "\n Converted absolute path: '%s'"
324 "\n to relative path: '%s'",
325 tmp.GetPath(),
326 fn.GetPath() );
327 m_fields->at( SHEETFILENAME ).SetText( fn.GetFullPath() );
328 newRelativeFilename = fn.GetFullPath();
329 }
330 }
331
332 if( !onSheetFilenameChanged( newRelativeFilename ) )
333 {
334 if( clearFileName )
335 currentScreen->SetFileName( wxEmptyString );
336
337 return false;
338 }
339
340 if( clearFileName )
341 currentScreen->SetFileName( wxEmptyString );
342
343 // One last validity check (and potential repair) just to be sure to be sure
344 SCH_SHEET_LIST repairedList( &m_frame->Schematic().Root(), true );
345 }
346
347 wxString newSheetname = m_fields->at( SHEETNAME ).GetText();
348
349 if( newSheetname.IsEmpty() )
350 newSheetname = _( "Untitled Sheet" );
351
352 m_fields->at( SHEETNAME ).SetText( newSheetname );
353
354 // change all field positions from relative to absolute
355 for( unsigned i = 0; i < m_fields->size(); ++i )
356 m_fields->at( i ).Offset( m_sheet->GetPosition() );
357
360
361 for( int ii = m_fields->GetNumberRows() - 1; ii >= SHEET_MANDATORY_FIELDS; ii-- )
362 {
363 SCH_FIELD& field = m_fields->at( ii );
364 const wxString& fieldName = field.GetCanonicalName();
365
366 if( fieldName.IsEmpty() && field.GetText().IsEmpty() )
367 m_fields->erase( m_fields->begin() + ii );
368 else if( fieldName.IsEmpty() )
369 field.SetName( _( "untitled" ) );
370 }
371
373
375
376 COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
377
378 if( colorSettings->GetOverrideSchItemColors()
381 {
382 wxPanel temp( this );
383 temp.Hide();
384 PANEL_EESCHEMA_COLOR_SETTINGS prefs( &temp );
385 wxString checkboxLabel = prefs.m_optOverrideColors->GetLabel();
386
387 KIDIALOG dlg( this, _( "Note: item colors are overridden in the current color theme." ),
389 dlg.ShowDetailedText( wxString::Format( _( "To see individual item colors uncheck '%s'\n"
390 "in Preferences > Schematic Editor > Colors." ),
391 checkboxLabel ) );
392 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
393 dlg.ShowModal();
394 }
395
398
400
401 instance.push_back( m_sheet );
402
403 instance.SetPageNumber( m_pageNumberTextCtrl->GetValue() );
404
406
407 // Refresh all sheets in case ordering changed.
408 for( SCH_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
409 m_frame->UpdateItem( item );
410
411 m_frame->OnModify();
412
413 return true;
414}
415
416
417bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilename )
418{
419 wxString msg;
420 wxFileName sheetFileName( EnsureFileExtension( aNewFilename, KiCadSchematicFileExtension ) );
421
422 // Sheet file names are relative to the path of the current sheet. This allows for
423 // nesting of schematic files in subfolders. Screen file names are always absolute.
424 SCHEMATIC& schematic = m_frame->Schematic();
425 SCH_SHEET_LIST fullHierarchy = schematic.GetFullHierarchy();
426 wxFileName screenFileName( sheetFileName );
427 wxFileName tmp( sheetFileName );
428
429 SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
430
431 wxCHECK( currentScreen, false );
432
433 // SCH_SCREEN file names are always absolute.
434 wxFileName currentScreenFileName = currentScreen->GetFileName();
435
436 if( !screenFileName.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS,
437 currentScreenFileName.GetPath() ) )
438 {
439 msg = wxString::Format( _( "Cannot normalize new sheet schematic file path:\n"
440 "'%s'\n"
441 "against parent sheet schematic file path:\n"
442 "'%s'." ),
443 sheetFileName.GetPath(),
444 currentScreenFileName.GetPath() );
445 DisplayError( this, msg );
446 return false;
447 }
448
449 wxString newAbsoluteFilename = screenFileName.GetFullPath();
450
451 // Inside Eeschema, filenames are stored using unix notation
452 newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
453
454 bool renameFile = false;
455 bool loadFromFile = false;
456 bool clearAnnotation = false;
457 bool isExistingSheet = false;
458 SCH_SCREEN* useScreen = nullptr;
459 SCH_SCREEN* oldScreen = nullptr;
460
461 // Search for a schematic file having the same filename already in use in the hierarchy
462 // or on disk, in order to reuse it.
463 if( !schematic.Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
464 {
465 loadFromFile = wxFileExists( newAbsoluteFilename );
466
467 wxLogTrace( tracePathsAndFiles, "\n Sheet requested file '%s', %s",
468 newAbsoluteFilename,
469 loadFromFile ? "found" : "not found" );
470 }
471
472 if( m_sheet->GetScreen() == nullptr ) // New just created sheet.
473 {
474 if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
475 return false;
476
477 if( useScreen || loadFromFile ) // Load from existing file.
478 {
479 clearAnnotation = true;
480
481 if( !IsOK( this, wxString::Format( _( "'%s' already exists." ),
482 sheetFileName.GetFullName() )
483 + wxT( "\n\n" )
484 + wxString::Format( _( "Link '%s' to this file?" ),
485 newAbsoluteFilename ) ) )
486 {
487 return false;
488 }
489 }
490 else // New file.
491 {
492 m_frame->InitSheet( m_sheet, newAbsoluteFilename );
493 }
494 }
495 else // Existing sheet.
496 {
497 bool isUndoable = true;
498 isExistingSheet = true;
499
500 if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
501 return false;
502
503 // We are always using here a case insensitive comparison to avoid issues
504 // under Windows, although under Unix filenames are case sensitive.
505 // But many users create schematic under both Unix and Windows
506 // **
507 // N.B. 1: aSheet->GetFileName() will return a relative path
508 // aSheet->GetScreen()->GetFileName() returns a full path
509 //
510 // N.B. 2: newFilename uses the unix notation for separator.
511 // so we must use it also to compare the old and new filenames
512 wxString oldAbsoluteFilename = m_sheet->GetScreen()->GetFileName();
513 oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
514
515 if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
516 {
517 // Sheet file name changes cannot be undone.
518 isUndoable = false;
519
520 if( useScreen || loadFromFile ) // Load from existing file.
521 {
522 clearAnnotation = true;
523
524 if( !IsOK( this, wxString::Format( _( "Change '%s' link from '%s' to '%s'?" ),
525 newAbsoluteFilename,
527 sheetFileName.GetFullName() )
528 + wxT( "\n\n" )
529 + _( "This action cannot be undone." ) ) )
530 {
531 return false;
532 }
533
534 if( loadFromFile )
535 m_sheet->SetScreen( nullptr );
536 }
537 else // Save to new file name.
538 {
539 if( m_sheet->GetScreenCount() > 1 )
540 {
541 if( !IsOK( this, wxString::Format( _( "Create new file '%s' with contents "
542 "of '%s'?" ),
543 sheetFileName.GetFullName(),
545 + wxT( "\n\n" )
546 + _( "This action cannot be undone." ) ) )
547 {
548 return false;
549 }
550 }
551
552 renameFile = true;
553 }
554 }
555
556 // If we are renaming files, the undo/redo list becomes invalid and must be cleared
557 if( isUndoable )
558 m_frame->SaveCopyInUndoList( m_frame->GetScreen(), m_sheet, UNDO_REDO::CHANGED, false );
559 else
561
562 if( renameFile )
563 {
564 SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
565
566 // If the associated screen is shared by more than one sheet, do not
567 // change the filename of the corresponding screen here.
568 // (a new screen will be created later)
569 // if it is not shared, update the filename
570 if( m_sheet->GetScreenCount() <= 1 )
571 m_sheet->GetScreen()->SetFileName( newAbsoluteFilename );
572
573 try
574 {
575 pi->Save( newAbsoluteFilename, m_sheet, &schematic );
576 }
577 catch( const IO_ERROR& ioe )
578 {
579 msg = wxString::Format( _( "Error occurred saving schematic file '%s'." ),
580 newAbsoluteFilename );
581 DisplayErrorMessage( this, msg, ioe.What() );
582
583 msg = wxString::Format( _( "Failed to save schematic '%s'" ),
584 newAbsoluteFilename );
585 m_frame->SetMsgPanel( wxEmptyString, msg );
586 return false;
587 }
588
589 // If the associated screen is shared by more than one sheet, remove the
590 // screen and reload the file to a new screen. Failure to do this will trash
591 // the screen reference counting in complex hierarchies.
592 if( m_sheet->GetScreenCount() > 1 )
593 {
594 oldScreen = m_sheet->GetScreen();
595 m_sheet->SetScreen( nullptr );
596 loadFromFile = true;
597 }
598 }
599 }
600
601 SCH_SHEET_PATH& currentSheet = m_frame->GetCurrentSheet();
602
603 if( useScreen )
604 {
605 // Create a temporary sheet for recursion testing to prevent a possible recursion error.
606 std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>( &schematic );
607 tmpSheet->GetFields()[SHEETNAME] = m_fields->at( SHEETNAME );
608 tmpSheet->GetFields()[SHEETFILENAME].SetText( sheetFileName.GetFullPath() );
609 tmpSheet->SetScreen( useScreen );
610
611 // No need to check for valid library IDs if we are using an existing screen.
612 if( m_frame->CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
613 return false;
614
615 // It's safe to set the sheet screen now.
616 m_sheet->SetScreen( useScreen );
617 }
618 else if( loadFromFile )
619 {
620 bool restoreSheet = false;
621
622 if( isExistingSheet )
623 {
624 // Temporarily remove the sheet from the current schematic page so that recursion
625 // and symbol library link tests can be performed with the modified sheet settings.
626 restoreSheet = true;
627 currentSheet.LastScreen()->Remove( m_sheet );
628 }
629
630 if( !m_frame->LoadSheetFromFile( m_sheet, &currentSheet, newAbsoluteFilename )
631 || m_frame->CheckSheetForRecursion( m_sheet, &currentSheet ) )
632 {
633 if( restoreSheet )
634 {
635 // If we cleared the previous screen, restore it before returning to the user
636 if( oldScreen )
637 m_sheet->SetScreen( oldScreen );
638
639 currentSheet.LastScreen()->Append( m_sheet );
640 }
641
642 return false;
643 }
644
645 if( restoreSheet )
646 currentSheet.LastScreen()->Append( m_sheet );
647 }
648
650 *m_clearAnnotationNewItems = clearAnnotation;
651
652 return true;
653}
654
655
657{
658 bool success = true;
659 wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
660 wxControl* control = editor->GetControl();
661 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
662
663 // Short-circuit the validator's more generic "can't be empty" message for the
664 // two mandatory fields:
665 if( event.GetRow() == SHEETNAME && event.GetCol() == FDC_VALUE )
666 {
667 if( textControl && textControl->IsEmpty() )
668 {
669 wxMessageBox( _( "A sheet must have a name." ) );
670 success = false;
671 }
672 }
673 else if( event.GetRow() == SHEETFILENAME && event.GetCol() == FDC_VALUE && textControl )
674 {
675 if( textControl->IsEmpty() )
676 {
677 wxMessageBox( _( "A sheet must have a file specified." ) );
678 success = false;
679 }
680 }
681
682 if( success && control && control->GetValidator() )
683 success = control->GetValidator()->Validate( control );
684
685 if( !success )
686 {
687 event.Veto();
688 m_delayedFocusRow = event.GetRow();
689 m_delayedFocusColumn = event.GetCol();
690 }
691
692 editor->DecRef();
693}
694
695
696void DIALOG_SHEET_PROPERTIES::OnAddField( wxCommandEvent& event )
697{
699 return;
700
701 int fieldID = m_fields->size();
702 SCH_FIELD newField( VECTOR2I( 0, 0 ), fieldID, m_sheet,
704
705 newField.SetTextAngle( m_fields->at( SHEETNAME ).GetTextAngle() );
706
707 m_fields->push_back( newField );
708
709 // notify the grid
710 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
711 m_grid->ProcessTableMessage( msg );
712
713 m_grid->MakeCellVisible( m_fields->size() - 1, 0 );
714 m_grid->SetGridCursor( m_fields->size() - 1, 0 );
715
716 m_grid->EnableCellEditControl();
717 m_grid->ShowCellEditControl();
718}
719
720
721void DIALOG_SHEET_PROPERTIES::OnDeleteField( wxCommandEvent& event )
722{
723 wxArrayInt selectedRows = m_grid->GetSelectedRows();
724
725 if( selectedRows.empty() && m_grid->GetGridCursorRow() >= 0 )
726 selectedRows.push_back( m_grid->GetGridCursorRow() );
727
728 if( selectedRows.empty() )
729 return;
730
731 for( int row : selectedRows )
732 {
733 if( row < SHEET_MANDATORY_FIELDS )
734 {
735 DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
737 return;
738 }
739 }
740
741 m_grid->CommitPendingChanges( true /* quiet mode */ );
742
743 // Reverse sort so deleting a row doesn't change the indexes of the other rows.
744 selectedRows.Sort( []( int* first, int* second ) { return *second - *first; } );
745
746 for( int row : selectedRows )
747 {
748 m_fields->erase( m_fields->begin() + row );
749
750 // notify the grid
751 wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, row, 1 );
752 m_grid->ProcessTableMessage( msg );
753
754 if( m_grid->GetNumberRows() > 0 )
755 {
756 m_grid->MakeCellVisible( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
757 m_grid->SetGridCursor( std::max( 0, row-1 ), m_grid->GetGridCursorCol() );
758 }
759 }
760}
761
762
763void DIALOG_SHEET_PROPERTIES::OnMoveUp( wxCommandEvent& event )
764{
766 return;
767
768 int i = m_grid->GetGridCursorRow();
769
770 if( i > SHEET_MANDATORY_FIELDS )
771 {
772 SCH_FIELD tmp = m_fields->at( (unsigned) i );
773 m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
774 m_fields->insert( m_fields->begin() + i - 1, tmp );
775 m_grid->ForceRefresh();
776
777 m_grid->SetGridCursor( i - 1, m_grid->GetGridCursorCol() );
778 m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
779 }
780 else
781 {
782 wxBell();
783 }
784}
785
786
787void DIALOG_SHEET_PROPERTIES::OnMoveDown( wxCommandEvent& event )
788{
790 return;
791
792 int i = m_grid->GetGridCursorRow();
793
794 if( i >= SHEET_MANDATORY_FIELDS && i < m_grid->GetNumberRows() - 1 )
795 {
796 SCH_FIELD tmp = m_fields->at( (unsigned) i );
797 m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
798 m_fields->insert( m_fields->begin() + i + 1, tmp );
799 m_grid->ForceRefresh();
800
801 m_grid->SetGridCursor( i + 1, m_grid->GetGridCursorCol() );
802 m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
803 }
804 else
805 {
806 wxBell();
807 }
808}
809
810
812{
813 // Account for scroll bars
815
816 m_grid->AutoSizeColumn( 0 );
817 m_grid->SetColSize( 0, std::max( 72, m_grid->GetColSize( 0 ) ) );
818
819 int fixedColsWidth = m_grid->GetColSize( 0 );
820
821 for( int i = 2; i < m_grid->GetNumberCols(); i++ )
822 fixedColsWidth += m_grid->GetColSize( i );
823
824 m_grid->SetColSize( 1, std::max( 120, width - fixedColsWidth ) );
825}
826
827
828void DIALOG_SHEET_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
829{
830 std::bitset<64> shownColumns = m_grid->GetShownColumns();
831
832 if( shownColumns != m_shownColumns )
833 {
834 m_shownColumns = shownColumns;
835
836 if( !m_grid->IsCellEditControlShown() )
838 }
839
840 // Propagate changes in sheetname to displayed hierarchical path
841 wxString path = m_frame->GetCurrentSheet().PathHumanReadable( false );
842
843 if( path.Last() != '/' )
844 path.Append( '/' );
845
846 wxGridCellEditor* editor = m_grid->GetCellEditor( SHEETNAME, FDC_VALUE );
847 wxControl* control = editor->GetControl();
848 wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
849 wxString sheetName;
850
851 if( textControl )
852 sheetName = textControl->GetValue();
853 else
854 sheetName = m_grid->GetCellValue( SHEETNAME, FDC_VALUE );
855
857 m_dummySheetNameField.SetText( sheetName );
859
860 editor->DecRef();
861
862 wxClientDC dc( m_hierarchicalPathLabel );
863 int width = m_sizerBottom->GetSize().x - m_stdDialogButtonSizer->GetSize().x
864 - m_hierarchicalPathLabel->GetSize().x
865 - 30;
866
867 path = wxControl::Ellipsize( path, dc, wxELLIPSIZE_START, width, wxELLIPSIZE_FLAGS_NONE );
868
869 if( m_hierarchicalPath->GetLabel() != path )
870 m_hierarchicalPath->SetLabel( path );
871
872 // Handle a delayed focus
873 if( m_delayedFocusRow >= 0 )
874 {
875 m_grid->SetFocus();
876 m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
878
879 m_grid->EnableCellEditControl( true );
880 m_grid->ShowCellEditControl();
881
884 }
885}
886
887
888void DIALOG_SHEET_PROPERTIES::OnSizeGrid( wxSizeEvent& event )
889{
890 auto new_size = event.GetSize();
891
892 if( m_size != new_size )
893 {
894 m_size = new_size;
895
897 }
898
899 // Always propagate for a grid repaint (needed if the height changes, as well as width)
900 event.Skip();
901}
902
903
904void DIALOG_SHEET_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
905{
907
908 // Now all widgets have the size fixed, call FinishDialogSettings
910
911 EESCHEMA_SETTINGS* cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
912
913 if( cfg && cfg->m_Appearance.edit_sheet_width > 0 && cfg->m_Appearance.edit_sheet_height > 0 )
915
916}
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:106
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:123
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:87
void Offset(const VECTOR2I &aOffset)
Definition: eda_text.cpp:401
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:152
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition: eda_text.h:155
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:175
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:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:46
@ KD_WARNING
Definition: confirm.h:49
void DoNotShowCheckbox(wxString file, int line)
Checks the 'do not show again' setting for the dialog.
Definition: confirm.cpp:59
int ShowModal() override
Definition: confirm.cpp:103
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:103
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition: project.cpp:305
Holds all the data relating to one schematic.
Definition: schematic.h:72
SCH_SHEET_LIST & GetFullHierarchy() const
Return the full schematic flattened hierarchical sheet list.
Definition: schematic.cpp:504
SCH_SHEET & Root() const
Definition: schematic.h:102
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:106
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:624
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:98
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy)
Verify that aSheet will not cause a recursion error in aHierarchy.
Definition: sheet.cpp:48
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:51
VECTOR2I GetPosition() const override
Definition: sch_field.cpp:1079
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:847
int GetId() const
Definition: sch_field.h:125
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
Definition: sch_field.cpp:815
void SetName(const wxString &aName)
Definition: sch_field.h:117
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
Definition: sch_field.cpp:175
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
void ClearFieldsAutoplaced()
Definition: sch_item.h:433
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:536
virtual void Save(const wxString &aFileName, SCH_SHEET *aSheet, SCHEMATIC *aSchematic, const STRING_UTF8_MAP *aProperties=nullptr)
Write aSchematic to a storage file in a format that this SCH_PLUGIN implementation knows about,...
Definition: sch_plugin.cpp:48
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Definition: sch_screen.cpp:144
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:109
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:314
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:310
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslated=true)
Definition: sch_sheet.cpp:54
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:722
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:346
int GetScreenCount() const
Return the number of times the associated screen for the sheet is being used.
Definition: sch_sheet.cpp:184
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:161
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 wxBitmap &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:306
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:164
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:262
wxString GetShownColumnsAsString()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:276
std::bitset< 64 > GetShownColumns()
Definition: wx_grid.cpp:295
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:474
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:380
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:363
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:283
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:308
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:380
wxSize GetUnobscuredSize(const wxWindow *aWindow)
Tries to determine the size of the viewport of a scrollable widget (wxDataViewCtrl,...
Definition: gtk/ui.cpp:172
wxFont GetInfoFont(wxWindow *aWindow)
Definition: ui_common.cpp:156
@ 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:148
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:38