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