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