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