KiCad PCB EDA Suite
dialog_symbol_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) 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 <kicad_string.h>
32 #include <menus_helpers.h>
34 #include <widgets/wx_grid.h>
36 #include <ee_collectors.h>
37 #include <class_library.h>
38 #include <fields_grid_table.h>
39 #include <sch_edit_frame.h>
40 #include <sch_reference_list.h>
41 #include <schematic.h>
42 #include <tool/tool_manager.h>
43 #include <tool/actions.h>
44 
45 #ifdef KICAD_SPICE
46 #include <dialog_spice_model.h>
47 #endif /* KICAD_SPICE */
48 
49 
51 {
57 
58  COL_COUNT // keep as last
59 };
60 
61 
62 class SCH_PIN_TABLE_DATA_MODEL : public wxGridTableBase, public std::vector<SCH_PIN>
63 {
64 protected:
65  std::vector<wxGridCellAttr*> m_nameAttrs;
66  wxGridCellAttr* m_readOnlyAttr;
67  wxGridCellAttr* m_typeAttr;
68  wxGridCellAttr* m_shapeAttr;
69 
70 public:
72  m_readOnlyAttr( nullptr ),
73  m_typeAttr( nullptr ),
74  m_shapeAttr( nullptr )
75  {
76  }
77 
79  {
80  for( wxGridCellAttr* attr : m_nameAttrs )
81  attr->DecRef();
82 
83  m_readOnlyAttr->DecRef();
84  m_typeAttr->DecRef();
85  m_shapeAttr->DecRef();
86  }
87 
88  void BuildAttrs()
89  {
90  m_readOnlyAttr = new wxGridCellAttr;
91  m_readOnlyAttr->SetReadOnly( true );
92 
93  for( const SCH_PIN& pin : *this )
94  {
95  LIB_PIN* lib_pin = pin.GetLibPin();
96  wxGridCellAttr* attr = nullptr;
97 
98  if( lib_pin->GetAlternates().empty() )
99  {
100  attr = new wxGridCellAttr;
101  attr->SetReadOnly( true );
102  }
103  else
104  {
105  wxArrayString choices;
106  choices.push_back( lib_pin->GetName() );
107 
108  for( const std::pair<const wxString, LIB_PIN::ALT>& alt : lib_pin->GetAlternates() )
109  choices.push_back( alt.first );
110 
111  attr = new wxGridCellAttr();
112  attr->SetEditor( new wxGridCellChoiceEditor( choices ) );
113  }
114 
115  m_nameAttrs.push_back( attr );
116  }
117 
118  m_typeAttr = new wxGridCellAttr;
120  m_typeAttr->SetReadOnly( true );
121 
122  m_shapeAttr = new wxGridCellAttr;
124  m_shapeAttr->SetReadOnly( true );
125  }
126 
127  int GetNumberRows() override { return (int) size(); }
128  int GetNumberCols() override { return COL_COUNT; }
129 
130  wxString GetColLabelValue( int aCol ) override
131  {
132  switch( aCol )
133  {
134  case COL_NUMBER: return _( "Number" );
135  case COL_BASE_NAME: return _( "Base Name" );
136  case COL_ALT_NAME: return _( "Alternate Assignment" );
137  case COL_TYPE: return _( "Electrical Type" );
138  case COL_SHAPE: return _( "Graphic Style" );
139  default: wxFAIL; return wxEmptyString;
140  }
141  }
142 
143  bool IsEmptyCell( int row, int col ) override
144  {
145  return false; // don't allow adjacent cell overflow, even if we are actually empty
146  }
147 
148  wxString GetValue( int aRow, int aCol ) override
149  {
150  return GetValue( at( aRow ), aCol );
151  }
152 
153  static wxString GetValue( const SCH_PIN& aPin, int aCol )
154  {
155  switch( aCol )
156  {
157  case COL_NUMBER: return aPin.GetNumber();
158  case COL_BASE_NAME: return aPin.GetLibPin()->GetName();
159  case COL_ALT_NAME: return aPin.GetAlt();
160  case COL_TYPE: return PinTypeNames()[static_cast<int>( aPin.GetType() )];
161  case COL_SHAPE: return PinShapeNames()[static_cast<int>( aPin.GetShape() )];
162  default: wxFAIL; return wxEmptyString;
163  }
164  }
165 
166  wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind ) override
167  {
168  switch( aCol )
169  {
170  case COL_NUMBER:
171  case COL_BASE_NAME:
172  m_readOnlyAttr->IncRef();
173  return m_readOnlyAttr;
174 
175  case COL_ALT_NAME:
176  m_nameAttrs[ aRow ]->IncRef();
177  return m_nameAttrs[ aRow ];
178 
179  case COL_TYPE:
180  m_typeAttr->IncRef();
181  return m_typeAttr;
182 
183  case COL_SHAPE:
184  m_shapeAttr->IncRef();
185  return m_shapeAttr;
186 
187  default:
188  wxFAIL;
189  return nullptr;
190  }
191  }
192 
193  void SetValue( int aRow, int aCol, const wxString &aValue ) override
194  {
195  switch( aCol )
196  {
197  case COL_ALT_NAME:
198  if( aValue == at( aRow ).GetName() )
199  at( aRow ).SetAlt( wxEmptyString );
200  else
201  at( aRow ).SetAlt( aValue );
202  break;
203 
204  case COL_NUMBER:
205  case COL_BASE_NAME:
206  case COL_TYPE:
207  case COL_SHAPE:
208  // Read-only.
209  break;
210 
211  default:
212  wxFAIL;
213  break;
214  }
215  }
216 
217  static bool compare( const SCH_PIN& lhs, const SCH_PIN& rhs, int sortCol, bool ascending )
218  {
219  wxString lhStr = GetValue( lhs, sortCol );
220  wxString rhStr = GetValue( rhs, sortCol );
221 
222  if( lhStr == rhStr )
223  {
224  // Secondary sort key is always COL_NUMBER
225  sortCol = COL_NUMBER;
226  lhStr = GetValue( lhs, sortCol );
227  rhStr = GetValue( rhs, sortCol );
228  }
229 
230  bool res;
231 
232  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
233  // to get the opposite sort. i.e. ~(a<b) != (a>b)
234  auto cmp = [ ascending ]( const auto a, const auto b )
235  {
236  if( ascending )
237  return a < b;
238  else
239  return b < a;
240  };
241 
242  switch( sortCol )
243  {
244  case COL_NUMBER:
245  case COL_BASE_NAME:
246  case COL_ALT_NAME:
247  res = cmp( PinNumbers::Compare( lhStr, rhStr ), 0 );
248  break;
249  case COL_TYPE:
250  case COL_SHAPE:
251  res = cmp( lhStr.CmpNoCase( rhStr ), 0 );
252  break;
253  default:
254  res = cmp( StrNumCmp( lhStr, rhStr ), 0 );
255  break;
256  }
257 
258  return res;
259  }
260 
261  void SortRows( int aSortCol, bool ascending )
262  {
263  std::sort( begin(), end(),
264  [ aSortCol, ascending ]( const SCH_PIN& lhs, const SCH_PIN& rhs ) -> bool
265  {
266  return compare( lhs, rhs, aSortCol, ascending );
267  } );
268  }
269 };
270 
271 
273  SCH_COMPONENT* aComponent ) :
275  m_comp( nullptr ),
276  m_part( nullptr ),
277  m_fields( nullptr ),
278  m_dataModel( nullptr )
279 {
280  m_comp = aComponent;
281  m_part = m_comp->GetPartRef().get();
282 
283  // GetPartRef() now points to the cached part in the schematic, which should always be
284  // there
285  wxASSERT( m_part );
286 
287  m_fields = new FIELDS_GRID_TABLE<SCH_FIELD>( this, aParent, m_part );
288 
289  m_width = 0;
292  m_delayedSelection = true;
293 
294 #ifndef KICAD_SPICE
295  m_spiceFieldsButton->Hide();
296 #endif /* not KICAD_SPICE */
297 
298  // disable some options inside the edit dialog which can cause problems while dragging
299  if( m_comp->IsDragging() )
300  {
301  m_orientationLabel->Disable();
302  m_orientationCtrl->Disable();
303  m_mirrorLabel->Disable();
304  m_mirrorCtrl->Disable();
305  }
306 
307  // Give a bit more room for combobox editors
308  m_fieldsGrid->SetDefaultRowSize( m_fieldsGrid->GetDefaultRowSize() + 4 );
309  m_pinGrid->SetDefaultRowSize( m_pinGrid->GetDefaultRowSize() + 4 );
310 
312  m_fieldsGrid->PushEventHandler( new FIELDS_GRID_TRICKS( m_fieldsGrid, this ) );
313 
314  // Show/hide columns according to user's preference
315  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
316 
317  if( cfg )
318  {
319  m_shownColumns = cfg->m_Appearance.edit_component_visible_columns;
321  }
322 
323  if( m_part->HasConversion() )
324  {
325  // DeMorgan conversions are a subclass of alternate pin assignments, so don't allow
326  // free-form alternate assignments as well. (We won't know how to map the alternates
327  // back and forth when the conversion is changed.)
328  m_notebook1->RemovePage( 1 );
329  }
330  else
331  {
333 
334  // Make a copy of the pins for editing
335  for( const std::unique_ptr<SCH_PIN>& pin : m_comp->GetRawPins() )
336  m_dataModel->push_back( *pin );
337 
338  m_dataModel->SortRows( COL_NUMBER, true );
340 
342  }
343 
344  m_pinGrid->PushEventHandler( new GRID_TRICKS( m_pinGrid ) );
345 
346  wxToolTip::Enable( true );
347  m_stdDialogButtonSizerOK->SetDefault();
348 
349  // Configure button logos
350  m_bpAdd->SetBitmap( KiBitmap( small_plus_xpm ) );
351  m_bpDelete->SetBitmap( KiBitmap( trash_xpm ) );
352  m_bpMoveUp->SetBitmap( KiBitmap( small_up_xpm ) );
353  m_bpMoveDown->SetBitmap( KiBitmap( small_down_xpm ) );
354 
355  // wxFormBuilder doesn't include this event...
356  m_fieldsGrid->Connect( wxEVT_GRID_CELL_CHANGING,
357  wxGridEventHandler( DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging ),
358  nullptr, this );
359 
360  m_pinGrid->Connect( wxEVT_GRID_COL_SORT,
361  wxGridEventHandler( DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort ),
362  nullptr, this );
363 
365 }
366 
367 
369 {
370  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
371 
372  if( cfg )
373  cfg->m_Appearance.edit_component_visible_columns = m_fieldsGrid->GetShownColumns();
374 
375  // Prevents crash bug in wxGrid's d'tor
377 
378  if( m_dataModel )
380 
381  m_fieldsGrid->Disconnect( wxEVT_GRID_CELL_CHANGING,
382  wxGridEventHandler( DIALOG_SYMBOL_PROPERTIES::OnGridCellChanging ),
383  nullptr, this );
384 
385  m_pinGrid->Disconnect( wxEVT_GRID_COL_SORT,
386  wxGridEventHandler( DIALOG_SYMBOL_PROPERTIES::OnPinTableColSort ),
387  nullptr, this );
388 
389  // Delete the GRID_TRICKS.
390  m_fieldsGrid->PopEventHandler( true );
391  m_pinGrid->PopEventHandler( true );
392 }
393 
394 
396 {
397  return dynamic_cast<SCH_EDIT_FRAME*>( wxDialog::GetParent() );
398 }
399 
400 
402 {
403  if( !wxDialog::TransferDataToWindow() )
404  return false;
405 
406  std::set<wxString> defined;
407 
408  // Push a copy of each field into m_updateFields
409  for( int i = 0; i < m_comp->GetFieldCount(); ++i )
410  {
411  SCH_FIELD field( *m_comp->GetField( i ) );
412 
413  // change offset to be symbol-relative
414  field.Offset( -m_comp->GetPosition() );
415 
416  defined.insert( field.GetName() );
417  m_fields->push_back( field );
418  }
419 
420  // Add in any template fieldnames not yet defined:
421  for( const TEMPLATE_FIELDNAME& templateFieldname :
422  GetParent()->Schematic().Settings().m_TemplateFieldNames.GetTemplateFieldNames() )
423  {
424  if( defined.count( templateFieldname.m_Name ) <= 0 )
425  {
426  SCH_FIELD field( wxPoint( 0, 0 ), -1, m_comp, templateFieldname.m_Name );
427  field.SetVisible( templateFieldname.m_Visible );
428  m_fields->push_back( field );
429  }
430  }
431 
432  // notify the grid
433  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_fields->size() );
434  m_fieldsGrid->ProcessTableMessage( msg );
435  AdjustGridColumns( m_fieldsGrid->GetRect().GetWidth() );
436 
437  // If a multi-unit component, set up the unit selector and interchangeable checkbox.
438  if( m_comp->GetUnitCount() > 1 )
439  {
440  for( int ii = 1; ii <= m_comp->GetUnitCount(); ii++ )
441  m_unitChoice->Append( LIB_PART::SubReference( ii, false ) );
442 
443  if( m_comp->GetUnit() <= ( int )m_unitChoice->GetCount() )
444  m_unitChoice->SetSelection( m_comp->GetUnit() - 1 );
445  }
446  else
447  {
448  m_unitLabel->Enable( false );
449  m_unitChoice->Enable( false );
450  }
451 
452  if( m_part->HasConversion() )
453  {
454  if( m_comp->GetConvert() > LIB_ITEM::LIB_CONVERT::BASE )
455  m_cbAlternateSymbol->SetValue( true );
456  }
457  else
458  {
459  m_cbAlternateSymbol->Enable( false );
460  }
461 
462  // Set the symbol orientation and mirroring.
463  int orientation = m_comp->GetOrientation() & ~( CMP_MIRROR_X | CMP_MIRROR_Y );
464 
465  switch( orientation )
466  {
467  default:
468  case CMP_ORIENT_0: m_orientationCtrl->SetSelection( 0 ); break;
469  case CMP_ORIENT_90: m_orientationCtrl->SetSelection( 1 ); break;
470  case CMP_ORIENT_270: m_orientationCtrl->SetSelection( 2 ); break;
471  case CMP_ORIENT_180: m_orientationCtrl->SetSelection( 3 ); break;
472  }
473 
474  int mirror = m_comp->GetOrientation() & ( CMP_MIRROR_X | CMP_MIRROR_Y );
475 
476  switch( mirror )
477  {
478  default: m_mirrorCtrl->SetSelection( 0 ) ; break;
479  case CMP_MIRROR_X: m_mirrorCtrl->SetSelection( 1 ); break;
480  case CMP_MIRROR_Y: m_mirrorCtrl->SetSelection( 2 ); break;
481  }
482 
483  m_cbExcludeFromBom->SetValue( !m_comp->GetIncludeInBom() );
485 
486  m_ShowPinNumButt->SetValue( m_part->ShowPinNumbers() );
487  m_ShowPinNameButt->SetValue( m_part->ShowPinNames() );
488 
489  // Set the component's library name.
490  m_tcLibraryID->SetLabelText( m_comp->GetLibId().Format() );
491 
492  Layout();
493 
494  return true;
495 }
496 
497 
498 void DIALOG_SYMBOL_PROPERTIES::OnEditSpiceModel( wxCommandEvent& event )
499 {
500 #ifdef KICAD_SPICE
501  int diff = m_fields->size();
502 
503  DIALOG_SPICE_MODEL dialog( this, *m_comp, m_fields );
504 
505  if( dialog.ShowModal() != wxID_OK )
506  return;
507 
508  diff = (int) m_fields->size() - diff;
509 
510  if( diff > 0 )
511  {
512  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, diff );
513  m_fieldsGrid->ProcessTableMessage( msg );
514  }
515  else if( diff < 0 )
516  {
517  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, -diff );
518  m_fieldsGrid->ProcessTableMessage( msg );
519  }
520 
521  m_fieldsGrid->ForceRefresh();
522 #endif /* KICAD_SPICE */
523 }
524 
525 
527 {
528  // Running the Footprint Browser gums up the works and causes the automatic cancel
529  // stuff to no longer work. So we do it here ourselves.
530  EndQuasiModal( wxID_CANCEL );
531 }
532 
533 
535 {
536  wxString msg;
537  LIB_ID id;
538 
539  if( !m_fieldsGrid->CommitPendingChanges() || !m_fieldsGrid->Validate() )
540  return false;
541 
543  {
544  DisplayErrorMessage( this, _( "References must start with a letter." ) );
545 
548  m_delayedSelection = false;
549 
550  return false;
551  }
552 
553  // Check for missing field names.
554  for( size_t i = MANDATORY_FIELDS; i < m_fields->size(); ++i )
555  {
556  SCH_FIELD& field = m_fields->at( i );
557  wxString fieldName = field.GetName( false );
558 
559  if( fieldName.IsEmpty() )
560  {
561  DisplayErrorMessage( this, _( "Fields must have a name." ) );
562 
564  m_delayedFocusRow = i;
565  m_delayedSelection = false;
566 
567  return false;
568  }
569  }
570 
571  return true;
572 }
573 
574 
576 {
577  if( !wxDialog::TransferDataFromWindow() ) // Calls our Validate() method.
578  return false;
579 
581  return false;
582 
584  return false;
585 
586  SCH_SCREEN* currentScreen = GetParent()->GetScreen();
587  SCHEMATIC& schematic = GetParent()->Schematic();
588 
589  wxCHECK( currentScreen, false );
590 
591  // This needs to be done before the LIB_ID is changed to prevent stale library symbols in
592  // the schematic file.
593  currentScreen->Remove( m_comp );
594 
595  wxString msg;
596 
597  // save old cmp in undo list if not already in edit, or moving ...
598  if( m_comp->GetEditFlags() == 0 )
599  GetParent()->SaveCopyInUndoList( currentScreen, m_comp, UNDO_REDO::CHANGED, false );
600 
601  // Save current flags which could be modified by next change settings
602  STATUS_FLAGS flags = m_comp->GetFlags();
603 
604  // For symbols with multiple shapes (De Morgan representation) Set the selected shape:
605  if( m_cbAlternateSymbol->IsEnabled() && m_cbAlternateSymbol->GetValue() )
606  m_comp->SetConvert( LIB_ITEM::LIB_CONVERT::DEMORGAN );
607  else
608  m_comp->SetConvert( LIB_ITEM::LIB_CONVERT::BASE );
609 
610  //Set the part selection in multiple part per package
611  int unit_selection = m_unitChoice->IsEnabled() ? m_unitChoice->GetSelection() + 1 : 1;
612  m_comp->SetUnitSelection( &GetParent()->GetCurrentSheet(), unit_selection );
613  m_comp->SetUnit( unit_selection );
614 
615  switch( m_orientationCtrl->GetSelection() )
616  {
617  case 0: m_comp->SetOrientation( CMP_ORIENT_0 ); break;
618  case 1: m_comp->SetOrientation( CMP_ORIENT_90 ); break;
619  case 2: m_comp->SetOrientation( CMP_ORIENT_270 ); break;
620  case 3: m_comp->SetOrientation( CMP_ORIENT_180 ); break;
621  }
622 
623  switch( m_mirrorCtrl->GetSelection() )
624  {
625  case 0: break;
626  case 1: m_comp->SetOrientation( CMP_MIRROR_X ); break;
627  case 2: m_comp->SetOrientation( CMP_MIRROR_Y ); break;
628  }
629 
630  m_part->SetShowPinNames( m_ShowPinNameButt->GetValue() );
631  m_part->SetShowPinNumbers( m_ShowPinNumButt->GetValue() );
632 
633  // Restore m_Flag modified by SetUnit() and other change settings
634  m_comp->ClearFlags();
635  m_comp->SetFlags( flags );
636 
637  // change all field positions from relative to absolute
638  for( unsigned i = 0; i < m_fields->size(); ++i )
639  m_fields->at( i ).Offset( m_comp->GetPosition() );
640 
641  LIB_PART* entry = GetParent()->GetLibPart( m_comp->GetLibId() );
642 
643  if( entry && entry->IsPower() )
644  m_fields->at( VALUE_FIELD ).SetText( m_comp->GetLibId().GetLibItemName() );
645 
646  // Push all fields to the component -except- for those which are TEMPLATE_FIELDNAMES
647  // with empty values.
648  SCH_FIELDS& fields = m_comp->GetFields();
649 
650  fields.clear();
651 
652  for( size_t i = 0; i < m_fields->size(); ++i )
653  {
654  SCH_FIELD& field = m_fields->at( i );
655  bool emptyTemplateField = false;
656 
657  if( i >= MANDATORY_FIELDS )
658  {
659  for( const TEMPLATE_FIELDNAME& fieldname :
661  {
662  if( field.GetName() == fieldname.m_Name && field.GetText().IsEmpty() )
663  {
664  emptyTemplateField = true;
665  break;
666  }
667  }
668  }
669 
670  if( !emptyTemplateField )
671  fields.push_back( field );
672  }
673 
674  // Reference has a specific initialization, depending on the current active sheet
675  // because for a given component, in a complex hierarchy, there are more than one
676  // reference.
677  m_comp->SetRef( &GetParent()->GetCurrentSheet(), m_fields->at( REFERENCE_FIELD ).GetText() );
678 
679  // Similar for Value and Footprint, except that the GUI behaviour is that they are kept
680  // in sync between multiple instances.
681  m_comp->SetValue( m_fields->at( VALUE_FIELD ).GetText() );
682  m_comp->SetFootprint( m_fields->at( FOOTPRINT_FIELD ).GetText() );
683 
684  m_comp->SetIncludeInBom( !m_cbExcludeFromBom->IsChecked() );
686 
687  // The value, footprint and datasheet fields and exclude from bill of materials setting
688  // should be kept in sync in multi-unit parts.
689  if( m_comp->GetUnitCount() > 1 && m_comp->IsAnnotated( &GetParent()->GetCurrentSheet() ) )
690  {
691  wxString ref = m_comp->GetRef( &GetParent()->GetCurrentSheet() );
692  int unit = m_comp->GetUnit();
693 
694  for( SCH_SHEET_PATH& sheet : GetParent()->Schematic().GetSheets() )
695  {
696  SCH_SCREEN* screen = sheet.LastScreen();
697  std::vector<SCH_COMPONENT*> otherUnits;
698  constexpr bool appendUndo = true;
699 
700  CollectOtherUnits( ref, unit, sheet, &otherUnits );
701 
702  for( SCH_COMPONENT* otherUnit : otherUnits )
703  {
704  GetParent()->SaveCopyInUndoList( screen, otherUnit, UNDO_REDO::CHANGED,
705  appendUndo );
706  otherUnit->SetValue( m_fields->at( VALUE_FIELD ).GetText() );
707  otherUnit->SetFootprint( m_fields->at( FOOTPRINT_FIELD ).GetText() );
708  otherUnit->GetField( DATASHEET_FIELD )->SetText( m_fields->at( DATASHEET_FIELD ).GetText() );
709  otherUnit->SetIncludeInBom( !m_cbExcludeFromBom->IsChecked() );
710  otherUnit->SetIncludeOnBoard( !m_cbExcludeFromBoard->IsChecked() );
711  GetParent()->UpdateItem( otherUnit );
712  }
713  }
714  }
715 
716  // Update any assignments
717  if( m_dataModel )
718  {
719  for( const SCH_PIN& model_pin : *m_dataModel )
720  {
721  // map from the edited copy back to the "real" pin in the component
722  SCH_PIN* src_pin = m_comp->GetPin( model_pin.GetLibPin() );
723  src_pin->SetAlt( model_pin.GetAlt() );
724  }
725  }
726 
727  currentScreen->Append( m_comp );
730  GetParent()->OnModify();
731 
732  // This must go after OnModify() so that the connectivity graph will have been updated.
734 
735  return true;
736 }
737 
738 
740 {
741  wxGridCellEditor* editor = m_fieldsGrid->GetCellEditor( event.GetRow(), event.GetCol() );
742  wxControl* control = editor->GetControl();
743 
744  if( control && control->GetValidator() && !control->GetValidator()->Validate( control ) )
745  {
746  event.Veto();
747  m_delayedFocusRow = event.GetRow();
748  m_delayedFocusColumn = event.GetCol();
749  m_delayedSelection = false;
750  }
751  else if( event.GetCol() == FDC_NAME )
752  {
753  wxString newName = event.GetString();
754 
755  for( int i = 0; i < m_fieldsGrid->GetNumberRows(); ++i )
756  {
757  if( i == event.GetRow() )
758  continue;
759 
760  if( newName.CmpNoCase( m_fieldsGrid->GetCellValue( i, FDC_NAME ) ) == 0 )
761  {
762  DisplayError( this, wxString::Format( _( "The name '%s' is already in use." ),
763  newName ) );
764  event.Veto();
765  m_delayedFocusRow = event.GetRow();
766  m_delayedFocusColumn = event.GetCol();
767  m_delayedSelection = false;
768  }
769  }
770  }
771 
772  editor->DecRef();
773 }
774 
775 
777 {
778  if( aEvent.GetRow() == REFERENCE_FIELD && aEvent.GetCol() == FDC_VALUE )
779  m_delayedSelection= true;
780 }
781 
782 
783 void DIALOG_SYMBOL_PROPERTIES::OnAddField( wxCommandEvent& event )
784 {
786  return;
787 
788  SCHEMATIC_SETTINGS& settings = m_comp->Schematic()->Settings();
789  int fieldID = m_fields->size();
790  SCH_FIELD newField( wxPoint( 0, 0 ), fieldID, m_comp,
792 
793  newField.SetTextAngle( m_fields->at( REFERENCE_FIELD ).GetTextAngle() );
794  newField.SetTextSize( wxSize( settings.m_DefaultTextSize, settings.m_DefaultTextSize ) );
795 
796  m_fields->push_back( newField );
797 
798  // notify the grid
799  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
800  m_fieldsGrid->ProcessTableMessage( msg );
801 
802  m_fieldsGrid->MakeCellVisible( (int) m_fields->size() - 1, 0 );
803  m_fieldsGrid->SetGridCursor( (int) m_fields->size() - 1, 0 );
804 
805  m_fieldsGrid->EnableCellEditControl();
806  m_fieldsGrid->ShowCellEditControl();
807 }
808 
809 
810 void DIALOG_SYMBOL_PROPERTIES::OnDeleteField( wxCommandEvent& event )
811 {
812  int curRow = m_fieldsGrid->GetGridCursorRow();
813 
814  if( curRow < 0 )
815  {
816  return;
817  }
818  else if( curRow < MANDATORY_FIELDS )
819  {
820  DisplayError( this, wxString::Format( _( "The first %d fields are mandatory." ),
821  MANDATORY_FIELDS ) );
822  return;
823  }
824 
825  m_fieldsGrid->CommitPendingChanges( true /* quiet mode */ );
826 
827  m_fields->erase( m_fields->begin() + curRow );
828 
829  // notify the grid
830  wxGridTableMessage msg( m_fields, wxGRIDTABLE_NOTIFY_ROWS_DELETED, curRow, 1 );
831  m_fieldsGrid->ProcessTableMessage( msg );
832 
833  if( m_fieldsGrid->GetNumberRows() > 0 )
834  {
835  m_fieldsGrid->MakeCellVisible( std::max( 0, curRow-1 ), m_fieldsGrid->GetGridCursorCol() );
836  m_fieldsGrid->SetGridCursor( std::max( 0, curRow-1 ), m_fieldsGrid->GetGridCursorCol() );
837  }
838 }
839 
840 
841 void DIALOG_SYMBOL_PROPERTIES::OnMoveUp( wxCommandEvent& event )
842 {
844  return;
845 
846  int i = m_fieldsGrid->GetGridCursorRow();
847 
848  if( i > MANDATORY_FIELDS )
849  {
850  SCH_FIELD tmp = m_fields->at( (unsigned) i );
851  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
852  m_fields->insert( m_fields->begin() + i - 1, tmp );
853  m_fieldsGrid->ForceRefresh();
854 
855  m_fieldsGrid->SetGridCursor( i - 1, m_fieldsGrid->GetGridCursorCol() );
856  m_fieldsGrid->MakeCellVisible( m_fieldsGrid->GetGridCursorRow(), m_fieldsGrid->GetGridCursorCol() );
857  }
858  else
859  {
860  wxBell();
861  }
862 }
863 
864 
865 void DIALOG_SYMBOL_PROPERTIES::OnMoveDown( wxCommandEvent& event )
866 {
868  return;
869 
870  int i = m_fieldsGrid->GetGridCursorRow();
871 
872  if( i >= MANDATORY_FIELDS && i < m_fieldsGrid->GetNumberRows() - 1 )
873  {
874  SCH_FIELD tmp = m_fields->at( (unsigned) i );
875  m_fields->erase( m_fields->begin() + i, m_fields->begin() + i + 1 );
876  m_fields->insert( m_fields->begin() + i + 1, tmp );
877  m_fieldsGrid->ForceRefresh();
878 
879  m_fieldsGrid->SetGridCursor( i + 1, m_fieldsGrid->GetGridCursorCol() );
880  m_fieldsGrid->MakeCellVisible( m_fieldsGrid->GetGridCursorRow(), m_fieldsGrid->GetGridCursorCol() );
881  }
882  else
883  {
884  wxBell();
885  }
886 }
887 
888 
890 {
892 }
893 
894 
896 {
898 }
899 
900 
902 {
904 }
905 
906 
908 {
910 }
911 
912 
914 {
915  int row = aEvent.GetRow();
916 
917  if( m_pinGrid->GetCellValue( row, COL_ALT_NAME ) == m_dataModel->GetValue( row, COL_BASE_NAME ) )
918  m_dataModel->SetValue( row, COL_ALT_NAME, wxEmptyString );
919 
920  // These are just to get the cells refreshed
923 
924  m_modified = true;
925 }
926 
927 
929 {
930  int sortCol = aEvent.GetCol();
931  bool ascending;
932 
933  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
934  // event, and if we ask it will give us pre-event info.
935  if( m_pinGrid->IsSortingBy( sortCol ) )
936  // same column; invert ascending
937  ascending = !m_pinGrid->IsSortOrderAscending();
938  else
939  // different column; start with ascending
940  ascending = true;
941 
942  m_dataModel->SortRows( sortCol, ascending );
943 }
944 
945 
947 {
948  wxGridUpdateLocker deferRepaintsTillLeavingScope;
949 
950  m_width = aWidth;
951 
952  // Account for scroll bars
953  int fieldsWidth = aWidth - ( m_fieldsGrid->GetSize().x - m_fieldsGrid->GetClientSize().x );
954  int pinTblWidth = aWidth - ( m_pinGrid->GetSize().x - m_pinGrid->GetClientSize().x );
955 
956  m_fieldsGrid->AutoSizeColumn( 0 );
957 
958  int fixedColsWidth = m_fieldsGrid->GetColSize( 0 );
959 
960  for( int i = 2; i < m_fieldsGrid->GetNumberCols(); i++ )
961  fixedColsWidth += m_fieldsGrid->GetColSize( i );
962 
963  m_fieldsGrid->SetColSize( 1, fieldsWidth - fixedColsWidth );
964 
965  // Stretch the Base Name and Alternate Assignment columns to fit.
966  for( int i = 0; i < COL_COUNT; ++i )
967  {
968  if( i != COL_BASE_NAME && i != COL_ALT_NAME )
969  pinTblWidth -= m_pinGrid->GetColSize( i );
970  }
971 
972  // Why? I haven't a clue....
973  pinTblWidth += 22;
974 
975  m_pinGrid->SetColSize( COL_BASE_NAME, pinTblWidth / 2 );
976  m_pinGrid->SetColSize( COL_ALT_NAME, pinTblWidth / 2 );
977 }
978 
979 
980 void DIALOG_SYMBOL_PROPERTIES::OnUpdateUI( wxUpdateUIEvent& event )
981 {
982  wxString shownColumns = m_fieldsGrid->GetShownColumns();
983 
984  if( shownColumns != m_shownColumns )
985  {
986  m_shownColumns = shownColumns;
987 
988  if( !m_fieldsGrid->IsCellEditControlShown() )
989  AdjustGridColumns( m_fieldsGrid->GetRect().GetWidth() );
990  }
991 
992  // Handle a delayed focus
993  if( m_delayedFocusRow >= 0 )
994  {
995  m_fieldsGrid->SetFocus();
998 
999  m_fieldsGrid->EnableCellEditControl( true );
1000  m_fieldsGrid->ShowCellEditControl();
1001 
1002  m_delayedFocusRow = -1;
1003  m_delayedFocusColumn = -1;
1004  }
1005 
1006  // Handle a delayed selection
1007  if( m_delayedSelection )
1008  {
1009  wxGridCellEditor* cellEditor = m_fieldsGrid->GetCellEditor( REFERENCE_FIELD, FDC_VALUE );
1010 
1011  if( wxTextEntry* txt = dynamic_cast<wxTextEntry*>( cellEditor->GetControl() ) )
1013 
1014  cellEditor->DecRef(); // we're done; must release
1015 
1016  m_delayedSelection = false;
1017  }
1018 }
1019 
1020 
1021 void DIALOG_SYMBOL_PROPERTIES::OnSizeGrid( wxSizeEvent& event )
1022 {
1023  auto new_size = event.GetSize().GetX();
1024 
1025  if( m_width != new_size )
1026  {
1027  AdjustGridColumns( new_size );
1028  }
1029 
1030  // Always propagate for a grid repaint (needed if the height changes, as well as width)
1031  event.Skip();
1032 }
1033 
1034 
1035 void DIALOG_SYMBOL_PROPERTIES::OnInitDlg( wxInitDialogEvent& event )
1036 {
1038 
1039  // Now all widgets have the size fixed, call FinishDialogSettings
1041 }
DIALOG_SYMBOL_PROPERTIES(SCH_EDIT_FRAME *aParent, SCH_COMPONENT *aComponent)
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:240
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:34
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:51
void SelectReferenceNumber(wxTextEntry *aTextEntry)
Select the number (or "?") in a reference for ease of editing.
Definition: ui_common.cpp:102
void Offset(const wxPoint &aOffset)
Definition: eda_text.h:259
wxString GetValue(int aRow, int aCol) override
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:69
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:241
void UpdateItem(EDA_ITEM *aItem, bool isAddOrDelete=false)
Mark an item for refresh.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:409
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:253
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:44
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
Class DIALOG_SYMBOL_PROPERTIES_BASE.
void CollectOtherUnits(const wxString &aRef, int aUnit, SCH_SHEET_PATH &aSheet, std::vector< SCH_COMPONENT * > *otherUnits)
const std::vector< BITMAP_DEF > & PinTypeIcons()
Definition: pin_type.cpp:195
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:125
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
TEMPLATES m_TemplateFieldNames
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:97
wxString GetAlt() const
Definition: sch_pin.h:74
int GetUnitCount() const
Return the number of units per package of the symbol.
void SetVisible(bool aVisible)
Definition: eda_text.h:191
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:52
SCH_PIN * GetPin(const wxString &number)
Find a symbol pin by number.
void OnGridEditorShown(wxGridEvent &event) override
Schematic editor (Eeschema) main window.
wxString GetNumber() const
Definition: sch_pin.h:116
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:244
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
void OnEditSpiceModel(wxCommandEvent &event) override
static const TOOL_EVENT SelectedItemsModified
Definition: actions.h:213
bool IsDragging() const
Definition: eda_item.h:189
name of datasheet
void OnAddField(wxCommandEvent &event) override
const std::vector< BITMAP_DEF > & PinShapeIcons()
Definition: pin_type.cpp:213
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populates a std::vector with SCH_FIELDs.
Field Value of part, i.e. "3.3K".
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:82
int GetUnit() const
bool ShowPinNumbers()
const wxArrayString & PinShapeNames()
Definition: pin_type.cpp:204
bool IsEmptyCell(int row, int col) override
void SetFlags(STATUS_FLAGS aMask)
Definition: eda_item.h:220
void OnGridCellChanging(wxGridEvent &event)
void OnMoveUp(wxCommandEvent &event) override
STATUS_FLAGS GetEditFlags() const
Definition: eda_item.h:225
void OnPinTableColSort(wxGridEvent &aEvent)
const wxString & GetName() const
Definition: lib_pin.h:156
void OnSizeGrid(wxSizeEvent &event) override
std::vector< SCH_FIELD > SCH_FIELDS
A container for several SCH_FIELD items.
Definition: sch_component.h:64
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
void OnEditSymbol(wxCommandEvent &) override
const BITMAP_OPAQUE small_down_xpm[1]
Definition: small_down.cpp:24
SCHEMATIC & Schematic() const
Define a library symbol object.
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.
unsigned STATUS_FLAGS
Definition: eda_item.h:142
const wxArrayString & PinTypeNames()
Definition: pin_type.cpp:186
static wxString GetValue(const SCH_PIN &aPin, int aCol)
void OnInitDlg(wxInitDialogEvent &event) override
bool IsAnnotated(const SCH_SHEET_PATH *aSheet)
Checks if the component has a valid annotation (reference) for the given sheet path.
GRAPHIC_PINSHAPE GetShape() const
Definition: sch_pin.cpp:97
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslate=true)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
void SetUnit(int aUnit)
Change the unit number to aUnit.
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
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
void OnPinTableCellEdited(wxGridEvent &event) override
const BITMAP_OPAQUE small_up_xpm[1]
Definition: small_up.cpp:25
int GetFieldCount() const
Return the number of fields in this symbol.
UTF8 Format() const
Definition: lib_id.cpp:237
Field Name Module PCB, i.e. "16DIP300".
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
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
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
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 OnDeleteField(wxCommandEvent &event) override
void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
void Append(SCH_ITEM *aItem)
Definition: sch_screen.cpp:129
SCH_PIN_TABLE_DATA_MODEL * m_dataModel
#define _(s)
Definition: 3d_actions.cpp:33
ELECTRICAL_PINTYPE GetType() const
Definition: sch_pin.cpp:88
void SetAlt(const wxString &aAlt)
Definition: sch_pin.h:75
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:507
void OnMoveDown(wxCommandEvent &event) override
static wxString SubReference(int aUnit, bool aAddSeparator=true)
std::vector< wxGridCellAttr * > m_nameAttrs
Schematic symbol object.
Definition: sch_component.h:79
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: eda_item.h:221
static bool compare(const SCH_PIN &lhs, const SCH_PIN &rhs, int sortCol, bool ascending)
void OnExchangeSymbol(wxCommandEvent &) override
int GetConvert() const
void OnEditLibrarySymbol(wxCommandEvent &) override
void OnCancelButtonClick(wxCommandEvent &event) override
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:76
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag of the current screen and u...
FIELDS_GRID_TABLE< SCH_FIELD > * m_fields
virtual void SetTextAngle(double aAngle)
Definition: eda_text.h:173
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 OnUpdateUI(wxUpdateUIEvent &event) override
void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
STATUS_FLAGS GetFlags() const
Definition: eda_item.h:222
const LIB_ID & GetLibId() const
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind) override
Field Reference of part, i.e. "IC21".
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:274
void OnUpdateSymbol(wxCommandEvent &) override
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
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.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const
Return the reference for the given sheet path.
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...