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