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 
604  m_frame->SetCurrentSheet( m_componentRefs[i].GetSheetPath() );
605  m_frame->SaveCopyInUndoList( &comp, UR_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  continue;
625  }
626 
627  // Reference and value fields cannot be empty. All other fields can.
628  if( srcValue.IsEmpty()
629  && (destField->GetId() == REFERENCE || destField->GetId() == VALUE))
630  continue;
631 
632  destField->SetText( srcValue );
633  }
634  }
635 
636  m_edited = false;
637  }
638 
639 
640  int GetDataWidth( int aCol )
641  {
642  int width = 0;
643 
644  if( aCol == REFERENCE )
645  {
646  for( int row = 0; row < GetNumberRows(); ++row )
647  {
648  width = std::max( width, GetTextSize( GetValue( row, aCol ), GetView() ).x );
649  }
650  }
651  else
652  {
653  wxString column_label = GetColLabelValue( aCol ); // component fieldName or Qty string
654 
655  for( unsigned compRef = 0; compRef < m_componentRefs.GetCount(); ++ compRef )
656  {
657  const KIID& compId = m_componentRefs[ compRef ].GetComp()->m_Uuid;
658  wxString text = m_dataStore[ compId ][ column_label ];
659 
660  width = std::max( width, GetTextSize( text, GetView() ).x );
661  }
662  }
663 
664  return width;
665  }
666 
667 
668  bool IsEdited()
669  {
670  return m_edited;
671  }
672 };
673 
674 
677  m_parent( parent )
678 {
679  wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
680 
681  // Get all components from the list of schematic sheets
683 
684  m_bRefresh->SetBitmap( KiBitmap( refresh_xpm ) );
685 
686  m_fieldsCtrl->AppendTextColumn( _( "Field" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
687  m_fieldsCtrl->AppendToggleColumn( _( "Show" ), wxDATAVIEW_CELL_ACTIVATABLE, 0, wxALIGN_CENTER,
688  0 );
689  m_fieldsCtrl->AppendToggleColumn( _( "Group By" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
690  wxALIGN_CENTER, 0 );
691 
692  // SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails here on GTK, so we calculate the title sizes and
693  // set the column widths ourselves.
694  auto column = m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN );
695  m_showColWidth = GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
696  column->SetWidth( m_showColWidth );
697 
698  column = m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN );
699  m_groupByColWidth = GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
700  column->SetWidth( m_groupByColWidth );
701 
702  // The fact that we're a list should keep the control from reserving space for the
703  // expander buttons... but it doesn't. Fix by forcing the indent to 0.
704  m_fieldsCtrl->SetIndent( 0 );
705 
707 
708  LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel
709 
710  // Now that the fields are loaded we can set the initial location of the splitter
711  // based on the list width. Again, SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails us on GTK.
712  int nameColWidth = 0;
713 
714  for( int row = 0; row < m_fieldsCtrl->GetItemCount(); ++row )
715  {
716  const wxString& fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
717  nameColWidth = std::max( nameColWidth, GetTextSize( fieldName, m_fieldsCtrl ).x );
718  }
719 
720  m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetWidth( nameColWidth );
721  m_splitter1->SetSashPosition( nameColWidth + m_showColWidth + m_groupByColWidth + 40 );
722 
724  m_dataModel->Sort( 0, true );
725 
726  // wxGrid's column moving is buggy with native headers and this is one dialog where you'd
727  // really like to be able to rearrange columns.
728  m_grid->UseNativeColHeader( false );
729  m_grid->SetTable( m_dataModel, true );
730 
731  // must be done after SetTable(), which appears to re-set it
732  m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
733 
734  // sync m_grid's column visibilities to Show checkboxes in m_fieldsCtrl
735  for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
736  {
737  if( m_fieldsCtrl->GetToggleValue( i, 1 ) )
738  m_grid->ShowCol( i );
739  else
740  m_grid->HideCol( i );
741  }
742 
743  // add Cut, Copy, and Paste to wxGrid
744  m_grid->PushEventHandler( new FIELDS_EDITOR_GRID_TRICKS( this, m_grid, m_fieldsCtrl ) );
745 
746  // give a bit more room for comboboxes
747  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
748 
749  // set reference column attributes
750  wxGridCellAttr* attr = new wxGridCellAttr;
751  attr->SetReadOnly();
752  m_grid->SetColAttr( REFERENCE, attr );
753 
754  // set footprint column browse button
755  attr = new wxGridCellAttr;
756  attr->SetEditor( new GRID_CELL_FOOTPRINT_ID_EDITOR( this ) );
757  m_grid->SetColAttr( FOOTPRINT, attr );
758 
759  // set datasheet column viewer button
760  attr = new wxGridCellAttr;
761  attr->SetEditor( new GRID_CELL_URL_EDITOR( this ) );
762  m_grid->SetColAttr( DATASHEET, attr );
763 
764  // set quantities column attributes
765  attr = new wxGridCellAttr;
766  attr->SetReadOnly();
767  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
768  m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
769  m_grid->AutoSizeColumns( false );
770 
771  for( int col = 0; col < m_grid->GetNumberCols(); ++col )
772  {
773  // Columns are hidden by setting their width to 0 so if we resize them they will
774  // become unhidden.
775  if( m_grid->IsColShown( col ) )
776  {
777  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
778  std::string key( m_dataModel->GetColLabelValue( col ).ToUTF8() );
779 
780  if( cfg->m_FieldEditorPanel.column_widths.count( key ) )
781  {
782  int width = cfg->m_FieldEditorPanel.column_widths.at( key );
783  m_grid->SetColSize( col, width );
784  }
785  else
786  {
787  int textWidth = m_dataModel->GetDataWidth( col ) + COLUMN_MARGIN;
788  int maxWidth = defaultDlgSize.x / 3;
789 
790  if( col == m_grid->GetNumberCols() - 1 )
791  m_grid->SetColSize( col, std::min( std::max( 50, textWidth ), maxWidth ) );
792  else
793  m_grid->SetColSize( col, std::min( std::max( 100, textWidth ), maxWidth ) );
794  }
795  }
796  }
797 
798  m_grid->SelectRow( 0 );
799  m_grid->SetGridCursor( 0, 1 );
801 
802  m_sdbSizer1OK->SetDefault();
803 
805  SetSize( defaultDlgSize );
806  Center();
807 
808  // Connect Events
809  m_grid->Connect( wxEVT_GRID_COL_SORT,
810  wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this );
811 }
812 
813 
815 {
816  // Disconnect Events
817  m_grid->Disconnect( wxEVT_GRID_COL_SORT,
818  wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this );
819 
820  // Delete the GRID_TRICKS.
821  m_grid->PopEventHandler( true );
822 
823  // we gave ownership of m_dataModel to the wxGrid...
824 }
825 
826 
828 {
829  if( !wxDialog::TransferDataFromWindow() )
830  return false;
831 
832  TOOL_MANAGER* toolMgr = m_parent->GetToolManager();
833  EE_SELECTION_TOOL* selectionTool = toolMgr->GetTool<EE_SELECTION_TOOL>();
834  EE_SELECTION& selection = selectionTool->GetSelection();
835  SCH_COMPONENT* component = nullptr;
836 
837  if( selection.GetSize() == 1 )
838  {
839  EDA_ITEM* item = selection.Front();
840 
841  if( item->Type() == SCH_COMPONENT_T )
842  component = (SCH_COMPONENT*) item;
843  else if( item->GetParent() && item->GetParent()->Type() == SCH_COMPONENT_T )
844  component = (SCH_COMPONENT*) item->GetParent();
845  }
846 
847  if( component )
848  {
849  for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
850  {
851  std::vector<SCH_REFERENCE> references = m_dataModel->GetRowReferences( row );
852  bool found = false;
853 
854  for( const SCH_REFERENCE& ref : references )
855  {
856  if( ref.GetComp() == component )
857  {
858  found = true;
859  break;
860  }
861  }
862 
863  if( found )
864  {
865  m_grid->GoToCell( row, 1 );
866  break;
867  }
868  }
869  }
870 
871  return true;
872 }
873 
874 
876 {
877  if( !m_grid->CommitPendingChanges() )
878  return false;
879 
880  if( !wxDialog::TransferDataFromWindow() )
881  return false;
882 
883  SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet();
884 
886 
887  // Reset the view to where we left the user
888  m_parent->SetCurrentSheet( currentSheet );
889  m_parent->SyncView();
890  m_parent->Refresh();
891 
892  m_parent->OnModify();
893 
894  return true;
895 }
896 
897 
898 void DIALOG_FIELDS_EDITOR_GLOBAL::AddField( const wxString& aName,
899  bool defaultShow, bool defaultSortBy )
900 {
901  m_dataModel->AddColumn( aName );
902 
903  wxVector<wxVariant> fieldsCtrlRow;
904 
905  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
906  bool show = defaultShow;
907  bool sort_by = defaultSortBy;
908 
909  std::string key( aName.ToUTF8() );
910 
911  if( cfg->m_FieldEditorPanel.fields_show.count( key ) )
912  show = cfg->m_FieldEditorPanel.fields_show.at( key );
913 
914  if( cfg->m_FieldEditorPanel.fields_group_by.count( key ) )
915  sort_by = cfg->m_FieldEditorPanel.fields_group_by.at( key );
916 
917  // Don't change these to emplace_back: some versions of wxWidgets don't support it
918  fieldsCtrlRow.push_back( wxVariant( aName ) );
919  fieldsCtrlRow.push_back( wxVariant( show ) );
920  fieldsCtrlRow.push_back( wxVariant( sort_by ) );
921 
922  m_fieldsCtrl->AppendItem( fieldsCtrlRow );
923 }
924 
925 
931 {
932  std::set<wxString> userFieldNames;
933 
934  for( unsigned i = 0; i < m_componentRefs.GetCount(); ++i )
935  {
936  SCH_COMPONENT* comp = m_componentRefs[ i ].GetComp();
937 
938  for( int j = MANDATORY_FIELDS; j < comp->GetFieldCount(); ++j )
939  userFieldNames.insert( comp->GetField( j )->GetName() );
940  }
941 
942  // Force References to always be shown
943  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
944  wxCHECK( cfg, /*void*/ );
945 
946  cfg->m_FieldEditorPanel.fields_show["Reference"] = true;
947 
948  // *DO NOT* use translated mandatory field names:
949  // They are also used as keyword to find fields in component list.
950  // Changing that is not a basic change
951  AddField( "Reference", true, true );
952  AddField( "Value", true, true );
953  AddField( "Footprint", true, true );
954  AddField( "Datasheet", true, false );
955 
956  for( const wxString& fieldName : userFieldNames )
957  AddField( fieldName, true, false );
958 
959  // Add any templateFieldNames which aren't already present in the userFieldNames
960  for( const TEMPLATE_FIELDNAME& templateFieldName : m_parent->GetTemplateFieldNames() )
961  {
962  if( userFieldNames.count( templateFieldName.m_Name ) == 0 )
963  AddField( templateFieldName.m_Name, false, false );
964  }
965 }
966 
967 
968 void DIALOG_FIELDS_EDITOR_GLOBAL::OnAddField( wxCommandEvent& event )
969 {
970  // quantities column will become new field column, so it needs to be reset
971  auto attr = new wxGridCellAttr;
972  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
973  m_grid->SetColFormatCustom( m_dataModel->GetColsCount() - 1, wxGRID_VALUE_STRING );
974 
975  wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Add Field" ) );
976 
977  if( dlg.ShowModal() != wxID_OK )
978  return;
979 
980  wxString fieldName = dlg.GetValue();
981 
982  if( fieldName.IsEmpty() )
983  {
984  DisplayError( this, _( "Field must have a name." ) );
985  return;
986  }
987 
988  for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
989  {
990  if( fieldName == m_dataModel->GetColLabelValue( i ) )
991  {
992  DisplayError( this, wxString::Format( _( "Field name \"%s\" already in use." ),
993  fieldName ) );
994  return;
995  }
996  }
997 
998  std::string key( fieldName.ToUTF8() );
999 
1000  auto cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1001  cfg->m_FieldEditorPanel.fields_show[key] = true;
1002 
1003  AddField( fieldName, true, false );
1004 
1005  wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_INSERTED,
1006  m_fieldsCtrl->GetItemCount(), 1 );
1007  m_grid->ProcessTableMessage( msg );
1008 
1009  // set up attributes on the new quantities column
1010  attr = new wxGridCellAttr;
1011  attr->SetReadOnly();
1012  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
1013  m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
1014  m_grid->SetColSize( m_dataModel->GetColsCount() - 1, 50 );
1015 }
1016 
1017 
1019 {
1020  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1021  wxDataViewItem item = event.GetItem();
1022 
1023  int row = m_fieldsCtrl->ItemToRow( item );
1024  int col = event.GetColumn();
1025 
1026  switch ( col )
1027  {
1028  default:
1029  break;
1030 
1031  case SHOW_FIELD_COLUMN:
1032  {
1033  bool value = m_fieldsCtrl->GetToggleValue( row, col );
1034 
1035  if( row == REFERENCE && !value )
1036  {
1037  DisplayError( this, _( "The Reference column cannot be hidden." ) );
1038 
1039  value = true;
1040  m_fieldsCtrl->SetToggleValue( value, row, col );
1041  }
1042 
1043  std::string fieldName( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ).ToUTF8() );
1044  cfg->m_FieldEditorPanel.fields_show[fieldName] = value;
1045 
1046  if( value )
1047  m_grid->ShowCol( row );
1048  else
1049  m_grid->HideCol( row ); // grid's columns map to fieldsCtrl's rows
1050  break;
1051  }
1052 
1053  case GROUP_BY_COLUMN:
1054  {
1055  bool value = m_fieldsCtrl->GetToggleValue( row, col );
1056  std::string fieldName( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ).ToUTF8() );
1057  cfg->m_FieldEditorPanel.fields_group_by[fieldName] = value;
1058 
1060  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1061  m_grid->ForceRefresh();
1062  break;
1063  }
1064  }
1065 }
1066 
1067 
1069 {
1071  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1072  m_grid->ForceRefresh();
1073 }
1074 
1075 
1076 void DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort( wxGridEvent& aEvent )
1077 {
1078  int sortCol = aEvent.GetCol();
1079  bool ascending;
1080 
1081  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
1082  // event, and if we ask it will give us pre-event info.
1083  if( m_grid->IsSortingBy( sortCol ) )
1084  // same column; invert ascending
1085  ascending = !m_grid->IsSortOrderAscending();
1086  else
1087  // different column; start with ascending
1088  ascending = true;
1089 
1090  m_dataModel->Sort( sortCol, ascending );
1091  m_grid->ForceRefresh();
1092 }
1093 
1094 
1096 {
1097  m_grid->ForceRefresh();
1098 }
1099 
1100 
1101 void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableColSize( wxGridSizeEvent& aEvent )
1102 {
1103  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1104  int col = aEvent.GetRowOrCol();
1105  std::string key( m_grid->GetColLabelValue( col ).ToUTF8() );
1106 
1107  if( m_grid->GetColSize( col ) )
1108  cfg->m_FieldEditorPanel.column_widths[ key ] = m_grid->GetColSize( col );
1109 
1110  aEvent.Skip();
1111 }
1112 
1113 
1115 {
1117  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1118  m_grid->ForceRefresh();
1119 }
1120 
1121 
1123 {
1124  if( event.GetCol() == REFERENCE )
1125  {
1126  m_grid->ClearSelection();
1127  m_grid->SetGridCursor( event.GetRow(), event.GetCol() );
1128 
1129  m_dataModel->ExpandCollapseRow( event.GetRow() );
1130  std::vector<SCH_REFERENCE> refs = m_dataModel->GetRowReferences( event.GetRow() );
1131 
1132  // Focus Eeschema view on the component selected in the dialog
1133  if( refs.size() == 1 )
1134  {
1136 
1137  editor->FindComponentAndItem( refs[0].GetRef() + refs[0].GetRefNumber(), true,
1138  HIGHLIGHT_COMPONENT, wxEmptyString );
1139  }
1140  }
1141  else
1142  {
1143  event.Skip();
1144  }
1145 }
1146 
1147 
1149 {
1150  // TODO: Option to select footprint if FOOTPRINT column selected
1151 
1152  event.Skip();
1153 }
1154 
1155 
1157 {
1158  int nameColWidth = event.GetSize().GetX() - m_showColWidth - m_groupByColWidth - 8;
1159 
1160  // GTK loses its head and messes these up when resizing the splitter bar:
1161  m_fieldsCtrl->GetColumn( 1 )->SetWidth( m_showColWidth );
1162  m_fieldsCtrl->GetColumn( 2 )->SetWidth( m_groupByColWidth );
1163 
1164  m_fieldsCtrl->GetColumn( 0 )->SetWidth( nameColWidth );
1165 
1166  event.Skip();
1167 }
1168 
1169 
1171 {
1172  if( TransferDataFromWindow() )
1173  m_parent->SaveProject();
1174 }
1175 
1176 
1177 void DIALOG_FIELDS_EDITOR_GLOBAL::OnCancel( wxCommandEvent& event )
1178 {
1179  Close();
1180 }
1181 
1182 
1183 void DIALOG_FIELDS_EDITOR_GLOBAL::OnClose( wxCloseEvent& event )
1184 {
1185  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
1186  m_grid->CommitPendingChanges( true );
1187 
1188  if( m_dataModel->IsEdited() )
1189  {
1190  if( !HandleUnsavedChanges( this, wxEmptyString,
1191  [&]()->bool { return TransferDataFromWindow(); } ) )
1192  {
1193  event.Veto();
1194  return;
1195  }
1196  }
1197 
1198  event.Skip();
1199 }
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:92
DATA_MODEL_ROW(const SCH_REFERENCE &aFirstReference, GROUP_TYPE aType)
#define INDETERMINATE_STATE
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: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:59
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:116
#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:342
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:575
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.
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.
SCHEMATIC & Schematic() const
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:174
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: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:420
Schematic symbol object.
Definition: sch_component.h:88
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:74
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
std::map< std::string, bool > fields_show
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:193
std::vector< SCH_REFERENCE > GetRowReferences(int aRow)
void AddField(const wxString &aName, bool defaultShow, bool defaultSortBy)