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