KiCad PCB EDA Suite
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 <stambaughw@gmail.com>
5  * Copyright (C) 2014-2020 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_i.h>
27 #include <wx/string.h>
28 #include <wx/tooltip.h>
29 #include <confirm.h>
30 #include <validators.h>
32 #include <widgets/tab_traversal.h>
33 #include <sch_edit_frame.h>
34 #include <sch_sheet.h>
35 #include <schematic.h>
36 #include <bitmaps.h>
37 #include <eeschema_settings.h>
39 #include <trace_helpers.h>
41 
43  bool* aClearAnnotationNewItems ) :
45  m_frame( aParent ),
46  m_clearAnnotationNewItems( aClearAnnotationNewItems ),
47  m_borderWidth( aParent, m_borderWidthLabel, m_borderWidthCtrl, m_borderWidthUnits, true ),
48  m_dummySheet( *aSheet ),
49  m_dummySheetNameField( wxDefaultPosition, SHEETNAME, &m_dummySheet )
50 {
51  m_sheet = aSheet;
52  m_fields = new FIELDS_GRID_TABLE<SCH_FIELD>( this, aParent, m_sheet );
53  m_width = 100; // Will be later set to a better value
56 
57  // Give a bit more room for combobox editors
58  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
59 
61  m_grid->PushEventHandler( new FIELDS_GRID_TRICKS( m_grid, this ) );
62 
63  // Show/hide columns according to user's preference
64  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
65  wxASSERT( cfg );
66 
67  if( cfg )
68  {
69  m_shownColumns = cfg->m_Appearance.edit_sheet_visible_columns;
71  }
72 
73  wxToolTip::Enable( true );
74  m_stdDialogButtonSizerOK->SetDefault();
75 
76  // Configure button logos
77  m_bpAdd->SetBitmap( KiBitmap( small_plus_xpm ) );
78  m_bpDelete->SetBitmap( KiBitmap( trash_xpm ) );
79  m_bpMoveUp->SetBitmap( KiBitmap( small_up_xpm ) );
80  m_bpMoveDown->SetBitmap( KiBitmap( small_down_xpm ) );
81 
82  // Set font sizes
83  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
84  infoFont.SetSymbolicSize( wxFONTSIZE_SMALL );
85  m_hierarchicalPathLabel->SetFont( infoFont );
86 
87  // wxFormBuilder doesn't include this event...
88  m_grid->Connect( wxEVT_GRID_CELL_CHANGING,
89  wxGridEventHandler( DIALOG_SHEET_PROPERTIES::OnGridCellChanging ),
90  NULL, this );
91 
93 }
94 
95 
97 {
98  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
99  wxASSERT( cfg );
100 
101  if( cfg )
102  cfg->m_Appearance.edit_sheet_visible_columns = m_grid->GetShownColumns();
103 
104  // Prevents crash bug in wxGrid's d'tor
106 
107  m_grid->Disconnect( wxEVT_GRID_CELL_CHANGING,
108  wxGridEventHandler( DIALOG_SHEET_PROPERTIES::OnGridCellChanging ),
109  NULL, this );
110 
111  // Delete the GRID_TRICKS.
112  m_grid->PopEventHandler( true );
113 }
114 
115 
117 {
118  if( !wxDialog::TransferDataToWindow() )
119  return false;
120 
121  // Push a copy of each field into m_updateFields
122  for( SCH_FIELD& field : m_sheet->GetFields() )
123  {
124  SCH_FIELD field_copy( field );
125 
126 #ifdef __WINDOWS__
127  // Filenames are stored using unix notation
128  if( field_copy.GetId() == SHEETFILENAME )
129  {
130  wxString filename = field_copy.GetText();
131  filename.Replace( wxT("/"), wxT("\\") );
132  field_copy.SetText( filename );
133  }
134 #endif
135 
136  // change offset to be symbol-relative
137  field_copy.Offset( -m_sheet->GetPosition() );
138 
139  m_fields->push_back( field_copy );
140  }
141 
142  // notify the grid
143  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
144  m_grid->ProcessTableMessage( msg );
145  AdjustGridColumns( m_grid->GetRect().GetWidth() );
146 
147  // border width
149 
150  // set up color swatches
151  KIGFX::COLOR4D borderColor = m_sheet->GetBorderColor();
152  KIGFX::COLOR4D backgroundColor = m_sheet->GetBackgroundColor();
153 
154  m_borderSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
155  m_backgroundSwatch->SetDefaultColor( COLOR4D::UNSPECIFIED );
156 
157  m_borderSwatch->SetSwatchColor( borderColor, false );
158  m_backgroundSwatch->SetSwatchColor( backgroundColor, false );
159 
163 
165  SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
166 
167  instance.push_back( m_sheet );
168 
169  wxString nextPageNumber;
170 
171  if( m_sheet->IsNew() )
172  nextPageNumber.Printf( "%d", static_cast<int>( hierarchy.size() ) + 1 );
173  else
174  nextPageNumber = m_sheet->GetPageNumber( instance );
175 
176  m_pageNumberTextCtrl->ChangeValue( nextPageNumber );
177 
178  Layout();
179 
180  return true;
181 }
182 
183 
185 {
186  wxString msg;
187  LIB_ID id;
188 
189  if( !m_grid->CommitPendingChanges() || !m_grid->Validate() )
190  return false;
191 
192  // Check for missing field names.
193  for( size_t i = SHEET_MANDATORY_FIELDS; i < m_fields->size(); ++i )
194  {
195  SCH_FIELD& field = m_fields->at( i );
196  wxString fieldName = field.GetName( false );
197 
198  if( fieldName.IsEmpty() )
199  {
200  DisplayErrorMessage( this, _( "Fields must have a name." ) );
201 
203  m_delayedFocusRow = i;
204 
205  return false;
206  }
207  }
208 
209  return true;
210 }
211 
212 
213 static bool positioningChanged( const SCH_FIELD& a, const SCH_FIELD& b )
214 {
215  if( a.GetPosition() != b.GetPosition() )
216  return true;
217 
218  if( a.GetHorizJustify() != b.GetHorizJustify() )
219  return true;
220 
221  if( a.GetVertJustify() != b.GetVertJustify() )
222  return true;
223 
224  if( a.GetTextAngle() != b.GetTextAngle() )
225  return true;
226 
227  return false;
228 }
229 
230 
231 static bool positioningChanged( FIELDS_GRID_TABLE<SCH_FIELD>* a, std::vector<SCH_FIELD>& b )
232 {
233  for( size_t i = 0; i < SHEET_MANDATORY_FIELDS; ++i )
234  {
235  if( positioningChanged( a->at( i ), b.at( i ) ) )
236  return true;
237  }
238 
239  return false;
240 }
241 
242 
244 {
245  if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
246  return false;
247 
248  wxString newRelativeNativeFilename = m_fields->at( SHEETFILENAME ).GetText();
249 
250  // Ensure filepath is not empty. (In normal use will be caught by grid validators,
251  // but unedited data from existing files can be bad.)
252 
253  // @todo What happens when there are invalid file name characters?
254  if( newRelativeNativeFilename.IsEmpty() )
255  {
256  wxMessageBox( _( "A sheet must have a valid file name." ) );
257  return false;
258  }
259 
260  // Ensure the filename extension is OK. (In normaly use will be caught by grid
261  // validators, but unedited data from existing files can be bad.)
262  wxFileName fn( newRelativeNativeFilename );
263 
264  if( fn.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
265  {
266  wxMessageBox( _( "Sheet file must have a '.kicad_sch' extension." ) );
267  return false;
268  }
269 
270  wxString newRelativeFilename = fn.GetFullPath();
271 
272  // Inside Eeschema, filenames are stored using unix notation
273  newRelativeFilename.Replace( wxT( "\\" ), wxT( "/" ) );
274 
275  wxString oldFilename = m_sheet->GetFields()[ SHEETFILENAME ].GetText();
276  oldFilename.Replace( wxT( "\\" ), wxT( "/" ) );
277 
278  bool filename_changed = oldFilename != newRelativeFilename;
279 
280  if( filename_changed || m_sheet->IsNew() )
281  {
282  if( !onSheetFilenameChanged( newRelativeFilename ) )
283  return false;
284 
285  // One last validity check (and potential repair) just to be sure to be sure
286  SCH_SHEET_LIST repairedList( &m_frame->Schematic().Root(), true );
287  }
288 
289  wxString newSheetname = m_fields->at( SHEETNAME ).GetText();
290 
291  if( newSheetname.IsEmpty() )
292  newSheetname = _( "Untitled Sheet" );
293 
294  m_fields->at( SHEETNAME ).SetText( newSheetname );
295 
296  // change all field positions from relative to absolute
297  for( unsigned i = 0; i < m_fields->size(); ++i )
298  m_fields->at( i ).Offset( m_sheet->GetPosition() );
299 
302 
304 
306 
307  COLOR_SETTINGS* colorSettings = m_frame->GetColorSettings();
308 
309  if( colorSettings->GetOverrideSchItemColors()
312  {
313  wxPanel temp( this );
314  temp.Hide();
315  PANEL_EESCHEMA_COLOR_SETTINGS prefs( m_frame, &temp );
316  wxString checkboxLabel = prefs.m_optOverrideColors->GetLabel();
317 
318  KIDIALOG dlg( this, _( "Note: item colors are overridden in the current color theme." ),
320  dlg.ShowDetailedText( wxString::Format( _( "To see individual item colors uncheck '%s'\n"
321  "in Preferences > Eeschema > Colors." ),
322  checkboxLabel ) );
323  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
324  dlg.ShowModal();
325  }
326 
329 
331  SCH_SHEET_PATH instance = m_frame->GetCurrentSheet();
332 
333  instance.push_back( m_sheet );
334 
335  if( m_sheet->IsNew() )
336  m_sheet->AddInstance( instance.Path() );
337 
338  m_sheet->SetPageNumber( instance, m_pageNumberTextCtrl->GetValue() );
339 
341 
342  // Refresh all sheets in case ordering changed.
343  for( SCH_ITEM* item : m_frame->GetScreen()->Items().OfType( SCH_SHEET_T ) )
344  m_frame->UpdateItem( item );
345 
346  m_frame->OnModify();
347 
348  return true;
349 }
350 
351 
352 bool DIALOG_SHEET_PROPERTIES::onSheetFilenameChanged( const wxString& aNewFilename )
353 {
354  wxString msg;
355 
356  // Relative file names are relative to the path of the current sheet. This allows for
357  // nesting of schematic files in subfolders.
358  wxFileName fileName( aNewFilename );
359 
360  if( fileName.GetExt().IsEmpty() )
361  {
362  fileName.SetExt( KiCadSchematicFileExtension );
363  }
364  else if( fileName.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
365  {
366  msg.Printf( _( "The file \"%s\" does not appear to be a valid schematic file." ),
367  fileName.GetFullName() );
368  wxMessageDialog badSchFileDialog( this, msg, _( "Invalid Schematic File" ),
369  wxOK | wxCENTRE | wxICON_EXCLAMATION );
370  badSchFileDialog.ShowModal();
371  return false;
372  }
373 
374  if( !fileName.IsAbsolute() )
375  {
376  const SCH_SCREEN* currentScreen = m_frame->GetCurrentSheet().LastScreen();
377  wxCHECK_MSG( currentScreen, false, "Invalid sheet path object." );
378 
379  wxFileName currentSheetFileName = currentScreen->GetFileName();
380 
381  if( !fileName.Normalize( wxPATH_NORM_ALL, currentSheetFileName.GetPath() ) )
382  {
383  wxFAIL_MSG( "Cannot normalize new sheet schematic file path." );
384  return false;
385  }
386  }
387 
388  wxString newAbsoluteFilename = fileName.GetFullPath();
389 
390  // Inside Eeschema, filenames are stored using unix notation
391  newAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
392 
393  bool renameFile = false;
394  bool loadFromFile = false;
395  bool clearAnnotation = false;
396  bool restoreSheet = false;
397  bool isExistingSheet = false;
398  SCH_SCREEN* useScreen = NULL;
399 
400  // Search for a schematic file having the same filename already in use in the hierarchy
401  // or on disk, in order to reuse it.
402  if( !m_frame->Schematic().Root().SearchHierarchy( newAbsoluteFilename, &useScreen ) )
403  {
404  loadFromFile = wxFileExists( newAbsoluteFilename );
405 
406  wxLogTrace( tracePathsAndFiles, "Sheet requested file \"%s\", %s",
407  newAbsoluteFilename,
408  ( loadFromFile ) ? "found" : "not found" );
409  }
410 
411  if( m_sheet->GetScreen() == NULL ) // New just created sheet.
412  {
413  if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
414  return false;
415 
416  if( useScreen || loadFromFile ) // Load from existing file.
417  {
418  clearAnnotation = true;
419  wxString existsMsg;
420  wxString linkMsg;
421  existsMsg.Printf( _( "\"%s\" already exists." ), fileName.GetFullName() );
422  linkMsg.Printf( _( "Link \"%s\" to this file?" ), newAbsoluteFilename );
423  msg.Printf( wxT( "%s\n\n%s" ), existsMsg, linkMsg );
424 
425  if( !IsOK( this, msg ) )
426  return false;
427  }
428  else // New file.
429  {
430  m_frame->InitSheet( m_sheet, newAbsoluteFilename );
431  }
432  }
433  else // Existing sheet.
434  {
435  bool isUndoable = true;
436  wxString replaceMsg;
437  wxString newMsg;
438  wxString noUndoMsg;
439  isExistingSheet = true;
440 
441  if( !m_frame->AllowCaseSensitiveFileNameClashes( newAbsoluteFilename ) )
442  return false;
443 
444  // Changing the filename of a sheet can modify the full hierarchy structure
445  // and can be not always undoable.
446  // So prepare messages for user notifications:
447  replaceMsg.Printf( _( "Change \"%s\" link from \"%s\" to \"%s\"?" ),
448  newAbsoluteFilename,
449  m_sheet->GetFileName(),
450  fileName.GetFullName() );
451  newMsg.Printf( _( "Create new file \"%s\" with contents of \"%s\"?" ),
452  fileName.GetFullName(),
453  m_sheet->GetFileName() );
454  noUndoMsg = _( "This action cannot be undone." );
455 
456  // We are always using here a case insensitive comparison to avoid issues
457  // under Windows, although under Unix filenames are case sensitive.
458  // But many users create schematic under both Unix and Windows
459  // **
460  // N.B. 1: aSheet->GetFileName() will return a relative path
461  // aSheet->GetScreen()->GetFileName() returns a full path
462  //
463  // N.B. 2: newFilename uses the unix notation for separator.
464  // so we must use it also to compare the old and new filenames
465  wxString oldAbsoluteFilename = m_sheet->GetScreen()->GetFileName();
466  oldAbsoluteFilename.Replace( wxT( "\\" ), wxT( "/" ) );
467 
468  if( newAbsoluteFilename.Cmp( oldAbsoluteFilename ) != 0 )
469  {
470  // Sheet file name changes cannot be undone.
471  isUndoable = false;
472 
473  if( useScreen || loadFromFile ) // Load from existing file.
474  {
475  clearAnnotation = true;
476 
477  msg.Printf( wxT( "%s\n\n%s" ), replaceMsg, noUndoMsg );
478 
479  if( !IsOK( this, msg ) )
480  return false;
481 
482  if( loadFromFile )
483  m_sheet->SetScreen( NULL );
484  }
485  else // Save to new file name.
486  {
487  if( m_sheet->GetScreenCount() > 1 )
488  {
489  msg.Printf( wxT( "%s\n\n%s" ), newMsg, noUndoMsg );
490 
491  if( !IsOK( this, msg ) )
492  return false;
493  }
494 
495  renameFile = true;
496  }
497  }
498 
499  if( isUndoable )
501 
502  if( renameFile )
503  {
504  SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
505 
506  // If the the associated screen is shared by more than one sheet, do not
507  // change the filename of the corresponding screen here.
508  // (a new screen will be created later)
509  // if it is not shared, update the filename
510  if( m_sheet->GetScreenCount() <= 1 )
511  m_sheet->GetScreen()->SetFileName( newAbsoluteFilename );
512 
513  try
514  {
515  pi->Save( newAbsoluteFilename, m_sheet, &m_frame->Schematic() );
516  }
517  catch( const IO_ERROR& ioe )
518  {
519  msg.Printf( _( "Error occurred saving schematic file \"%s\"." ),
520  newAbsoluteFilename );
521  DisplayErrorMessage( this, msg, ioe.What() );
522 
523  msg.Printf( _( "Failed to save schematic \"%s\"" ), newAbsoluteFilename );
524  m_frame->AppendMsgPanel( wxEmptyString, msg, CYAN );
525 
526  return false;
527  }
528 
529  // If the the associated screen is shared by more than one sheet, remove the
530  // screen and reload the file to a new screen. Failure to do this will trash
531  // the screen reference counting in complex hierarchies.
532  if( m_sheet->GetScreenCount() > 1 )
533  {
534  m_sheet->SetScreen( NULL );
535  loadFromFile = true;
536  }
537  }
538  }
539 
540  wxFileName nativeFileName( aNewFilename );
541  SCH_SHEET_PATH& currentSheet = m_frame->GetCurrentSheet();
542 
543  if( useScreen )
544  {
545  // Create a temporary sheet for recursion testing to prevent a possible recursion error.
546  std::unique_ptr< SCH_SHEET> tmpSheet = std::make_unique<SCH_SHEET>();
547  tmpSheet->GetFields()[SHEETNAME] = m_fields->at( SHEETNAME );
548  tmpSheet->GetFields()[SHEETFILENAME].SetText( nativeFileName.GetFullPath() );
549  tmpSheet->SetScreen( useScreen );
550 
551  // No need to check for valid library IDs if we are using an existing screen.
552  if( m_frame->CheckSheetForRecursion( tmpSheet.get(), &currentSheet ) )
553  {
554  if( restoreSheet )
555  currentSheet.LastScreen()->Append( m_sheet );
556 
557  return false;
558  }
559 
560  // It's safe to set the sheet screen now.
561  m_sheet->SetScreen( useScreen );
562  }
563  else if( loadFromFile )
564  {
565  if( isExistingSheet )
566  {
567  // Temporarily remove the sheet from the current schematic page so that recursion
568  // and symbol library link tests can be performed with the modified sheet settings.
569  restoreSheet = true;
570  currentSheet.LastScreen()->Remove( m_sheet );
571  }
572 
573  if( !m_frame->LoadSheetFromFile( m_sheet, &currentSheet, newAbsoluteFilename )
574  || m_frame->CheckSheetForRecursion( m_sheet, &currentSheet ) )
575  {
576  if( restoreSheet )
577  currentSheet.LastScreen()->Append( m_sheet );
578 
579  return false;
580  }
581 
582  if( restoreSheet )
583  currentSheet.LastScreen()->Append( m_sheet );
584  }
585 
587  *m_clearAnnotationNewItems = clearAnnotation;
588 
589  return true;
590 }
591 
592 
594 {
595  bool success = true;
596  wxGridCellEditor* editor = m_grid->GetCellEditor( event.GetRow(), event.GetCol() );
597  wxControl* control = editor->GetControl();
598  wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
599 
600  // Short-circuit the validator's more generic "can't be empty" message for the
601  // two mandatory fields:
602  if( event.GetRow() == SHEETNAME && event.GetCol() == FDC_VALUE )
603  {
604  if( textControl && textControl->IsEmpty() )
605  {
606  wxMessageBox( _( "A sheet must have a name." ) );
607  success = false;
608  }
609  }
610  else if( event.GetRow() == SHEETFILENAME && event.GetCol() == FDC_VALUE && textControl )
611  {
612  if( textControl->IsEmpty() )
613  {
614  wxMessageBox( _( "A sheet must have a file specified." ) );
615  success = false;
616  }
617  else
618  {
619  wxFileName fn = textControl->GetValue();
620 
621  if( fn.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
622  {
623  wxMessageBox( _( "Sheet filename must have a '.kicad_sch' extension." ) );
624  success = false;
625  }
626  }
627  }
628 
629  if( success && control && control->GetValidator() )
630  success = control->GetValidator()->Validate( control );
631 
632  if( !success )
633  {
634  event.Veto();
635  m_delayedFocusRow = event.GetRow();
636  m_delayedFocusColumn = event.GetCol();
637  }
638 
639  editor->DecRef();
640 }
641 
642 
643 void DIALOG_SHEET_PROPERTIES::OnAddField( wxCommandEvent& event )
644 {
645  if( !m_grid->CommitPendingChanges() )
646  return;
647 
648  int fieldID = m_fields->size();
649  SCH_FIELD newField( wxPoint( 0, 0 ), fieldID, m_sheet,
650  SCH_SHEET::GetDefaultFieldName( fieldID ) );
651 
652  newField.SetTextAngle( m_fields->at( SHEETNAME ).GetTextAngle() );
653 
654  m_fields->push_back( newField );
655 
656  // notify the grid
657  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
658  m_grid->ProcessTableMessage( msg );
659 
660  m_grid->MakeCellVisible( m_fields->size() - 1, 0 );
661  m_grid->SetGridCursor( m_fields->size() - 1, 0 );
662 
663  m_grid->EnableCellEditControl();
664  m_grid->ShowCellEditControl();
665 }
666 
667 
668 void DIALOG_SHEET_PROPERTIES::OnDeleteField( wxCommandEvent& event )
669 {
670  int curRow = m_grid->GetGridCursorRow();
671 
672  if( curRow < 0 )
673  return;
674  else if( curRow < SHEET_MANDATORY_FIELDS )
675  {
676  DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
678  return;
679  }
680 
681  m_grid->CommitPendingChanges( true /* quiet mode */ );
682 
683  m_fields->erase( m_fields->begin() + curRow );
684 
685  // notify the grid
686  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
687  m_grid->ProcessTableMessage( msg );
688 
689  if( m_grid->GetNumberRows() > 0 )
690  {
691  m_grid->MakeCellVisible( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
692  m_grid->SetGridCursor( std::max( 0, curRow-1 ), m_grid->GetGridCursorCol() );
693  }
694 }
695 
696 
697 void DIALOG_SHEET_PROPERTIES::OnMoveUp( wxCommandEvent& event )
698 {
699  if( !m_grid->CommitPendingChanges() )
700  return;
701 
702  int i = m_grid->GetGridCursorRow();
703 
704  if( i > SHEET_MANDATORY_FIELDS )
705  {
706  SCH_FIELD tmp = m_fields->at( (unsigned) i );
707  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
708  m_fields->insert( m_fields->begin() + i - 1, tmp );
709  m_grid->ForceRefresh();
710 
711  m_grid->SetGridCursor( i - 1, m_grid->GetGridCursorCol() );
712  m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
713  }
714  else
715  wxBell();
716 }
717 
718 
719 void DIALOG_SHEET_PROPERTIES::OnMoveDown( wxCommandEvent& event )
720 {
721  if( !m_grid->CommitPendingChanges() )
722  return;
723 
724  int i = m_grid->GetGridCursorRow();
725 
726  if( i >= SHEET_MANDATORY_FIELDS && i < m_grid->GetNumberRows() - 1 )
727  {
728  SCH_FIELD tmp = m_fields->at( (unsigned) i );
729  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
730  m_fields->insert( m_fields->begin() + i + 1, tmp );
731  m_grid->ForceRefresh();
732 
733  m_grid->SetGridCursor( i + 1, m_grid->GetGridCursorCol() );
734  m_grid->MakeCellVisible( m_grid->GetGridCursorRow(), m_grid->GetGridCursorCol() );
735  }
736  else
737  wxBell();
738 }
739 
740 
742 {
743  m_width = aWidth;
744  // Account for scroll bars
745  aWidth -= ( m_grid->GetSize().x - m_grid->GetClientSize().x );
746 
747  m_grid->AutoSizeColumn( 0 );
748 
749  int fixedColsWidth = m_grid->GetColSize( 0 );
750 
751  for( int i = 2; i < m_grid->GetNumberCols(); i++ )
752  fixedColsWidth += m_grid->GetColSize( i );
753 
754  m_grid->SetColSize( 1, aWidth - fixedColsWidth );
755 }
756 
757 
758 void DIALOG_SHEET_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
759 {
760  wxString shownColumns = m_grid->GetShownColumns();
761 
762  if( shownColumns != m_shownColumns )
763  {
764  m_shownColumns = shownColumns;
765 
766  if( !m_grid->IsCellEditControlShown() )
767  AdjustGridColumns( m_grid->GetRect().GetWidth() );
768  }
769 
770  // Propagate changes in sheetname to displayed hierarchical path
771  wxString hierarchicalPath = _( "Hierarchical path: " );
772 
773  hierarchicalPath += m_frame->GetCurrentSheet().PathHumanReadable( false );
774 
775  if( hierarchicalPath.Last() != '/' )
776  hierarchicalPath.Append( '/' );
777 
778  wxGridCellEditor* editor = m_grid->GetCellEditor( SHEETNAME, FDC_VALUE );
779  wxControl* control = editor->GetControl();
780  wxTextEntry* textControl = dynamic_cast<wxTextEntry*>( control );
781  wxString sheetName;
782 
783  if( textControl )
784  sheetName = textControl->GetValue();
785  else
786  sheetName = m_grid->GetCellValue( SHEETNAME, FDC_VALUE );
787 
789  m_dummySheetNameField.SetText( sheetName );
790  hierarchicalPath += m_dummySheetNameField.GetShownText();
791 
792  editor->DecRef();
793 
794  if( m_hierarchicalPathLabel->GetLabel() != hierarchicalPath )
795  m_hierarchicalPathLabel->SetLabel( hierarchicalPath );
796 
797  // Handle a delayed focus
798  if( m_delayedFocusRow >= 0 )
799  {
800  m_grid->SetFocus();
801  m_grid->MakeCellVisible( m_delayedFocusRow, m_delayedFocusColumn );
802  m_grid->SetGridCursor( m_delayedFocusRow, m_delayedFocusColumn );
803 
804 
805  m_grid->EnableCellEditControl( true );
806  m_grid->ShowCellEditControl();
807 
808  m_delayedFocusRow = -1;
810  }
811 }
812 
813 
814 void DIALOG_SHEET_PROPERTIES::OnSizeGrid( wxSizeEvent& event )
815 {
816  auto new_size = event.GetSize().GetX();
817 
818  if( m_width != new_size )
819  {
820  AdjustGridColumns( new_size );
821  }
822 
823  // Always propagate for a grid repaint (needed if the height changes, as well as width)
824  event.Skip();
825 }
826 
827 
828 void DIALOG_SHEET_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
829 {
831 
832  // Now all widgets have the size fixed, call FinishDialogSettings
834 }
bool CheckSheetForRecursion(SCH_SHEET *aSheet, SCH_SHEET_PATH *aHierarchy)
Verify that aSheet will not cause a recursion error in aHierarchy.
Definition: sheet.cpp:44
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:240
const BITMAP_OPAQUE trash_xpm[1]
Definition: trash.cpp:34
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void OnDeleteField(wxCommandEvent &event) override
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:51
void Offset(const wxPoint &aOffset)
Definition: eda_text.h:259
Functions for manipulating tab traversal in forms and dialogs.
const wxString & GetFileName() const
Definition: sch_screen.h:186
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox
Definition: confirm.cpp:54
void SetSwatchColor(KIGFX::COLOR4D aColor, bool aSendEvent)
Set the current swatch color directly.
bool Remove(SCH_ITEM *aItem)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:241
bool SearchHierarchy(const wxString &aFilename, SCH_SCREEN **aScreen)
Search the existing hierarchy for an instance of screen loaded from aFileName.
Definition: sch_sheet.cpp:631
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
KIGFX::COLOR4D GetSwatchColor() const
EDA_TEXT_VJUSTIFY_T GetVertJustify() const
Definition: eda_text.h:206
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:253
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:44
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
Definition: sch_sheet.h:277
void OnUpdateUI(wxUpdateUIEvent &event) override
The first 2 are mandatory, and must be instantiated in SCH_SHEET.
Definition: sch_sheet.h:71
This file is part of the common library.
void OnMoveDown(wxCommandEvent &event) override
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:127
void SetDefaultColor(KIGFX::COLOR4D aColor)
Sets the color that will be chosen with the "Reset to Default" button in the chooser.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
wxString PathHumanReadable(bool aUseShortRootName=true) const
Return the sheet path in a human readable form made from thesheet names.
wxPoint GetPosition() const override
Definition: sch_field.cpp:673
KIID_PATH Path() const
Get the sheet path as an KIID_PATH.
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Definition: sch_sheet.cpp:151
EE_TYPE OfType(KICAD_T aType)
Definition: sch_rtree.h:219
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
double GetTextAngle() const
Definition: eda_text.h:180
int GetId() const
Definition: sch_field.h:120
void InitSheet(SCH_SHEET *aSheet, const wxString &aNewFilename)
Definition: sheet.cpp:93
KIGFX::COLOR4D GetBorderColor() const
Definition: sch_sheet.h:292
Schematic editor (Eeschema) main window.
void SetSwatchBackground(KIGFX::COLOR4D aBackground)
Set the swatch background color.
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
COLOR_SETTINGS * GetColorSettings() override
Returns a pointer to the active color theme settings.
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:65
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
SCH_SCREEN * GetScreen() const
Definition: sch_sheet.h:284
void OnInitDlg(wxInitDialogEvent &event) override
void SetPageNumber(const SCH_SHEET_PATH &aInstance, const wxString &aPageNumber)
Set the page number for the sheet instance aInstance.
Definition: sch_sheet.cpp:1092
wxString GetShownText(int aDepth=0) const override
Return the string actually shown after processing of the base text.
Definition: sch_field.cpp:104
bool IsNew() const
Definition: eda_item.h:187
KIGFX::COLOR4D GetBackgroundColor() const
Definition: sch_sheet.h:295
void SetBorderWidth(int aWidth)
Definition: sch_sheet.h:290
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:96
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:270
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
int GetScreenCount() const
Return the number of times the associated screen for the sheet is being used.
Definition: sch_sheet.cpp:174
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:82
int GetBorderWidth() const
Definition: sch_sheet.h:289
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:101
void SetBackgroundColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:296
bool AllowCaseSensitiveFileNameClashes(const wxString &aSchematicFileName)
Check aSchematicFileName for a potential file name case sensitivity clashes.
Definition: sheet.cpp:549
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:205
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
#define NULL
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
const BITMAP_OPAQUE small_down_xpm[1]
Definition: small_down.cpp:24
SCHEMATIC & Schematic() const
void SetBorderColor(KIGFX::COLOR4D aColor)
Definition: sch_sheet.h:293
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
Definition of file extensions used in Kicad.
static bool positioningChanged(const SCH_FIELD &a, const SCH_FIELD &b)
void ClearFieldsAutoplaced()
Set fields automatically placed flag false.
Definition: sch_item.h:458
Class DIALOG_SHEET_PROPERTIES_BASE.
Definition: color4d.h:59
wxLogTrace helper definitions.
static const wxString GetDefaultFieldName(int aFieldNdx)
Definition: sch_sheet.cpp:44
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:180
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition: sch_sheet.h:498
wxPoint GetPosition() const override
Definition: sch_sheet.h:571
const BITMAP_OPAQUE small_up_xpm[1]
Definition: small_up.cpp:25
void OnGridCellChanging(wxGridEvent &event)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:219
DIALOG_SHEET_PROPERTIES(SCH_EDIT_FRAME *aParent, SCH_SHEET *aSheet, bool *aClearAnnotationNewItems)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
Helper object to release a SCH_PLUGIN in the context of a potential thrown exception through its dest...
Definition: sch_io_mgr.h:470
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
wxString GetShownColumns()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:109
COLOR4D GetColor(int aLayer) const
SCH_SHEET & Root() const
Definition: schematic.h:102
SCH_SCREEN * LastScreen()
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:129
#define _(s)
Definition: 3d_actions.cpp:33
void OnMoveUp(wxCommandEvent &event) override
virtual void SetValue(int aValue)
Function SetValue Sets new value (in Internal Units) for the text field, taking care of units convers...
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:507
EE_RTREE & Items()
Definition: sch_screen.h:159
const std::string KiCadSchematicFileExtension
virtual long long int GetValue()
Function GetValue Returns the current value in Internal Units.
int ShowModal() override
Definition: confirm.cpp:96
Color settings are a bit different than most of the settings objects in that there can be more than o...
SCH_SHEET_PATH & GetCurrentSheet() const
bool GetOverrideSchItemColors() const
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:173
void OnSizeGrid(wxSizeEvent &event) override
void SetFileName(const wxString &aFileName)
Definition: sch_screen.h:184
bool onSheetFilenameChanged(const wxString &aNewFilename)
FIELDS_GRID_TABLE< SCH_FIELD > * m_fields
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:284
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:133
const BITMAP_OPAQUE small_plus_xpm[1]
Definition: small_plus.cpp:20
Custom text control validator definitions.
SCH_SHEET_LIST & GetFullHierarchy() const
Return the full schematic flattened hiearchical sheet list.
Definition: schematic.cpp:354
wxString GetPageNumber(const SCH_SHEET_PATH &aInstance) const
Return the sheet page number for aInstance.
Definition: sch_sheet.cpp:1074
bool AddInstance(const KIID_PATH &aInstance)
Add a new instance aSheetPath to the instance list.
Definition: sch_sheet.cpp:1050
void AppendMsgPanel(const wxString &aTextUpper, const wxString &aTextLower, int aPadding=6)
Append a message to the message panel.
COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:100
void OnAddField(wxCommandEvent &event) override