KiCad PCB EDA Suite
dialog_fields_editor_global.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) 2017 Oliver Walters
5  * Copyright (C) 2017-2020 KiCad Developers, see AUTHORS.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 
25 
26 #include <base_units.h>
27 #include <bitmaps.h>
28 #include <class_library.h>
29 #include <confirm.h>
30 #include <eda_doc.h>
31 #include <eeschema_settings.h>
32 #include <general.h>
33 #include <grid_tricks.h>
34 #include <kicad_string.h>
35 #include <kiface_i.h>
36 #include <refdes_utils.h>
37 #include <sch_edit_frame.h>
38 #include <sch_reference_list.h>
39 #include <schematic.h>
42 #include <widgets/wx_grid.h>
43 #include <wx/grid.h>
44 #include <wx/msgdlg.h>
45 
47 
48 
49 enum
50 {
51  MYID_SELECT_FOOTPRINT = 991, // must be within GRID_TRICKS' enum range
53 };
54 
55 
57 {
58 public:
60  wxDataViewListCtrl* aFieldsCtrl ) :
61  GRID_TRICKS( aGrid ),
62  m_dlg( aParent ),
63  m_fieldsCtrl( aFieldsCtrl )
64  {}
65 
66 protected:
67  void showPopupMenu( wxMenu& menu ) override
68  {
69  if( m_grid->GetGridCursorCol() == FOOTPRINT )
70  {
71  menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
72  _( "Browse for footprint" ) );
73  menu.AppendSeparator();
74  }
75  else if( m_grid->GetGridCursorCol() == DATASHEET )
76  {
77  menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
78  _( "Show datasheet in browser" ) );
79  menu.AppendSeparator();
80  }
81 
83  }
84 
85  void doPopupSelection( wxCommandEvent& event ) override
86  {
87  if( event.GetId() == MYID_SELECT_FOOTPRINT )
88  {
89  // pick a footprint using the footprint picker.
90  wxString fpid = m_grid->GetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT );
92 
93  if( frame->ShowModal( &fpid, m_dlg ) )
94  m_grid->SetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT, fpid );
95 
96  frame->Destroy();
97  }
98  else if (event.GetId() == MYID_SHOW_DATASHEET )
99  {
100  wxString datasheet_uri = m_grid->GetCellValue( m_grid->GetGridCursorRow(), DATASHEET );
101  GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj() );
102  }
103  else
104  {
106  }
107 
108  if( event.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE && event.GetId() < GRIDTRICKS_LAST_ID )
109  {
110  if( !m_grid->IsColShown( REFERENCE ) )
111  {
112  DisplayError( m_dlg, _( "The Reference column cannot be hidden." ) );
113 
114  m_grid->ShowCol( REFERENCE );
115  }
116 
117  // Refresh Show checkboxes from grid columns
118  for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
119  m_fieldsCtrl->SetToggleValue( m_grid->IsColShown( i ), i, 1 );
120  }
121  }
122 
124  wxDataViewListCtrl* m_fieldsCtrl;
125 };
126 
127 
129 {
135 };
136 
137 
139 {
140  DATA_MODEL_ROW( const SCH_REFERENCE& aFirstReference, GROUP_TYPE aType )
141  {
142  m_Refs.push_back( aFirstReference );
143  m_Flag = aType;
144  }
145 
147  std::vector<SCH_REFERENCE> m_Refs;
148 };
149 
150 
151 #define FIELD_NAME_COLUMN 0
152 #define SHOW_FIELD_COLUMN 1
153 #define GROUP_BY_COLUMN 2
154 
155 #define QUANTITY_COLUMN ( GetNumberCols() - 1 )
156 
157 #ifdef __WXMAC__
158 #define COLUMN_MARGIN 5
159 #else
160 #define COLUMN_MARGIN 15
161 #endif
162 
163 
164 class FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase
165 {
166 protected:
167  // The data model is fundamentally m_componentRefs X m_fieldNames.
168 
171  bool m_edited;
172  std::vector<wxString> m_fieldNames;
175 
176  // However, the grid view can vary in two ways:
177  // 1) the componentRefs can be grouped into fewer rows
178  // 2) some columns can be hidden
179  //
180  // We handle (1) here (ie: a table row maps to a group, and the table is rebuilt
181  // when the groupings change), and we let the wxGrid handle (2) (ie: the number
182  // of columns is constant but are hidden/shown by the wxGrid control).
183 
184  std::vector< DATA_MODEL_ROW > m_rows;
185 
186  // Data store
187  // A map of compID : fieldSet, where fieldSet is a map of fieldName : fieldValue
188  std::map< KIID, std::map<wxString, wxString> > m_dataStore;
189 
190 
191 public:
193  m_frame( aFrame ),
194  m_componentRefs( aComponentList ),
195  m_edited( false ),
196  m_sortColumn( 0 ),
197  m_sortAscending( false )
198  {
200  }
201 
202 
203  void AddColumn( const wxString& aFieldName )
204  {
205  m_fieldNames.push_back( aFieldName );
206 
207  for( unsigned i = 0; i < m_componentRefs.GetCount(); ++i )
208  {
209  SCH_COMPONENT* comp = m_componentRefs[ i ].GetComp();
210  m_dataStore[ comp->m_Uuid ][ aFieldName ] = comp->GetFieldText( aFieldName, m_frame );
211  }
212  }
213 
214 
215  int GetNumberRows() override { return m_rows.size(); }
216 
217  // Columns are fieldNames + quantity column
218  int GetNumberCols() override { return (int) m_fieldNames.size() + 1; }
219 
220 
221  wxString GetColLabelValue( int aCol ) override
222  {
223  if( aCol == QUANTITY_COLUMN )
224  return _( "Qty" );
225  else
226  return m_fieldNames[ aCol ];
227  }
228 
229 
230  bool IsEmptyCell( int aRow, int aCol ) override
231  {
232  return false; // don't allow adjacent cell overflow, even if we are actually empty
233  }
234 
235 
236  wxString GetValue( int aRow, int aCol ) override
237  {
238  if( aCol == REFERENCE )
239  {
240  // Poor-man's tree controls
241  if( m_rows[ aRow ].m_Flag == GROUP_COLLAPSED )
242  return wxT( "> " ) + GetValue( m_rows[ aRow ], aCol );
243  else if (m_rows[ aRow ].m_Flag == GROUP_EXPANDED )
244  return wxT( "v " ) + GetValue( m_rows[ aRow ], aCol );
245  else if( m_rows[ aRow ].m_Flag == CHILD_ITEM )
246  return wxT( " " ) + GetValue( m_rows[ aRow ], aCol );
247  else
248  return wxT( " " ) + GetValue( m_rows[ aRow ], aCol );
249  }
250  else
251  return GetValue( m_rows[ aRow ], aCol );
252  }
253 
254  std::vector<SCH_REFERENCE> GetRowReferences( int aRow )
255  {
256  wxCHECK( aRow < (int)m_rows.size(), std::vector<SCH_REFERENCE>() );
257  return m_rows[ aRow ].m_Refs;
258  }
259 
260  wxString GetValue( DATA_MODEL_ROW& group, int aCol )
261  {
262  std::vector<SCH_REFERENCE> references;
263  wxString fieldValue;
264 
265  for( const auto& ref : group.m_Refs )
266  {
267  if( aCol == REFERENCE || aCol == QUANTITY_COLUMN )
268  {
269  references.push_back( ref );
270  }
271  else // Other columns are either a single value or ROW_MULTI_ITEMS
272  {
273  const KIID& compID = ref.GetComp()->m_Uuid;
274 
275  if( !m_dataStore.count( compID ) ||
276  !m_dataStore[ compID ].count( m_fieldNames[ aCol ] ) )
277  {
278  return INDETERMINATE_STATE;
279  }
280 
281  if( &ref == &group.m_Refs.front() )
282  {
283  fieldValue = m_dataStore[ compID ][ m_fieldNames[ aCol ] ];
284  }
285  else if ( fieldValue != m_dataStore[ compID ][ m_fieldNames[ aCol ] ] )
286  {
287  return INDETERMINATE_STATE;
288  }
289  }
290  }
291 
292  if( aCol == REFERENCE || aCol == QUANTITY_COLUMN )
293  {
294  // Remove duplicates (other units of multi-unit parts)
295  std::sort( references.begin(), references.end(),
296  []( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
297  {
298  wxString l_ref( l.GetRef() << l.GetRefNumber() );
299  wxString r_ref( r.GetRef() << r.GetRefNumber() );
300  return UTIL::RefDesStringCompare( l_ref, r_ref ) < 0;
301  } );
302 
303  auto logicalEnd = std::unique( references.begin(), references.end(),
304  []( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
305  {
306  // If unannotated then we can't tell what units belong together
307  // so we have to leave them all
308  if( l.GetRefNumber() == wxT( "?" ) )
309  return false;
310 
311  wxString l_ref( l.GetRef() << l.GetRefNumber() );
312  wxString r_ref( r.GetRef() << r.GetRefNumber() );
313  return l_ref == r_ref;
314  } );
315  references.erase( logicalEnd, references.end() );
316  }
317 
318  if( aCol == REFERENCE )
319  {
320  fieldValue = SCH_REFERENCE_LIST::Shorthand( references );
321  }
322  else if( aCol == QUANTITY_COLUMN )
323  {
324  fieldValue = wxString::Format( wxT( "%d" ), ( int )references.size() );
325  }
326 
327  return fieldValue;
328  }
329 
330 
331  void SetValue( int aRow, int aCol, const wxString &aValue ) override
332  {
333  if( aCol == REFERENCE || aCol == QUANTITY_COLUMN )
334  return; // Can't modify references or quantity
335 
336  DATA_MODEL_ROW& rowGroup = m_rows[ aRow ];
337  wxString fieldName = m_fieldNames[ aCol ];
338 
339  for( const auto& ref : rowGroup.m_Refs )
340  m_dataStore[ ref.GetComp()->m_Uuid ][ fieldName ] = aValue;
341 
342  m_edited = true;
343  }
344 
345 
346  static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup,
347  FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending )
348  {
349  // Empty rows always go to the bottom, whether ascending or descending
350  if( lhGroup.m_Refs.size() == 0 )
351  return true;
352  else if( rhGroup.m_Refs.size() == 0 )
353  return false;
354 
355  // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
356  // to get the opposite sort. i.e. ~(a<b) != (a>b)
357  auto local_cmp = [ ascending ]( const auto a, const auto b )
358  {
359  if( ascending )
360  return a < b;
361  else
362  return a > b;
363  };
364 
365  // Primary sort key is sortCol; secondary is always REFERENCE (column 0)
366 
367  wxString lhs = dataModel->GetValue( (DATA_MODEL_ROW&) lhGroup, sortCol );
368  wxString rhs = dataModel->GetValue( (DATA_MODEL_ROW&) rhGroup, sortCol );
369 
370  if( lhs == rhs || sortCol == REFERENCE )
371  {
372  wxString lhRef = lhGroup.m_Refs[ 0 ].GetRef() + lhGroup.m_Refs[ 0 ].GetRefNumber();
373  wxString rhRef = rhGroup.m_Refs[ 0 ].GetRef() + rhGroup.m_Refs[ 0 ].GetRefNumber();
374  return local_cmp( UTIL::RefDesStringCompare( lhRef, rhRef ), 0 );
375  }
376  else
377  return local_cmp( ValueStringCompare( lhs, rhs ), 0 );
378  }
379 
380 
381  void Sort( int aColumn, bool ascending )
382  {
383  if( aColumn < 0 )
384  aColumn = 0;
385 
386  m_sortColumn = aColumn;
387  m_sortAscending = ascending;
388 
389  CollapseForSort();
390 
391  std::sort( m_rows.begin(), m_rows.end(),
392  [ this ]( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
393  {
394  return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
395  } );
396 
397  ExpandAfterSort();
398  }
399 
400 
401  bool unitMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef )
402  {
403  // If items are unannotated then we can't tell if they're units of the same
404  // component or not
405  if( lhRef.GetRefNumber() == wxT( "?" ) )
406  return false;
407 
408  return ( lhRef.GetRef() == rhRef.GetRef() && lhRef.GetRefNumber() == rhRef.GetRefNumber() );
409  }
410 
411 
412  bool groupMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef,
413  wxDataViewListCtrl* fieldsCtrl )
414  {
415  bool matchFound = false;
416 
417  // First check the reference column. This can be done directly out of the
418  // SCH_REFERENCEs as the references can't be edited in the grid.
419  if( fieldsCtrl->GetToggleValue( REFERENCE, GROUP_BY_COLUMN ) )
420  {
421  // if we're grouping by reference, then only the prefix must match
422  if( lhRef.GetRef() != rhRef.GetRef() )
423  return false;
424 
425  matchFound = true;
426  }
427 
428  const KIID& lhRefID = lhRef.GetComp()->m_Uuid;
429  const KIID& rhRefID = rhRef.GetComp()->m_Uuid;
430 
431  // Now check all the other columns. This must be done out of the dataStore
432  // for the refresh button to work after editing.
433  for( int i = REFERENCE + 1; i < fieldsCtrl->GetItemCount(); ++i )
434  {
435  if( !fieldsCtrl->GetToggleValue( i, GROUP_BY_COLUMN ) )
436  continue;
437 
438  wxString fieldName = fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN );
439 
440  if( m_dataStore[ lhRefID ][ fieldName ] != m_dataStore[ rhRefID ][ fieldName ] )
441  return false;
442 
443  matchFound = true;
444  }
445 
446  return matchFound;
447  }
448 
449 
450  void RebuildRows( wxCheckBox* groupComponentsBox, wxDataViewListCtrl* fieldsCtrl )
451  {
452  if ( GetView() )
453  {
454  // Commit any pending in-place edits before the row gets moved out from under
455  // the editor.
456  static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
457 
458  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
459  GetView()->ProcessTableMessage( msg );
460  }
461 
462  m_rows.clear();
463 
464  for( unsigned i = 0; i < m_componentRefs.GetCount(); ++i )
465  {
466  SCH_REFERENCE ref = m_componentRefs[ i ];
467  bool matchFound = false;
468 
469  // See if we already have a row which this component fits into
470  for( auto& row : m_rows )
471  {
472  // all group members must have identical refs so just use the first one
473  SCH_REFERENCE rowRef = row.m_Refs[ 0 ];
474 
475  if( unitMatch( ref, rowRef ) )
476  {
477  matchFound = true;
478  row.m_Refs.push_back( ref );
479  break;
480  }
481  else if (groupComponentsBox->GetValue() && groupMatch( ref, rowRef, fieldsCtrl ) )
482  {
483  matchFound = true;
484  row.m_Refs.push_back( ref );
485  row.m_Flag = GROUP_COLLAPSED;
486  break;
487  }
488  }
489 
490  if( !matchFound )
491  m_rows.emplace_back( DATA_MODEL_ROW( ref, GROUP_SINGLETON ) );
492  }
493 
494  if ( GetView() )
495  {
496  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
497  GetView()->ProcessTableMessage( msg );
498  }
499  }
500 
501 
502  void ExpandRow( int aRow )
503  {
504  std::vector<DATA_MODEL_ROW> children;
505 
506  for( auto& ref : m_rows[ aRow ].m_Refs )
507  {
508  bool matchFound = false;
509 
510  // See if we already have a child group which this component fits into
511  for( auto& child : children )
512  {
513  // group members are by definition all matching, so just check
514  // against the first member
515  if( unitMatch( ref, child.m_Refs[ 0 ] ) )
516  {
517  matchFound = true;
518  child.m_Refs.push_back( ref );
519  break;
520  }
521  }
522 
523  if( !matchFound )
524  children.emplace_back( DATA_MODEL_ROW( ref, CHILD_ITEM ) );
525  }
526 
527  if( children.size() < 2 )
528  return;
529 
530  std::sort( children.begin(), children.end(),
531  [ this ] ( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
532  {
533  return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
534  } );
535 
536  m_rows[ aRow ].m_Flag = GROUP_EXPANDED;
537  m_rows.insert( m_rows.begin() + aRow + 1, children.begin(), children.end() );
538 
539  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, children.size() );
540  GetView()->ProcessTableMessage( msg );
541  }
542 
543 
544  void CollapseRow( int aRow )
545  {
546  auto firstChild = m_rows.begin() + aRow + 1;
547  auto afterLastChild = firstChild;
548  int deleted = 0;
549 
550  while( afterLastChild != m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
551  {
552  deleted++;
553  afterLastChild++;
554  }
555 
556  m_rows[ aRow ].m_Flag = GROUP_COLLAPSED;
557  m_rows.erase( firstChild, afterLastChild );
558 
559  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
560  GetView()->ProcessTableMessage( msg );
561  }
562 
563 
564  void ExpandCollapseRow( int aRow )
565  {
566  DATA_MODEL_ROW& group = m_rows[ aRow ];
567 
568  if( group.m_Flag == GROUP_COLLAPSED )
569  ExpandRow( aRow );
570  else if( group.m_Flag == GROUP_EXPANDED )
571  CollapseRow( aRow );
572  }
573 
574 
576  {
577  for( size_t i = 0; i < m_rows.size(); ++i )
578  {
579  if( m_rows[ i ].m_Flag == GROUP_EXPANDED )
580  {
581  CollapseRow( i );
582  m_rows[ i ].m_Flag = GROUP_COLLAPSED_DURING_SORT;
583  }
584  }
585  }
586 
587 
589  {
590  for( size_t i = 0; i < m_rows.size(); ++i )
591  {
592  if( m_rows[ i ].m_Flag == GROUP_COLLAPSED_DURING_SORT )
593  ExpandRow( i );
594  }
595  }
596 
597 
598  void ApplyData()
599  {
600  for( unsigned i = 0; i < m_componentRefs.GetCount(); ++i )
601  {
602  SCH_COMPONENT& comp = *m_componentRefs[i].GetComp();
603  SCH_SCREEN* screen = m_componentRefs[i].GetSheetPath().LastScreen();
604 
605  m_frame->SaveCopyInUndoList( screen, &comp, UNDO_REDO::CHANGED, true );
606 
607  const std::map<wxString, wxString>& fieldStore = m_dataStore[comp.m_Uuid];
608 
609  for( const std::pair<wxString, wxString> srcData : fieldStore )
610  {
611  const wxString& srcName = srcData.first;
612  const wxString& srcValue = srcData.second;
613  SCH_FIELD* destField = comp.FindField( srcName );
614 
615  if( !destField && !srcValue.IsEmpty() )
616  {
617  const auto compOrigin = comp.GetPosition();
618  destField = comp.AddField( SCH_FIELD( compOrigin, -1, &comp, srcName ) );
619  }
620 
621  if( !destField )
622  {
623  comp.RemoveField( srcName );
624  }
625  else if( destField->GetId() == REFERENCE )
626  {
627  // Reference is not editable
628  }
629  else if( destField->GetId() == VALUE )
630  {
631  // Value field cannot be empty
632  if( !srcValue.IsEmpty() )
633  comp.SetValue( srcValue );
634  }
635  else if( destField->GetId() == FOOTPRINT )
636  {
637  comp.SetFootprint( srcValue );
638  }
639  else
640  {
641  destField->SetText( srcValue );
642  }
643  }
644  }
645 
646  m_edited = false;
647  }
648 
649 
650  int GetDataWidth( int aCol )
651  {
652  int width = 0;
653 
654  if( aCol == REFERENCE )
655  {
656  for( int row = 0; row < GetNumberRows(); ++row )
657  {
658  width = std::max( width, GetTextSize( GetValue( row, aCol ), GetView() ).x );
659  }
660  }
661  else
662  {
663  wxString column_label = GetColLabelValue( aCol ); // component fieldName or Qty string
664 
665  for( unsigned compRef = 0; compRef < m_componentRefs.GetCount(); ++ compRef )
666  {
667  const KIID& compId = m_componentRefs[ compRef ].GetComp()->m_Uuid;
668  wxString text = m_dataStore[ compId ][ column_label ];
669 
670  width = std::max( width, GetTextSize( text, GetView() ).x );
671  }
672  }
673 
674  return width;
675  }
676 
677 
678  bool IsEdited()
679  {
680  return m_edited;
681  }
682 };
683 
684 
687  m_parent( parent )
688 {
689  wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
690 
691  // Get all components from the list of schematic sheets
693 
694  m_bRefresh->SetBitmap( KiBitmap( refresh_xpm ) );
695 
696  m_fieldsCtrl->AppendTextColumn( _( "Field" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
697  m_fieldsCtrl->AppendToggleColumn( _( "Show" ), wxDATAVIEW_CELL_ACTIVATABLE, 0, wxALIGN_CENTER,
698  0 );
699  m_fieldsCtrl->AppendToggleColumn( _( "Group By" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
700  wxALIGN_CENTER, 0 );
701 
702  // SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails here on GTK, so we calculate the title sizes and
703  // set the column widths ourselves.
704  auto column = m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN );
705  m_showColWidth = GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
706  column->SetWidth( m_showColWidth );
707 
708  column = m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN );
709  m_groupByColWidth = GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
710  column->SetWidth( m_groupByColWidth );
711 
712  // The fact that we're a list should keep the control from reserving space for the
713  // expander buttons... but it doesn't. Fix by forcing the indent to 0.
714  m_fieldsCtrl->SetIndent( 0 );
715 
717 
718  LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel
719 
720  // Now that the fields are loaded we can set the initial location of the splitter
721  // based on the list width. Again, SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails us on GTK.
722  int nameColWidth = 0;
723 
724  for( int row = 0; row < m_fieldsCtrl->GetItemCount(); ++row )
725  {
726  const wxString& fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
727  nameColWidth = std::max( nameColWidth, GetTextSize( fieldName, m_fieldsCtrl ).x );
728  }
729 
730  m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetWidth( nameColWidth );
731  m_splitter1->SetSashPosition( nameColWidth + m_showColWidth + m_groupByColWidth + 40 );
732 
734  m_dataModel->Sort( 0, true );
735 
736  // wxGrid's column moving is buggy with native headers and this is one dialog where you'd
737  // really like to be able to rearrange columns.
738  m_grid->UseNativeColHeader( false );
739  m_grid->SetTable( m_dataModel, true );
740 
741  // must be done after SetTable(), which appears to re-set it
742  m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
743 
744  // sync m_grid's column visibilities to Show checkboxes in m_fieldsCtrl
745  for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
746  {
747  if( m_fieldsCtrl->GetToggleValue( i, 1 ) )
748  m_grid->ShowCol( i );
749  else
750  m_grid->HideCol( i );
751  }
752 
753  // add Cut, Copy, and Paste to wxGrid
754  m_grid->PushEventHandler( new FIELDS_EDITOR_GRID_TRICKS( this, m_grid, m_fieldsCtrl ) );
755 
756  // give a bit more room for comboboxes
757  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
758 
759  // set reference column attributes
760  wxGridCellAttr* attr = new wxGridCellAttr;
761  attr->SetReadOnly();
762  m_grid->SetColAttr( REFERENCE, attr );
763 
764  // set footprint column browse button
765  attr = new wxGridCellAttr;
766  attr->SetEditor( new GRID_CELL_FOOTPRINT_ID_EDITOR( this ) );
767  m_grid->SetColAttr( FOOTPRINT, attr );
768 
769  // set datasheet column viewer button
770  attr = new wxGridCellAttr;
771  attr->SetEditor( new GRID_CELL_URL_EDITOR( this ) );
772  m_grid->SetColAttr( DATASHEET, attr );
773 
774  // set quantities column attributes
775  attr = new wxGridCellAttr;
776  attr->SetReadOnly();
777  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
778  m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
779  m_grid->AutoSizeColumns( false );
780 
781  for( int col = 0; col < m_grid->GetNumberCols(); ++col )
782  {
783  // Columns are hidden by setting their width to 0 so if we resize them they will
784  // become unhidden.
785  if( m_grid->IsColShown( col ) )
786  {
787  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
788  std::string key( m_dataModel->GetColLabelValue( col ).ToUTF8() );
789 
790  if( cfg->m_FieldEditorPanel.column_widths.count( key ) )
791  {
792  int width = cfg->m_FieldEditorPanel.column_widths.at( key );
793  m_grid->SetColSize( col, width );
794  }
795  else
796  {
797  int textWidth = m_dataModel->GetDataWidth( col ) + COLUMN_MARGIN;
798  int maxWidth = defaultDlgSize.x / 3;
799 
800  if( col == m_grid->GetNumberCols() - 1 )
801  m_grid->SetColSize( col, std::min( std::max( 50, textWidth ), maxWidth ) );
802  else
803  m_grid->SetColSize( col, std::min( std::max( 100, textWidth ), maxWidth ) );
804  }
805  }
806  }
807 
808  m_grid->SelectRow( 0 );
809  m_grid->SetGridCursor( 0, 1 );
811 
812  m_sdbSizer1OK->SetDefault();
813 
815  SetSize( defaultDlgSize );
816  Center();
817 
818  // Connect Events
819  m_grid->Connect( wxEVT_GRID_COL_SORT,
820  wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this );
821 }
822 
823 
825 {
826  // Disconnect Events
827  m_grid->Disconnect( wxEVT_GRID_COL_SORT,
828  wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this );
829 
830  // Delete the GRID_TRICKS.
831  m_grid->PopEventHandler( true );
832 
833  // we gave ownership of m_dataModel to the wxGrid...
834 }
835 
836 
838 {
839  if( !wxDialog::TransferDataFromWindow() )
840  return false;
841 
842  TOOL_MANAGER* toolMgr = m_parent->GetToolManager();
843  EE_SELECTION_TOOL* selectionTool = toolMgr->GetTool<EE_SELECTION_TOOL>();
844  EE_SELECTION& selection = selectionTool->GetSelection();
845  SCH_COMPONENT* component = nullptr;
846 
847  if( selection.GetSize() == 1 )
848  {
849  EDA_ITEM* item = selection.Front();
850 
851  if( item->Type() == SCH_COMPONENT_T )
852  component = (SCH_COMPONENT*) item;
853  else if( item->GetParent() && item->GetParent()->Type() == SCH_COMPONENT_T )
854  component = (SCH_COMPONENT*) item->GetParent();
855  }
856 
857  if( component )
858  {
859  for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
860  {
861  std::vector<SCH_REFERENCE> references = m_dataModel->GetRowReferences( row );
862  bool found = false;
863 
864  for( const SCH_REFERENCE& ref : references )
865  {
866  if( ref.GetComp() == component )
867  {
868  found = true;
869  break;
870  }
871  }
872 
873  if( found )
874  {
875  m_grid->GoToCell( row, 1 );
876  break;
877  }
878  }
879  }
880 
881  return true;
882 }
883 
884 
886 {
887  if( !m_grid->CommitPendingChanges() )
888  return false;
889 
890  if( !wxDialog::TransferDataFromWindow() )
891  return false;
892 
893  SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet();
894 
896 
897  // Reset the view to where we left the user
898  m_parent->SetCurrentSheet( currentSheet );
899  m_parent->SyncView();
900  m_parent->Refresh();
901 
902  m_parent->OnModify();
903 
904  return true;
905 }
906 
907 
908 void DIALOG_FIELDS_EDITOR_GLOBAL::AddField( const wxString& aName,
909  bool defaultShow, bool defaultSortBy )
910 {
911  m_dataModel->AddColumn( aName );
912 
913  wxVector<wxVariant> fieldsCtrlRow;
914 
915  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
916  bool show = defaultShow;
917  bool sort_by = defaultSortBy;
918 
919  std::string key( aName.ToUTF8() );
920 
921  if( cfg->m_FieldEditorPanel.fields_show.count( key ) )
922  show = cfg->m_FieldEditorPanel.fields_show.at( key );
923 
924  if( cfg->m_FieldEditorPanel.fields_group_by.count( key ) )
925  sort_by = cfg->m_FieldEditorPanel.fields_group_by.at( key );
926 
927  // Don't change these to emplace_back: some versions of wxWidgets don't support it
928  fieldsCtrlRow.push_back( wxVariant( aName ) );
929  fieldsCtrlRow.push_back( wxVariant( show ) );
930  fieldsCtrlRow.push_back( wxVariant( sort_by ) );
931 
932  m_fieldsCtrl->AppendItem( fieldsCtrlRow );
933 }
934 
935 
941 {
942  std::set<wxString> userFieldNames;
943 
944  for( unsigned i = 0; i < m_componentRefs.GetCount(); ++i )
945  {
946  SCH_COMPONENT* comp = m_componentRefs[ i ].GetComp();
947 
948  for( int j = MANDATORY_FIELDS; j < comp->GetFieldCount(); ++j )
949  userFieldNames.insert( comp->GetField( j )->GetName() );
950  }
951 
952  // Force References to always be shown
953  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
954  wxCHECK( cfg, /*void*/ );
955 
956  cfg->m_FieldEditorPanel.fields_show["Reference"] = true;
957 
958  // *DO NOT* use translated mandatory field names:
959  // They are also used as keyword to find fields in component list.
960  // Changing that is not a basic change
961  AddField( "Reference", true, true );
962  AddField( "Value", true, true );
963  AddField( "Footprint", true, true );
964  AddField( "Datasheet", true, false );
965 
966  for( const wxString& fieldName : userFieldNames )
967  AddField( fieldName, true, false );
968 
969  // Add any templateFieldNames which aren't already present in the userFieldNames
970  for( const TEMPLATE_FIELDNAME& templateFieldname :
972  {
973  if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
974  AddField( templateFieldname.m_Name, false, false );
975  }
976 }
977 
978 
979 void DIALOG_FIELDS_EDITOR_GLOBAL::OnAddField( wxCommandEvent& event )
980 {
981  // quantities column will become new field column, so it needs to be reset
982  auto attr = new wxGridCellAttr;
983  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
984  m_grid->SetColFormatCustom( m_dataModel->GetColsCount() - 1, wxGRID_VALUE_STRING );
985 
986  wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Add Field" ) );
987 
988  if( dlg.ShowModal() != wxID_OK )
989  return;
990 
991  wxString fieldName = dlg.GetValue();
992 
993  if( fieldName.IsEmpty() )
994  {
995  DisplayError( this, _( "Field must have a name." ) );
996  return;
997  }
998 
999  for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
1000  {
1001  if( fieldName == m_dataModel->GetColLabelValue( i ) )
1002  {
1003  DisplayError( this, wxString::Format( _( "Field name \"%s\" already in use." ),
1004  fieldName ) );
1005  return;
1006  }
1007  }
1008 
1009  std::string key( fieldName.ToUTF8() );
1010 
1011  auto cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1012  cfg->m_FieldEditorPanel.fields_show[key] = true;
1013 
1014  AddField( fieldName, true, false );
1015 
1016  wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_INSERTED,
1017  m_fieldsCtrl->GetItemCount(), 1 );
1018  m_grid->ProcessTableMessage( msg );
1019 
1020  // set up attributes on the new quantities column
1021  attr = new wxGridCellAttr;
1022  attr->SetReadOnly();
1023  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
1024  m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
1025  m_grid->SetColSize( m_dataModel->GetColsCount() - 1, 50 );
1026 }
1027 
1028 
1030 {
1031  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1032  wxDataViewItem item = event.GetItem();
1033 
1034  int row = m_fieldsCtrl->ItemToRow( item );
1035  int col = event.GetColumn();
1036 
1037  switch ( col )
1038  {
1039  default:
1040  break;
1041 
1042  case SHOW_FIELD_COLUMN:
1043  {
1044  bool value = m_fieldsCtrl->GetToggleValue( row, col );
1045 
1046  if( row == REFERENCE && !value )
1047  {
1048  DisplayError( this, _( "The Reference column cannot be hidden." ) );
1049 
1050  value = true;
1051  m_fieldsCtrl->SetToggleValue( value, row, col );
1052  }
1053 
1054  std::string fieldName( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ).ToUTF8() );
1055  cfg->m_FieldEditorPanel.fields_show[fieldName] = value;
1056 
1057  if( value )
1058  m_grid->ShowCol( row );
1059  else
1060  m_grid->HideCol( row ); // grid's columns map to fieldsCtrl's rows
1061  break;
1062  }
1063 
1064  case GROUP_BY_COLUMN:
1065  {
1066  bool value = m_fieldsCtrl->GetToggleValue( row, col );
1067  std::string fieldName( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ).ToUTF8() );
1068  cfg->m_FieldEditorPanel.fields_group_by[fieldName] = value;
1069 
1071  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1072  m_grid->ForceRefresh();
1073  break;
1074  }
1075  }
1076 }
1077 
1078 
1080 {
1082  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1083  m_grid->ForceRefresh();
1084 }
1085 
1086 
1087 void DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort( wxGridEvent& aEvent )
1088 {
1089  int sortCol = aEvent.GetCol();
1090  bool ascending;
1091 
1092  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
1093  // event, and if we ask it will give us pre-event info.
1094  if( m_grid->IsSortingBy( sortCol ) )
1095  // same column; invert ascending
1096  ascending = !m_grid->IsSortOrderAscending();
1097  else
1098  // different column; start with ascending
1099  ascending = true;
1100 
1101  m_dataModel->Sort( sortCol, ascending );
1102  m_grid->ForceRefresh();
1103 }
1104 
1105 
1107 {
1108  m_grid->ForceRefresh();
1109 }
1110 
1111 
1112 void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableColSize( wxGridSizeEvent& aEvent )
1113 {
1114  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1115  int col = aEvent.GetRowOrCol();
1116  std::string key( m_grid->GetColLabelValue( col ).ToUTF8() );
1117 
1118  if( m_grid->GetColSize( col ) )
1119  cfg->m_FieldEditorPanel.column_widths[ key ] = m_grid->GetColSize( col );
1120 
1121  aEvent.Skip();
1122 }
1123 
1124 
1126 {
1128  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1129  m_grid->ForceRefresh();
1130 }
1131 
1132 
1134 {
1135  if( event.GetCol() == REFERENCE )
1136  {
1137  m_grid->ClearSelection();
1138  m_grid->SetGridCursor( event.GetRow(), event.GetCol() );
1139 
1140  m_dataModel->ExpandCollapseRow( event.GetRow() );
1141  std::vector<SCH_REFERENCE> refs = m_dataModel->GetRowReferences( event.GetRow() );
1142 
1143  // Focus Eeschema view on the component selected in the dialog
1144  if( refs.size() == 1 )
1145  {
1147 
1148  editor->FindComponentAndItem( refs[0].GetRef() + refs[0].GetRefNumber(), true,
1149  HIGHLIGHT_COMPONENT, wxEmptyString );
1150  }
1151  }
1152  else
1153  {
1154  event.Skip();
1155  }
1156 }
1157 
1158 
1160 {
1161  // TODO: Option to select footprint if FOOTPRINT column selected
1162 
1163  event.Skip();
1164 }
1165 
1166 
1168 {
1169  int nameColWidth = event.GetSize().GetX() - m_showColWidth - m_groupByColWidth - 8;
1170 
1171  // GTK loses its head and messes these up when resizing the splitter bar:
1172  m_fieldsCtrl->GetColumn( 1 )->SetWidth( m_showColWidth );
1173  m_fieldsCtrl->GetColumn( 2 )->SetWidth( m_groupByColWidth );
1174 
1175  m_fieldsCtrl->GetColumn( 0 )->SetWidth( nameColWidth );
1176 
1177  event.Skip();
1178 }
1179 
1180 
1182 {
1183  if( TransferDataFromWindow() )
1184  m_parent->SaveProject();
1185 }
1186 
1187 
1188 void DIALOG_FIELDS_EDITOR_GLOBAL::OnCancel( wxCommandEvent& event )
1189 {
1190  Close();
1191 }
1192 
1193 
1194 void DIALOG_FIELDS_EDITOR_GLOBAL::OnClose( wxCloseEvent& event )
1195 {
1196  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
1197  m_grid->CommitPendingChanges( true );
1198 
1199  if( m_dataModel->IsEdited() )
1200  {
1201  if( !HandleUnsavedChanges( this, _( "Save changes?" ),
1202  [&]()->bool { return TransferDataFromWindow(); } ) )
1203  {
1204  event.Veto();
1205  return;
1206  }
1207  }
1208 
1209  event.Skip();
1210 }
void SetCurrentSheet(const SCH_SHEET_PATH &aSheet)
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
void doPopupSelection(wxCommandEvent &event) override
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
bool HandleUnsavedChanges(wxWindow *aParent, const wxString &aMessage, const std::function< bool()> &aSaveFunction)
Display a dialog with Save, Cancel and Discard Changes buttons.
Definition: confirm.cpp:201
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject)
Function GetAssociatedDocument open a document (file) with the suitable browser.
Definition: eda_doc.cpp:80
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:59
SCH_FIELD * FindField(const wxString &aFieldName, bool aIncludeDefaultFields=true)
Search for a SCH_FIELD with aFieldName.
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
void OnColumnItemToggled(wxDataViewEvent &event) override
void AddColumn(const wxString &aFieldName)
name of datasheet
void LoadFieldNames()
Constructs the rows of m_fieldsCtrl and the columns of m_dataModel from a union of all field names in...
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:89
DATA_MODEL_ROW(const SCH_REFERENCE &aFirstReference, GROUP_TYPE aType)
std::vector< SCH_REFERENCE > m_Refs
Implementation of conversion functions that require both schematic and board internal units.
This file is part of the common library.
This file is part of the common library.
FIELDS_EDITOR_GRID_TRICKS(DIALOG_SHIM *aParent, WX_GRID *aGrid, wxDataViewListCtrl *aFieldsCtrl)
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:124
SCH_COMPONENT * GetComp() const
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
std::map< KIID, std::map< wxString, wxString > > m_dataStore
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
TEMPLATES m_TemplateFieldNames
void OnAddField(wxCommandEvent &event) override
Collection of utility functions for component reference designators (refdes)
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
int GetId() const
Definition: sch_field.h:114
Schematic editor (Eeschema) main window.
static wxString Shorthand(std::vector< SCH_REFERENCE > aList)
Function Shorthand Returns a shorthand string representing all the references in the list.
Dialog helper object to sit in the inheritance tree between wxDialog and any class written by wxFormB...
Definition: dialog_shim.h:83
wxString GetRefNumber() const
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
bool IsEmptyCell(int aRow, int aCol) override
wxString GetColLabelValue(int aCol) override
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:114
Field Name Module PCB, i.e. "16DIP300".
Field Reference of part, i.e. "IC21".
SCH_REFERENCE_LIST is used to create a flattened list of components because in a complex hierarchy,...
wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
Definition: common.cpp:268
DIALOG_FIELDS_EDITOR_GLOBAL(SCH_EDIT_FRAME *parent)
void OnCancel(wxCommandEvent &event) override
PANEL_FIELD_EDITOR m_FieldEditorPanel
WX_GRID * m_grid
I don't own the grid, but he owns me.
Definition: grid_tricks.h:58
EE_SELECTION & GetSelection()
Function GetSelection()
int RefDesStringCompare(const wxString &aFirst, const wxString &aSecond)
Acts just like the strcmp function but treats numbers within the string text correctly for sorting.
SCH_EDITOR_CONTROL.
wxString GetRef() const
void RebuildRows(wxCheckBox *groupComponentsBox, wxDataViewListCtrl *fieldsCtrl)
TOOL_MANAGER.
Definition: tool_manager.h:51
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:80
Definition: common.h:68
FIELDS_EDITOR_GRID_DATA_MODEL(SCH_EDIT_FRAME *aFrame, SCH_REFERENCE_LIST &aComponentList)
SCH_ITEM * FindComponentAndItem(const wxString &aReference, bool aSearchHierarchy, SCH_SEARCH_T aSearchType, const wxString &aSearchText)
Finds a component in the schematic and an item in this component.
void OnSizeFieldList(wxSizeEvent &event) override
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
#define NULL
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:343
int ValueStringCompare(wxString strFWord, wxString strSWord)
Compare strings like the strcmp function but handle numbers and modifiers within the string text corr...
Definition: string.cpp:596
void GetComponents(SCH_REFERENCE_LIST &aReferences, bool aIncludePowerSymbols=true, bool aForceIncludeOrphanComponents=false) const
Function GetComponents adds a SCH_REFERENCE() object to aReferences for each component in the list of...
void SyncView()
Mark all items for refresh.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
SCHEMATIC & Schematic() const
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.
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void OnClose(wxCloseEvent &event) override
void OnTableCellClick(wxGridEvent &event) override
EDA_ITEM * GetParent() const
Definition: base_struct.h:195
void showPopupMenu(wxMenu &menu) override
bool unitMatch(const SCH_REFERENCE &lhRef, const SCH_REFERENCE &rhRef)
SCH_SHEET_PATH.
bool groupMatch(const SCH_REFERENCE &lhRef, const SCH_REFERENCE &rhRef, wxDataViewListCtrl *fieldsCtrl)
bool CommitPendingChanges(bool aQuietMode=false)
Close any open cell edit controls.
Definition: wx_grid.cpp:180
void Sort(int aColumn, bool ascending)
std::map< std::string, int > column_widths
int GetFieldCount() const
Return the number of fields in this symbol.
const BITMAP_OPAQUE refresh_xpm[1]
Definition: refresh.cpp:32
#define SHOW_FIELD_COLUMN
const KIID m_Uuid
Definition: base_struct.h:162
unsigned GetCount() const
Function GetCount.
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
Field Value of part, i.e. "3.3K".
void OnSaveAndContinue(wxCommandEvent &aEvent) override
void OnRegroupComponents(wxCommandEvent &event) override
wxString GetFieldText(const wxString &aFieldName, SCH_EDIT_FRAME *aFrame) const
Search for a field named aFieldName and returns text associated with this field.
FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
virtual void doPopupSelection(wxCommandEvent &event)
#define QUANTITY_COLUMN
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
virtual void showPopupMenu(wxMenu &menu)
void SplitReferences()
Function SplitReferences attempts to split all reference designators into a name (U) and number (1).
#define _(s)
Definition: 3d_actions.cpp:33
#define FIELD_NAME_COLUMN
static bool cmp(const DATA_MODEL_ROW &lhGroup, const DATA_MODEL_ROW &rhGroup, FIELDS_EDITOR_GRID_DATA_MODEL *dataModel, int sortCol, bool ascending)
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:442
Schematic symbol object.
Definition: sch_component.h:80
wxPoint GetPosition() const override
void RemoveField(const wxString &aFieldName)
Removes a user field from the symbol.
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: base_struct.h:159
#define COLUMN_MARGIN
Struct TEMPLATE_FIELDNAME holds a name of a component's field, field value, and default visibility.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void SetValue(int aRow, int aCol, const wxString &aValue) override
#define GROUP_BY_COLUMN
SCH_SHEET_PATH & GetCurrentSheet() const
void OnTableColSize(wxGridSizeEvent &event) override
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...
Definition for part library class.
Class DIALOG_FIELDS_EDITOR_GLOBAL_BASE.
wxString GetValue(int aRow, int aCol) override
std::map< std::string, bool > fields_group_by
void SetValue(const SCH_SHEET_PATH *sheet, const wxString &aValue)
std::map< std::string, bool > fields_show
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition: base_units.h:48
void OnTableItemContextMenu(wxGridEvent &event) override
void OnTableValueChanged(wxGridEvent &event) override
virtual bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
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.
std::vector< DATA_MODEL_ROW > m_rows
SCH_REFERENCE is used as a helper to define a component's reference designator in a schematic.
wxString GetValue(DATA_MODEL_ROW &group, int aCol)
void OnGroupComponentsToggled(wxCommandEvent &event) override
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
std::vector< SCH_REFERENCE > GetRowReferences(int aRow)
void AddField(const wxString &aName, bool defaultShow, bool defaultSortBy)