KiCad PCB EDA Suite
dialog_edit_component_in_schematic.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) 2004-2020 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, you may find one here:
18  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19  * or you may search the http://www.gnu.org website for the version 2 license,
20  * or you may write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23 
25 
26 #include <wx/tooltip.h>
27 #include <grid_tricks.h>
28 #include <confirm.h>
29 #include <kiface_i.h>
30 #include <pin_number.h>
31 #include <menus_helpers.h>
33 #include <widgets/wx_grid.h>
35 #include <ee_collectors.h>
36 #include <class_library.h>
37 #include <fields_grid_table.h>
38 #include <sch_edit_frame.h>
39 #include <sch_reference_list.h>
40 #include <schematic.h>
41 #include <tool/tool_manager.h>
42 #include <tool/actions.h>
43 
44 #ifdef KICAD_SPICE
45 #include <dialog_spice_model.h>
46 #endif /* KICAD_SPICE */
47 
48 
50 {
56 
57  COL_COUNT // keep as last
58 };
59 
60 
61 class SCH_PIN_TABLE_DATA_MODEL : public wxGridTableBase, public std::vector<SCH_PIN>
62 {
63 protected:
64  std::vector<wxGridCellAttr*> m_nameAttrs;
65  wxGridCellAttr* m_readOnlyAttr;
66  wxGridCellAttr* m_typeAttr;
67  wxGridCellAttr* m_shapeAttr;
68 
69 public:
71  m_readOnlyAttr( nullptr ),
72  m_typeAttr( nullptr ),
73  m_shapeAttr( nullptr )
74  {
75  }
76 
78  {
79  for( wxGridCellAttr* attr : m_nameAttrs )
80  attr->DecRef();
81 
82  m_readOnlyAttr->DecRef();
83  m_typeAttr->DecRef();
84  m_shapeAttr->DecRef();
85  }
86 
87  void BuildAttrs()
88  {
89  m_readOnlyAttr = new wxGridCellAttr;
90  m_readOnlyAttr->SetReadOnly( true );
91 
92  for( const SCH_PIN& pin : *this )
93  {
94  LIB_PIN* lib_pin = pin.GetLibPin();
95  wxGridCellAttr* attr = nullptr;
96 
97  if( lib_pin->GetAlternates().empty() )
98  {
99  attr = new wxGridCellAttr;
100  attr->SetReadOnly( true );
101  }
102  else
103  {
104  wxArrayString choices;
105  choices.push_back( lib_pin->GetName() );
106 
107  for( const std::pair<const wxString, LIB_PIN::ALT>& alt : lib_pin->GetAlternates() )
108  choices.push_back( alt.first );
109 
110  attr = new wxGridCellAttr();
111  attr->SetEditor( new wxGridCellChoiceEditor( choices ) );
112  }
113 
114  m_nameAttrs.push_back( attr );
115  }
116 
117  m_typeAttr = new wxGridCellAttr;
119  m_typeAttr->SetReadOnly( true );
120 
121  m_shapeAttr = new wxGridCellAttr;
123  m_shapeAttr->SetReadOnly( true );
124  }
125 
126  int GetNumberRows() override { return (int) size(); }
127  int GetNumberCols() override { return COL_COUNT; }
128 
129  wxString GetColLabelValue( int aCol ) override
130  {
131  switch( aCol )
132  {
133  case COL_NUMBER: return _( "Number" );
134  case COL_BASE_NAME: return _( "Base Name" );
135  case COL_ALT_NAME: return _( "Alternate Assignment" );
136  case COL_TYPE: return _( "Electrical Type" );
137  case COL_SHAPE: return _( "Graphic Style" );
138  default: wxFAIL; return wxEmptyString;
139  }
140  }
141 
142  bool IsEmptyCell( int row, int col ) override
143  {
144  return false; // don't allow adjacent cell overflow, even if we are actually empty
145  }
146 
147  wxString GetValue( int aRow, int aCol ) override
148  {
149  return GetValue( at( aRow ), aCol );
150  }
151 
152  static wxString GetValue( const SCH_PIN& aPin, int aCol )
153  {
154  switch( aCol )
155  {
156  case COL_NUMBER: return aPin.GetNumber();
157  case COL_BASE_NAME: return aPin.GetLibPin()->GetName();
158  case COL_ALT_NAME: return aPin.GetAlt();
159  case COL_TYPE: return PinTypeNames()[static_cast<int>( aPin.GetType() )];
160  case COL_SHAPE: return PinShapeNames()[static_cast<int>( aPin.GetShape() )];
161  default: wxFAIL; return wxEmptyString;
162  }
163  }
164 
165  wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind ) override
166  {
167  switch( aCol )
168  {
169  case COL_NUMBER:
170  case COL_BASE_NAME:
171  m_readOnlyAttr->IncRef();
172  return m_readOnlyAttr;
173 
174  case COL_ALT_NAME:
175  m_nameAttrs[ aRow ]->IncRef();
176  return m_nameAttrs[ aRow ];
177 
178  case COL_TYPE:
179  m_typeAttr->IncRef();
180  return m_typeAttr;
181 
182  case COL_SHAPE:
183  m_shapeAttr->IncRef();
184  return m_shapeAttr;
185 
186  default:
187  wxFAIL;
188  return nullptr;
189  }
190  }
191 
192  void SetValue( int aRow, int aCol, const wxString &aValue ) override
193  {
194  switch( aCol )
195  {
196  case COL_ALT_NAME:
197  if( aValue == at( aRow ).GetName() )
198  at( aRow ).SetAlt( wxEmptyString );
199  else
200  at( aRow ).SetAlt( aValue );
201  break;
202 
203  case COL_NUMBER:
204  case COL_BASE_NAME:
205  case COL_TYPE:
206  case COL_SHAPE:
207  // Read-only.
208  break;
209 
210  default:
211  wxFAIL;
212  break;
213  }
214  }
215 
216  static bool compare( const SCH_PIN& lhs, const SCH_PIN& rhs, int sortCol, bool ascending )
217  {
218  wxString lhStr = GetValue( lhs, sortCol );
219  wxString rhStr = GetValue( rhs, sortCol );
220 
221  if( lhStr == rhStr )
222  {
223  // Secondary sort key is always COL_NUMBER
224  sortCol = COL_NUMBER;
225  lhStr = GetValue( lhs, sortCol );
226  rhStr = GetValue( rhs, sortCol );
227  }
228 
229  bool res;
230 
231  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
232  // to get the opposite sort. i.e. ~(a<b) != (a>b)
233  auto cmp = [ ascending ]( const auto a, const auto b )
234  {
235  if( ascending )
236  return a < b;
237  else
238  return b < a;
239  };
240 
241  switch( sortCol )
242  {
243  case COL_NUMBER:
244  case COL_BASE_NAME:
245  case COL_ALT_NAME:
246  res = cmp( PinNumbers::Compare( lhStr, rhStr ), 0 );
247  break;
248  case COL_TYPE:
249  case COL_SHAPE:
250  res = cmp( lhStr.CmpNoCase( rhStr ), 0 );
251  break;
252  default:
253  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
254  break;
255  }
256 
257  return res;
258  }
259 
260  void SortRows( int aSortCol, bool ascending )
261  {
262  std::sort( begin(), end(),
263  [ aSortCol, ascending ]( const SCH_PIN& lhs, const SCH_PIN& rhs ) -> bool
264  {
265  return compare( lhs, rhs, aSortCol, ascending );
266  } );
267  }
268 };
269 
270 
272  SCH_COMPONENT* aComponent ) :
274 {
275  m_comp = aComponent;
276  m_part = m_comp->GetPartRef().get();
277 
278  // GetPartRef() now points to the cached part in the schematic, which should always be
279  // there
280  wxASSERT( m_part );
281 
282  m_fields = new FIELDS_GRID_TABLE<SCH_FIELD>( this, aParent, m_part );
283 
284  m_width = 0;
287 
288 #ifndef KICAD_SPICE
289  m_spiceFieldsButton->Hide();
290 #endif /* not KICAD_SPICE */
291 
292  // disable some options inside the edit dialog which can cause problems while dragging
293  if( m_comp->IsDragging() )
294  {
295  m_orientationLabel->Disable();
296  m_orientationCtrl->Disable();
297  m_mirrorLabel->Disable();
298  m_mirrorCtrl->Disable();
299  }
300 
301  // Give a bit more room for combobox editors
302  m_fieldsGrid->SetDefaultRowSize( m_fieldsGrid->GetDefaultRowSize() + 4 );
303  m_pinGrid->SetDefaultRowSize( m_pinGrid->GetDefaultRowSize() + 4 );
304 
306  m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this ) );
307 
308  // Show/hide columns according to user's preference
309  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
310 
311  if( cfg )
312  {
313  m_shownColumns = cfg->m_Appearance.edit_component_visible_columns;
315  }
316 
318 
319  // Make a copy of the pins for editing
320  for( const std::unique_ptr<SCH_PIN>& pin : m_comp->GetRawPins() )
321  m_dataModel->push_back( *pin );
322 
323  m_dataModel->SortRows( COL_NUMBER, true );
325 
327  m_pinGrid->PushEventHandler( new GRID_TRICKS( m_pinGrid ) );
328 
329  // Set font size for items showing long strings:
330  wxFont infoFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
331  infoFont.SetSymbolicSize( wxFONTSIZE_SMALL );
332 
333  m_libraryIDLabel->SetFont( infoFont );
334  m_tcLibraryID->SetFont( infoFont );
335 
336  wxToolTip::Enable( true );
337  m_stdDialogButtonSizerOK->SetDefault();
338 
339  // Configure button logos
340  m_bpAdd->SetBitmap( KiBitmap( small_plus_xpm ) );
341  m_bpDelete->SetBitmap( KiBitmap( trash_xpm ) );
342  m_bpMoveUp->SetBitmap( KiBitmap( small_up_xpm ) );
343  m_bpMoveDown->SetBitmap( KiBitmap( small_down_xpm ) );
344 
345  // wxFormBuilder doesn't include this event...
346  m_fieldsGrid->Connect( wxEVT_GRID_CELL_CHANGING,
348  nullptr, this );
349 
350  m_pinGrid->Connect( wxEVT_GRID_COL_SORT,
352  nullptr, this );
353 
355 }
356 
357 
359 {
360  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
361 
362  if( cfg )
363  cfg->m_Appearance.edit_component_visible_columns = m_fieldsGrid->GetShownColumns();
364 
365  // Prevents crash bug in wxGrid's d'tor
368 
369  m_fieldsGrid->Disconnect( wxEVT_GRID_CELL_CHANGING,
371  nullptr, this );
372  m_pinGrid->Disconnect( wxEVT_GRID_COL_SORT,
374  nullptr, this );
375 
376  // Delete the GRID_TRICKS.
377  m_fieldsGrid->PopEventHandler( true );
378  m_pinGrid->PopEventHandler( true );
379 }
380 
381 
383 {
384  return dynamic_cast<SCH_EDIT_FRAME*>( wxDialog::GetParent() );
385 }
386 
387 
389 {
390  if( !wxDialog::TransferDataToWindow() )
391  return false;
392 
393  std::set<wxString> defined;
394 
395  // Push a copy of each field into m_updateFields
396  for( int i = 0; i < m_comp->GetFieldCount(); ++i )
397  {
398  SCH_FIELD field( *m_comp->GetField( i ) );
399 
400  // change offset to be symbol-relative
401  field.Offset( -m_comp->GetPosition() );
402 
403  defined.insert( field.GetName() );
404  m_fields->push_back( field );
405  }
406 
407  // Add in any template fieldnames not yet defined:
408  for( const TEMPLATE_FIELDNAME& templateFieldname :
409  GetParent()->Schematic().Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
410  {
411  if( defined.count( templateFieldname.m_Name ) <= 0 )
412  {
413  SCH_FIELD field( wxPoint( 0, 0 ), -1, m_comp, templateFieldname.m_Name );
414  field.SetVisible( templateFieldname.m_Visible );
415  m_fields->push_back( field );
416  }
417  }
418 
419  // notify the grid
420  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
421  m_fieldsGrid->ProcessTableMessage( msg );
422  AdjustGridColumns( m_fieldsGrid->GetRect().GetWidth() );
423 
424  // If a multi-unit component, set up the unit selector and interchangeable checkbox.
425  if( m_comp->GetUnitCount() > 1 )
426  {
427  for( int ii = 1; ii <= m_comp->GetUnitCount(); ii++ )
428  m_unitChoice->Append( LIB_PART::SubReference( ii, false ) );
429 
430  if( m_comp->GetUnit() <= ( int )m_unitChoice->GetCount() )
431  m_unitChoice->SetSelection( m_comp->GetUnit() - 1 );
432  }
433  else
434  {
435  m_unitLabel->Enable( false );
436  m_unitChoice->Enable( false );
437  }
438 
439  if( m_part->HasConversion() )
440  {
441  if( m_comp->GetConvert() > LIB_ITEM::LIB_CONVERT::BASE )
442  m_cbAlternateSymbol->SetValue( true );
443  }
444  else
445  {
446  m_cbAlternateSymbol->Enable( false );
447  }
448 
449  // Set the symbol orientation and mirroring.
450  int orientation = m_comp->GetOrientation() & ~( CMP_MIRROR_X | CMP_MIRROR_Y );
451 
452  switch( orientation )
453  {
454  default:
455  case CMP_ORIENT_0: m_orientationCtrl->SetSelection( 0 ); break;
456  case CMP_ORIENT_90: m_orientationCtrl->SetSelection( 1 ); break;
457  case CMP_ORIENT_270: m_orientationCtrl->SetSelection( 2 ); break;
458  case CMP_ORIENT_180: m_orientationCtrl->SetSelection( 3 ); break;
459  }
460 
461  int mirror = m_comp->GetOrientation() & ( CMP_MIRROR_X | CMP_MIRROR_Y );
462 
463  switch( mirror )
464  {
465  default: m_mirrorCtrl->SetSelection( 0 ) ; break;
466  case CMP_MIRROR_X: m_mirrorCtrl->SetSelection( 1 ); break;
467  case CMP_MIRROR_Y: m_mirrorCtrl->SetSelection( 2 ); break;
468  }
469 
470  m_cbExcludeFromBom->SetValue( !m_comp->GetIncludeInBom() );
472 
473  m_ShowPinNumButt->SetValue( m_part->ShowPinNumbers() );
474  m_ShowPinNameButt->SetValue( m_part->ShowPinNames() );
475 
476  // Set the component's library name.
477  m_tcLibraryID->SetValue( m_comp->GetLibId().Format() );
478 
479  Layout();
480 
481  return true;
482 }
483 
484 
486 {
487 #ifdef KICAD_SPICE
488  int diff = m_fields->size();
489 
490  DIALOG_SPICE_MODEL dialog( this, *m_comp, m_fields );
491 
492  if( dialog.ShowModal() != wxID_OK )
493  return;
494 
495  diff = (int) m_fields->size() - diff;
496 
497  if( diff > 0 )
498  {
499  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, diff );
500  m_fieldsGrid->ProcessTableMessage( msg );
501  }
502  else if( diff < 0 )
503  {
504  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, -diff );
505  m_fieldsGrid->ProcessTableMessage( msg );
506  }
507 
508  m_fieldsGrid->ForceRefresh();
509 #endif /* KICAD_SPICE */
510 }
511 
512 
514 {
515  // Running the Footprint Browser gums up the works and causes the automatic cancel
516  // stuff to no longer work. So we do it here ourselves.
517  EndQuasiModal( wxID_CANCEL );
518 }
519 
520 
522 {
523  wxString msg;
524  LIB_ID id;
525 
526  if( !m_fieldsGrid->CommitPendingChanges() || !m_fieldsGrid->Validate() )
527  return false;
528 
529  if( !SCH_COMPONENT::IsReferenceStringValid( m_fields->at( REFERENCE ).GetText() ) )
530  {
531  DisplayErrorMessage( this, _( "References must start with a letter." ) );
532 
535 
536  return false;
537  }
538 
539  // Check for missing field names.
540  for( size_t i = MANDATORY_FIELDS; i < m_fields->size(); ++i )
541  {
542  SCH_FIELD& field = m_fields->at( i );
543  wxString fieldName = field.GetName( false );
544 
545  if( fieldName.IsEmpty() )
546  {
547  DisplayErrorMessage( this, _( "Fields must have a name." ) );
548 
550  m_delayedFocusRow = i;
551 
552  return false;
553  }
554  }
555 
556  return true;
557 }
558 
559 
561 {
562  if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
563  return false;
564 
566  return false;
567 
569  return false;
570 
571  SCH_SCREEN* currentScreen = GetParent()->GetScreen();
572  SCHEMATIC& schematic = GetParent()->Schematic();
573 
574  wxCHECK( currentScreen, false );
575 
576  // This needs to be done before the LIB_ID is changed to prevent stale library symbols in
577  // the schematic file.
578  currentScreen->Remove( m_comp );
579 
580  wxString msg;
581 
582  // save old cmp in undo list if not already in edit, or moving ...
583  if( m_comp->GetEditFlags() == 0 )
584  GetParent()->SaveCopyInUndoList( currentScreen, m_comp, UNDO_REDO::CHANGED, false );
585 
586  // Save current flags which could be modified by next change settings
587  STATUS_FLAGS flags = m_comp->GetFlags();
588 
589  // For symbols with multiple shapes (De Morgan representation) Set the selected shape:
590  if( m_cbAlternateSymbol->IsEnabled() && m_cbAlternateSymbol->GetValue() )
591  m_comp->SetConvert( LIB_ITEM::LIB_CONVERT::DEMORGAN );
592  else
593  m_comp->SetConvert( LIB_ITEM::LIB_CONVERT::BASE );
594 
595  //Set the part selection in multiple part per package
596  int unit_selection = m_unitChoice->IsEnabled() ? m_unitChoice->GetSelection() + 1 : 1;
597  m_comp->SetUnitSelection( &GetParent()->GetCurrentSheet(), unit_selection );
598  m_comp->SetUnit( unit_selection );
599 
600  switch( m_orientationCtrl->GetSelection() )
601  {
602  case 0: m_comp->SetOrientation( CMP_ORIENT_0 ); break;
603  case 1: m_comp->SetOrientation( CMP_ORIENT_90 ); break;
604  case 2: m_comp->SetOrientation( CMP_ORIENT_270 ); break;
605  case 3: m_comp->SetOrientation( CMP_ORIENT_180 ); break;
606  }
607 
608  switch( m_mirrorCtrl->GetSelection() )
609  {
610  case 0: break;
611  case 1: m_comp->SetOrientation( CMP_MIRROR_X ); break;
612  case 2: m_comp->SetOrientation( CMP_MIRROR_Y ); break;
613  }
614 
615  m_part->SetShowPinNames( m_ShowPinNameButt->GetValue() );
616  m_part->SetShowPinNumbers( m_ShowPinNumButt->GetValue() );
617 
618  // Restore m_Flag modified by SetUnit() and other change settings
619  m_comp->ClearFlags();
620  m_comp->SetFlags( flags );
621 
622  // change all field positions from relative to absolute
623  for( unsigned i = 0; i < m_fields->size(); ++i )
624  m_fields->at( i ).Offset( m_comp->GetPosition() );
625 
626  LIB_PART* entry = GetParent()->GetLibPart( m_comp->GetLibId() );
627 
628  if( entry && entry->IsPower() )
629  m_fields->at( VALUE ).SetText( m_comp->GetLibId().GetLibItemName() );
630 
631  // Push all fields to the component -except- for those which are TEMPLATE_FIELDNAMES
632  // with empty values.
633  SCH_FIELDS& fields = m_comp->GetFields();
634 
635  fields.clear();
636 
637  for( size_t i = 0; i < m_fields->size(); ++i )
638  {
639  SCH_FIELD& field = m_fields->at( i );
640  bool emptyTemplateField = false;
641 
642  if( i >= MANDATORY_FIELDS )
643  {
644  for( const TEMPLATE_FIELDNAME& fieldname :
646  {
647  if( field.GetName() == fieldname.m_Name && field.GetText().IsEmpty() )
648  {
649  emptyTemplateField = true;
650  break;
651  }
652  }
653  }
654 
655  if( !emptyTemplateField )
656  fields.push_back( field );
657  }
658 
659  // Reference has a specific initialization, depending on the current active sheet
660  // because for a given component, in a complex hierarchy, there are more than one
661  // reference.
662  m_comp->SetRef( &GetParent()->GetCurrentSheet(), m_fields->at( REFERENCE ).GetText() );
663 
664  // Similar for Value and Footprint, except that the GUI behaviour is that they are kept
665  // in sync between multiple instances.
666  m_comp->SetValue( m_fields->at( VALUE ).GetText() );
667  m_comp->SetFootprint( m_fields->at( FOOTPRINT ).GetText() );
668 
669  m_comp->SetIncludeInBom( !m_cbExcludeFromBom->IsChecked() );
671 
672  // The value, footprint and datasheet fields and exclude from bill of materials setting
673  // should be kept in sync in multi-unit parts.
674  if( m_comp->GetUnitCount() > 1 )
675  {
676  for( SCH_SHEET_PATH& sheet : GetParent()->Schematic().GetSheets() )
677  {
678  SCH_SCREEN* screen = sheet.LastScreen();
679  std::vector<SCH_COMPONENT*> otherUnits;
680 
681  CollectOtherUnits( sheet, m_comp, &otherUnits );
682 
683  for( SCH_COMPONENT* otherUnit : otherUnits )
684  {
685  GetParent()->SaveCopyInUndoList( screen, otherUnit, UNDO_REDO::CHANGED, true /* append */);
686  otherUnit->GetField( VALUE )->SetText( m_fields->at( VALUE ).GetText() );
687  otherUnit->GetField( FOOTPRINT )->SetText( m_fields->at( FOOTPRINT ).GetText() );
688  otherUnit->GetField( DATASHEET )->SetText( m_fields->at( DATASHEET ).GetText() );
689  otherUnit->SetIncludeInBom( !m_cbExcludeFromBom->IsChecked() );
690  otherUnit->SetIncludeOnBoard( !m_cbExcludeFromBoard->IsChecked() );
691  GetParent()->UpdateItem( otherUnit );
692  }
693  }
694  }
695 
696  // Update any assignments
697  for( const SCH_PIN& model_pin : *m_dataModel )
698  {
699  // map from the edited copy back to the "real" pin in the component
700  SCH_PIN* src_pin = m_comp->GetPin( model_pin.GetLibPin() );
701  src_pin->SetAlt( model_pin.GetAlt() );
702  }
703 
704  currentScreen->Append( m_comp );
707  GetParent()->OnModify();
708 
709  // This must go after OnModify() so that the connectivity graph will have been updated.
711 
712  return true;
713 }
714 
715 
717 {
718  wxGridCellEditor* editor = m_fieldsGrid->GetCellEditor( event.GetRow(), event.GetCol() );
719  wxControl* control = editor->GetControl();
720 
721  if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
722  {
723  event.Veto();
724  m_delayedFocusRow = event.GetRow();
725  m_delayedFocusColumn = event.GetCol();
726  }
727  else if( event.GetCol() == FDC_NAME )
728  {
729  wxString newName = event.GetString();
730 
731  for( int i = 0; i < m_fieldsGrid->GetNumberRows(); ++i )
732  {
733  if( i == event.GetRow() )
734  continue;
735 
736  if( newName.CmpNoCase( m_fieldsGrid->GetCellValue( i, FDC_NAME ) ) == 0 )
737  {
738  DisplayError( this, wxString::Format( _( "The name '%s' is already in use." ),
739  newName ) );
740  event.Veto();
741  m_delayedFocusRow = event.GetRow();
742  m_delayedFocusColumn = event.GetCol();
743  }
744  }
745  }
746 
747  editor->DecRef();
748 }
749 
750 
752 {
754  return;
755 
756  SCHEMATIC_SETTINGS& settings = m_comp->Schematic()->Settings();
757  int fieldID = m_fields->size();
758  SCH_FIELD newField( wxPoint( 0, 0 ), fieldID, m_comp,
760 
761  newField.SetTextAngle( m_fields->at( REFERENCE ).GetTextAngle() );
762  newField.SetTextSize( wxSize( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
763 
764  m_fields->push_back( newField );
765 
766  // notify the grid
767  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
768  m_fieldsGrid->ProcessTableMessage( msg );
769 
770  m_fieldsGrid->MakeCellVisible( (int) m_fields->size() - 1, 0 );
771  m_fieldsGrid->SetGridCursor( (int) m_fields->size() - 1, 0 );
772 
773  m_fieldsGrid->EnableCellEditControl();
774  m_fieldsGrid->ShowCellEditControl();
775 }
776 
777 
779 {
780  int curRow = m_fieldsGrid->GetGridCursorRow();
781 
782  if( curRow < 0 )
783  {
784  return;
785  }
786  else if( curRow < MANDATORY_FIELDS )
787  {
788  DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
789  MANDATORY_FIELDS ) );
790  return;
791  }
792 
793  m_fieldsGrid->CommitPendingChanges( true /* quiet mode */ );
794 
795  m_fields->erase( m_fields->begin() + curRow );
796 
797  // notify the grid
798  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
799  m_fieldsGrid->ProcessTableMessage( msg );
800 
801  if( m_fieldsGrid->GetNumberRows() > 0 )
802  {
803  m_fieldsGrid->MakeCellVisible( std::max( 0, curRow-1 ), m_fieldsGrid->GetGridCursorCol() );
804  m_fieldsGrid->SetGridCursor( std::max( 0, curRow-1 ), m_fieldsGrid->GetGridCursorCol() );
805  }
806 }
807 
808 
809 void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnMoveUp( wxCommandEvent& event )
810 {
812  return;
813 
814  int i = m_fieldsGrid->GetGridCursorRow();
815 
816  if( i > MANDATORY_FIELDS )
817  {
818  SCH_FIELD tmp = m_fields->at( (unsigned) i );
819  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
820  m_fields->insert( m_fields->begin() + i - 1, tmp );
821  m_fieldsGrid->ForceRefresh();
822 
823  m_fieldsGrid->SetGridCursor( i - 1, m_fieldsGrid->GetGridCursorCol() );
824  m_fieldsGrid->MakeCellVisible( m_fieldsGrid->GetGridCursorRow(), m_fieldsGrid->GetGridCursorCol() );
825  }
826  else
827  {
828  wxBell();
829  }
830 }
831 
832 
834 {
836  return;
837 
838  int i = m_fieldsGrid->GetGridCursorRow();
839 
840  if( i >= MANDATORY_FIELDS && i < m_fieldsGrid->GetNumberRows() - 1 )
841  {
842  SCH_FIELD tmp = m_fields->at( (unsigned) i );
843  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
844  m_fields->insert( m_fields->begin() + i + 1, tmp );
845  m_fieldsGrid->ForceRefresh();
846 
847  m_fieldsGrid->SetGridCursor( i + 1, m_fieldsGrid->GetGridCursorCol() );
848  m_fieldsGrid->MakeCellVisible( m_fieldsGrid->GetGridCursorRow(), m_fieldsGrid->GetGridCursorCol() );
849  }
850  else
851  {
852  wxBell();
853  }
854 }
855 
856 
858 {
860 }
861 
862 
864 {
866 }
867 
868 
870 {
872 }
873 
874 
876 {
878 }
879 
880 
882 {
883  int row = aEvent.GetRow();
884 
885  if( m_pinGrid->GetCellValue( row, COL_ALT_NAME ) == m_dataModel->GetValue( row, COL_BASE_NAME ) )
886  m_dataModel->SetValue( row, COL_ALT_NAME, wxEmptyString );
887 
888  // These are just to get the cells refreshed
891 
892  m_modified = true;
893 }
894 
895 
897 {
898  int sortCol = aEvent.GetCol();
899  bool ascending;
900 
901  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
902  // event, and if we ask it will give us pre-event info.
903  if( m_pinGrid->IsSortingBy( sortCol ) )
904  // same column; invert ascending
905  ascending = !m_pinGrid->IsSortOrderAscending();
906  else
907  // different column; start with ascending
908  ascending = true;
909 
910  m_dataModel->SortRows( sortCol, ascending );
911 }
912 
913 
915 {
916  wxGridUpdateLocker deferRepaintsTillLeavingScope;
917 
918  m_width = aWidth;
919 
920  // Account for scroll bars
921  int fieldsWidth = aWidth - ( m_fieldsGrid->GetSize().x - m_fieldsGrid->GetClientSize().x );
922  int pinTblWidth = aWidth - ( m_pinGrid->GetSize().x - m_pinGrid->GetClientSize().x );
923 
924  m_fieldsGrid->AutoSizeColumn( 0 );
925 
926  int fixedColsWidth = m_fieldsGrid->GetColSize( 0 );
927 
928  for( int i = 2; i < m_fieldsGrid->GetNumberCols(); i++ )
929  fixedColsWidth += m_fieldsGrid->GetColSize( i );
930 
931  m_fieldsGrid->SetColSize( 1, fieldsWidth - fixedColsWidth );
932 
933  // Stretch the Base Name and Alternate Assignment columns to fit.
934  for( int i = 0; i < COL_COUNT; ++i )
935  {
936  if( i != COL_BASE_NAME && i != COL_ALT_NAME )
937  pinTblWidth -= m_pinGrid->GetColSize( i );
938  }
939 
940  // Why? I haven't a clue....
941  pinTblWidth += 22;
942 
943  m_pinGrid->SetColSize( COL_BASE_NAME, pinTblWidth / 2 );
944  m_pinGrid->SetColSize( COL_ALT_NAME, pinTblWidth / 2 );
945 }
946 
947 
949 {
950  wxString shownColumns = m_fieldsGrid->GetShownColumns();
951 
952  if( shownColumns != m_shownColumns )
953  {
954  m_shownColumns = shownColumns;
955 
956  if( !m_fieldsGrid->IsCellEditControlShown() )
957  AdjustGridColumns( m_fieldsGrid->GetRect().GetWidth() );
958  }
959 
960  // Handle a delayed focus
961  if( m_delayedFocusRow >= 0 )
962  {
963  m_fieldsGrid->SetFocus();
966 
967 
968  m_fieldsGrid->EnableCellEditControl( true );
969  m_fieldsGrid->ShowCellEditControl();
970 
971  m_delayedFocusRow = -1;
973  }
974 }
975 
976 
978 {
979  auto new_size = event.GetSize().GetX();
980 
981  if( m_width != new_size )
982  {
983  AdjustGridColumns( new_size );
984  }
985 
986  // Always propagate for a grid repaint (needed if the height changes, as well as width)
987  event.Skip();
988 }
989 
990 
991 void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::OnInitDlg( wxInitDialogEvent& event )
992 {
994 
995  // Now all widgets have the size fixed, call FinishDialogSettings
997 }
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
DIALOG_EDIT_COMPONENT_IN_SCHEMATIC(SCH_EDIT_FRAME *aParent, SCH_COMPONENT *aComponent)
static int Compare(PinNumber const &lhs, PinNumber const &rhs)
Definition: pin_number.cpp:111
void SortRows(int aSortCol, bool ascending)
const BITMAP_OPAQUE trash_xpm[1]
Definition: trash.cpp:46
wxString GetColLabelValue(int aCol) override
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
void Offset(const wxPoint &aOffset)
Definition: eda_text.h:253
wxString GetValue(int aRow, int aCol) override
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:67
std::vector< std::unique_ptr< SCH_PIN > > & GetRawPins()
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
bool Remove(SCH_ITEM *aItem)
Remove aItem from the schematic associated with this screen.
Definition: sch_screen.cpp:243
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
name of datasheet
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:409
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:89
int GetOrientation()
Get the display symbol orientation.
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:252
void OnMoveDown(wxCommandEvent &event) override
void SetIncludeInBom(bool aIncludeInBom)
Holds all the data relating to one schematic A schematic may consist of one or more sheets (and one r...
Definition: schematic.h:42
This file is part of the common library.
bool GetIncludeOnBoard() const
bool HasConversion() const
Test if part has more than one body conversion type (DeMorgan).
void ShowHideColumns(const wxString &shownColumns)
Show/hide the grid columns based on a tokenized string of shown column indexes.
Definition: wx_grid.cpp:127
const std::vector< BITMAP_DEF > & PinTypeIcons()
Definition: pin_type.cpp:194
void OnAddField(wxCommandEvent &event) override
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:124
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
void OnEditSpiceModel(wxCommandEvent &event) override
void OnInitDlg(wxInitDialogEvent &event) override
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
TEMPLATES m_TemplateFieldNames
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:116
wxString GetAlt() const
Definition: sch_pin.h:72
int GetUnitCount() const
Return the number of units per package of the symbol.
void SetVisible(bool aVisible)
Definition: eda_text.h:185
GRID_TRICKS is used to add mouse and command handling (such as cut, copy, and paste) to a WX_GRID ins...
Definition: grid_tricks.h:51
void OnCancelButtonClick(wxCommandEvent &event) override
SCH_PIN * GetPin(const wxString &number)
Find a symbol pin by number.
static const wxString GetDefaultFieldName(int aFieldNdx)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
Schematic editor (Eeschema) main window.
wxString GetNumber() const
Definition: sch_pin.h:112
LIB_PART * GetLibPart(const LIB_ID &aLibId, bool aUseCacheLib=false, bool aShowErrorMsg=false)
Load symbol from symbol library table.
bool TestDanglingEnds()
Test all of the connectable objects in the schematic for unused connection points.
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:238
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
void SetIncludeOnBoard(bool aIncludeOnBoard)
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
Field Name Module PCB, i.e. "16DIP300".
Field Reference of part, i.e. "IC21".
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:211
bool IsDragging() const
Definition: base_struct.h:201
const std::vector< BITMAP_DEF > & PinShapeIcons()
Definition: pin_type.cpp:212
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populates a std::vector with SCH_FIELDs.
void SetConvert(int aConvert)
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
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
bool ShowPinNames()
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
int GetUnit() const
bool ShowPinNumbers()
const wxArrayString & PinShapeNames()
Definition: pin_type.cpp:203
bool IsEmptyCell(int row, int col) override
void SetFlags(STATUS_FLAGS aMask)
Definition: base_struct.h:232
STATUS_FLAGS GetEditFlags() const
Definition: base_struct.h:237
const wxString & GetName() const
Definition: lib_pin.h:156
std::vector< SCH_FIELD > SCH_FIELDS
A container for several SCH_FIELD items.
Definition: sch_component.h:65
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
const BITMAP_OPAQUE small_down_xpm[1]
Definition: small_down.cpp:25
SCHEMATIC & Schematic() const
Define a library symbol object.
void OnDeleteField(wxCommandEvent &event) override
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.
const wxArrayString & PinTypeNames()
Definition: pin_type.cpp:185
unsigned STATUS_FLAGS
Definition: base_struct.h:152
static wxString GetValue(const SCH_PIN &aPin, int aCol)
GRAPHIC_PINSHAPE GetShape() const
Definition: sch_pin.cpp:83
void SetUnit(int aUnit)
Change the unit number to aUnit.
SCH_SHEET_PATH.
std::unique_ptr< LIB_PART > & GetPartRef()
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:180
bool GetIncludeInBom() const
const BITMAP_OPAQUE small_up_xpm[1]
Definition: small_up.cpp:26
int GetFieldCount() const
Return the number of fields in this symbol.
UTF8 Format() const
Definition: lib_id.cpp:237
Class DIALOG_EDIT_COMPONENT_IN_SCHEMATIC_BASE.
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
Field Value of part, i.e. "3.3K".
wxString GetShownColumns()
Get a tokenized string containing the shown column indexes.
Definition: wx_grid.cpp:109
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void EndQuasiModal(int retCode)
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
std::map< wxString, ALT > & GetAlternates()
Definition: lib_pin.h:180
bool IsPower() const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:131
#define _(s)
Definition: 3d_actions.cpp:33
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:74
void SetAlt(const wxString &aAlt)
Definition: sch_pin.h:73
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:442
static wxString SubReference(int aUnit, bool aAddSeparator=true)
std::vector< wxGridCellAttr * > m_nameAttrs
Schematic symbol object.
Definition: sch_component.h:80
wxPoint GetPosition() const override
These settings were stored in SCH_BASE_FRAME previously.
Struct TEMPLATE_FIELDNAME holds a name of a component's field, field value, and default visibility.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:233
static bool compare(const SCH_PIN &lhs, const SCH_PIN &rhs, int sortCol, bool ascending)
void OnPinTableCellEdited(wxGridEvent &event) override
int GetConvert() const
void CollectOtherUnits(SCH_SHEET_PATH &aSheet, SCH_COMPONENT *aUnit, std::vector< SCH_COMPONENT * > *otherUnits)
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:78
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:167
Definition for part library class.
void SetValue(const SCH_SHEET_PATH *sheet, const wxString &aValue)
static bool IsReferenceStringValid(const wxString &aReferenceString)
Tests for an acceptable reference string.
void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:234
const LIB_ID & GetLibId() const
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind) override
void PostEvent(const TOOL_EVENT &aEvent)
Puts an event to the event queue to be processed at the end of event processing cycle.
Definition: tool_manager.h:273
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:127
const BITMAP_OPAQUE small_plus_xpm[1]
Definition: small_plus.cpp:20
void OnUpdateUI(wxUpdateUIEvent &event) override
void SetFootprint(const SCH_SHEET_PATH *sheet, const wxString &aFootprint)
const TEMPLATE_FIELDNAMES & GetTemplateFieldNames()
Function GetTemplateFieldName returns a template fieldnames list for read only access.
void SetValue(int aRow, int aCol, const wxString &aValue) override
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...