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 
191 public:
193  m_frame( aFrame ),
194  m_symbolsList( aSymbolsList ),
195  m_edited( false ),
196  m_sortColumn( 0 ),
197  m_sortAscending( false )
198  {
200  }
201 
202 
203  void AddColumn( const wxString& aFieldName )
204  {
205  m_fieldNames.push_back( aFieldName );
206 
207  for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
208  {
209  SCH_COMPONENT* symbol = m_symbolsList[ i ].GetSymbol();
210  m_dataStore[ symbol->m_Uuid ][ aFieldName ] = symbol->GetFieldText( aFieldName, m_frame );
211  }
212  }
213 
214 
215  int GetNumberRows() override { return m_rows.size(); }
216 
217  // Columns are fieldNames + quantity column
218  int GetNumberCols() override { return (int) m_fieldNames.size() + 1; }
219 
220 
221  wxString GetColLabelValue( int aCol ) override
222  {
223  if( aCol == QUANTITY_COLUMN )
224  return _( "Qty" );
225  else if( aCol < MANDATORY_FIELDS )
227  else
228  return m_fieldNames[ aCol ];
229  }
230 
231 
232  wxString GetCanonicalColLabel( int aCol )
233  {
234  if( aCol == QUANTITY_COLUMN )
235  return _( "Qty" );
236  else
237  return m_fieldNames[ aCol ];
238  }
239 
240 
241  bool IsEmptyCell( int aRow, int aCol ) override
242  {
243  return false; // don't allow adjacent cell overflow, even if we are actually empty
244  }
245 
246 
247  wxString GetValue( int aRow, int aCol ) override
248  {
249  if( aCol == REFERENCE_FIELD )
250  {
251  // Poor-man's tree controls
252  if( m_rows[ aRow ].m_Flag == GROUP_COLLAPSED )
253  return wxT( "> " ) + GetValue( m_rows[ aRow ], aCol );
254  else if (m_rows[ aRow ].m_Flag == GROUP_EXPANDED )
255  return wxT( "v " ) + GetValue( m_rows[ aRow ], aCol );
256  else if( m_rows[ aRow ].m_Flag == CHILD_ITEM )
257  return wxT( " " ) + GetValue( m_rows[ aRow ], aCol );
258  else
259  return wxT( " " ) + GetValue( m_rows[ aRow ], aCol );
260  }
261  else
262  return GetValue( m_rows[ aRow ], aCol );
263  }
264 
265  std::vector<SCH_REFERENCE> GetRowReferences( int aRow ) const
266  {
267  wxCHECK( aRow < (int)m_rows.size(), std::vector<SCH_REFERENCE>() );
268  return m_rows[ aRow ].m_Refs;
269  }
270 
271  wxString GetValue( const DATA_MODEL_ROW& group, int aCol )
272  {
273  std::vector<SCH_REFERENCE> references;
274  wxString fieldValue;
275 
276  for( const auto& ref : group.m_Refs )
277  {
278  if( aCol == REFERENCE_FIELD || aCol == QUANTITY_COLUMN )
279  {
280  references.push_back( ref );
281  }
282  else // Other columns are either a single value or ROW_MULTI_ITEMS
283  {
284  const KIID& symbolID = ref.GetSymbol()->m_Uuid;
285 
286  if( !m_dataStore.count( symbolID ) ||
287  !m_dataStore[ symbolID ].count( m_fieldNames[ aCol ] ) )
288  {
289  return INDETERMINATE_STATE;
290  }
291 
292  if( &ref == &group.m_Refs.front() )
293  {
294  fieldValue = m_dataStore[ symbolID ][ m_fieldNames[ aCol ] ];
295  }
296  else if ( fieldValue != m_dataStore[ symbolID ][ m_fieldNames[ aCol ] ] )
297  {
298  return INDETERMINATE_STATE;
299  }
300  }
301  }
302 
303  if( aCol == REFERENCE_FIELD || aCol == QUANTITY_COLUMN )
304  {
305  // Remove duplicates (other units of multi-unit parts)
306  std::sort( references.begin(), references.end(),
307  []( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
308  {
309  wxString l_ref( l.GetRef() << l.GetRefNumber() );
310  wxString r_ref( r.GetRef() << r.GetRefNumber() );
311  return UTIL::RefDesStringCompare( l_ref, r_ref ) < 0;
312  } );
313 
314  auto logicalEnd = std::unique( references.begin(), references.end(),
315  []( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
316  {
317  // If unannotated then we can't tell what units belong together
318  // so we have to leave them all
319  if( l.GetRefNumber() == wxT( "?" ) )
320  return false;
321 
322  wxString l_ref( l.GetRef() << l.GetRefNumber() );
323  wxString r_ref( r.GetRef() << r.GetRefNumber() );
324  return l_ref == r_ref;
325  } );
326  references.erase( logicalEnd, references.end() );
327  }
328 
329  if( aCol == REFERENCE_FIELD )
330  {
331  fieldValue = SCH_REFERENCE_LIST::Shorthand( references );
332  }
333  else if( aCol == QUANTITY_COLUMN )
334  {
335  fieldValue = wxString::Format( wxT( "%d" ), ( int )references.size() );
336  }
337 
338  return fieldValue;
339  }
340 
341 
342  void SetValue( int aRow, int aCol, const wxString &aValue ) override
343  {
344  if( aCol == REFERENCE_FIELD || aCol == QUANTITY_COLUMN )
345  return; // Can't modify references or quantity
346 
347  DATA_MODEL_ROW& rowGroup = m_rows[ aRow ];
348  wxString fieldName = m_fieldNames[ aCol ];
349 
350  for( const auto& ref : rowGroup.m_Refs )
351  m_dataStore[ ref.GetSymbol()->m_Uuid ][ fieldName ] = aValue;
352 
353  m_edited = true;
354  }
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 = [ ascending ]( const auto a, const auto b )
369  {
370  if( ascending )
371  return a < b;
372  else
373  return a > b;
374  };
375 
376  // Primary sort key is sortCol; secondary is always REFERENCE (column 0)
377 
378  wxString lhs = dataModel->GetValue( (DATA_MODEL_ROW&) lhGroup, sortCol );
379  wxString rhs = dataModel->GetValue( (DATA_MODEL_ROW&) rhGroup, sortCol );
380 
381  if( lhs == rhs || sortCol == REFERENCE_FIELD )
382  {
383  wxString lhRef = lhGroup.m_Refs[ 0 ].GetRef() + lhGroup.m_Refs[ 0 ].GetRefNumber();
384  wxString rhRef = rhGroup.m_Refs[ 0 ].GetRef() + rhGroup.m_Refs[ 0 ].GetRefNumber();
385  return local_cmp( UTIL::RefDesStringCompare( lhRef, rhRef ), 0 );
386  }
387  else
388  return local_cmp( ValueStringCompare( lhs, rhs ), 0 );
389  }
390 
391 
392  void Sort( int aColumn, bool ascending )
393  {
394  if( aColumn < 0 )
395  aColumn = 0;
396 
397  m_sortColumn = aColumn;
398  m_sortAscending = ascending;
399 
400  CollapseForSort();
401 
402  std::sort( m_rows.begin(), m_rows.end(),
403  [ this ]( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
404  {
405  return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
406  } );
407 
408  ExpandAfterSort();
409  }
410 
411 
412  bool unitMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef )
413  {
414  // If items are unannotated then we can't tell if they're units of the same symbol or not
415  if( lhRef.GetRefNumber() == wxT( "?" ) )
416  return false;
417 
418  return ( lhRef.GetRef() == rhRef.GetRef() && lhRef.GetRefNumber() == rhRef.GetRefNumber() );
419  }
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 
460  void RebuildRows( wxCheckBox* aGroupSymbolsBox, wxDataViewListCtrl* aFieldsCtrl )
461  {
462  if ( GetView() )
463  {
464  // Commit any pending in-place edits before the row gets moved out from under
465  // the editor.
466  static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
467 
468  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
469  GetView()->ProcessTableMessage( msg );
470  }
471 
472  m_rows.clear();
473 
474  for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
475  {
476  SCH_REFERENCE ref = m_symbolsList[ i ];
477  bool matchFound = false;
478 
479  // See if we already have a row which this symbol fits into
480  for( auto& row : m_rows )
481  {
482  // all group members must have identical refs so just use the first one
483  SCH_REFERENCE rowRef = row.m_Refs[ 0 ];
484 
485  if( unitMatch( ref, rowRef ) )
486  {
487  matchFound = true;
488  row.m_Refs.push_back( ref );
489  break;
490  }
491  else if ( aGroupSymbolsBox->GetValue() && groupMatch( ref, rowRef, aFieldsCtrl ) )
492  {
493  matchFound = true;
494  row.m_Refs.push_back( ref );
495  row.m_Flag = GROUP_COLLAPSED;
496  break;
497  }
498  }
499 
500  if( !matchFound )
501  m_rows.emplace_back( DATA_MODEL_ROW( ref, GROUP_SINGLETON ) );
502  }
503 
504  if ( GetView() )
505  {
506  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
507  GetView()->ProcessTableMessage( msg );
508  }
509  }
510 
511 
512  void ExpandRow( int aRow )
513  {
514  std::vector<DATA_MODEL_ROW> children;
515 
516  for( auto& ref : m_rows[ aRow ].m_Refs )
517  {
518  bool matchFound = false;
519 
520  // See if we already have a child group which this symbol fits into
521  for( auto& child : children )
522  {
523  // group members are by definition all matching, so just check
524  // against the first member
525  if( unitMatch( ref, child.m_Refs[ 0 ] ) )
526  {
527  matchFound = true;
528  child.m_Refs.push_back( ref );
529  break;
530  }
531  }
532 
533  if( !matchFound )
534  children.emplace_back( DATA_MODEL_ROW( ref, CHILD_ITEM ) );
535  }
536 
537  if( children.size() < 2 )
538  return;
539 
540  std::sort( children.begin(), children.end(),
541  [ this ] ( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
542  {
543  return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
544  } );
545 
546  m_rows[ aRow ].m_Flag = GROUP_EXPANDED;
547  m_rows.insert( m_rows.begin() + aRow + 1, children.begin(), children.end() );
548 
549  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, children.size() );
550  GetView()->ProcessTableMessage( msg );
551  }
552 
553 
554  void CollapseRow( int aRow )
555  {
556  auto firstChild = m_rows.begin() + aRow + 1;
557  auto afterLastChild = firstChild;
558  int deleted = 0;
559 
560  while( afterLastChild != m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
561  {
562  deleted++;
563  afterLastChild++;
564  }
565 
566  m_rows[ aRow ].m_Flag = GROUP_COLLAPSED;
567  m_rows.erase( firstChild, afterLastChild );
568 
569  wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
570  GetView()->ProcessTableMessage( msg );
571  }
572 
573 
574  void ExpandCollapseRow( int aRow )
575  {
576  DATA_MODEL_ROW& group = m_rows[ aRow ];
577 
578  if( group.m_Flag == GROUP_COLLAPSED )
579  ExpandRow( aRow );
580  else if( group.m_Flag == GROUP_EXPANDED )
581  CollapseRow( aRow );
582  }
583 
584 
586  {
587  for( size_t i = 0; i < m_rows.size(); ++i )
588  {
589  if( m_rows[ i ].m_Flag == GROUP_EXPANDED )
590  {
591  CollapseRow( i );
592  m_rows[ i ].m_Flag = GROUP_COLLAPSED_DURING_SORT;
593  }
594  }
595  }
596 
597 
599  {
600  for( size_t i = 0; i < m_rows.size(); ++i )
601  {
602  if( m_rows[ i ].m_Flag == GROUP_COLLAPSED_DURING_SORT )
603  ExpandRow( i );
604  }
605  }
606 
607 
608  void ApplyData()
609  {
610  for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
611  {
612  SCH_COMPONENT& symbol = *m_symbolsList[ i ].GetSymbol();
613  SCH_SCREEN* screen = m_symbolsList[i].GetSheetPath().LastScreen();
614 
615  m_frame->SaveCopyInUndoList( screen, &symbol, UNDO_REDO::CHANGED, true );
616 
617  const std::map<wxString, wxString>& fieldStore = m_dataStore[symbol.m_Uuid];
618 
619  for( const std::pair<wxString, wxString> srcData : fieldStore )
620  {
621  const wxString& srcName = srcData.first;
622  const wxString& srcValue = srcData.second;
623  SCH_FIELD* destField = symbol.FindField( srcName );
624 
625  if( !destField && !srcValue.IsEmpty() )
626  {
627  const wxPoint symbolPos = symbol.GetPosition();
628  destField = symbol.AddField( SCH_FIELD( symbolPos, -1, &symbol, srcName ) );
629  }
630 
631  if( !destField )
632  {
633  symbol.RemoveField( srcName );
634  }
635  else if( destField->GetId() == REFERENCE_FIELD )
636  {
637  // Reference is not editable
638  }
639  else if( destField->GetId() == VALUE_FIELD )
640  {
641  // Value field cannot be empty
642  if( !srcValue.IsEmpty() )
643  symbol.SetValue( srcValue );
644  }
645  else if( destField->GetId() == FOOTPRINT_FIELD )
646  {
647  symbol.SetFootprint( srcValue );
648  }
649  else
650  {
651  destField->SetText( srcValue );
652  }
653  }
654  }
655 
656  m_edited = false;
657  }
658 
659 
660  int GetDataWidth( int aCol )
661  {
662  int width = 0;
663 
664  if( aCol == REFERENCE_FIELD )
665  {
666  for( int row = 0; row < GetNumberRows(); ++row )
667  {
668  width = std::max( width, KIUI::GetTextSize( GetValue( row, aCol ), GetView() ).x );
669  }
670  }
671  else
672  {
673  wxString column_label = GetColLabelValue( aCol ); // symbol fieldName or Qty string
674 
675  for( unsigned symbolRef = 0; symbolRef < m_symbolsList.GetCount(); ++ symbolRef )
676  {
677  const KIID& symbolID = m_symbolsList[ symbolRef ].GetSymbol()->m_Uuid;
678  wxString text = m_dataStore[ symbolID ][ column_label ];
679 
680  width = std::max( width, KIUI::GetTextSize( text, GetView() ).x );
681  }
682  }
683 
684  return width;
685  }
686 
687 
688  bool IsEdited()
689  {
690  return m_edited;
691  }
692 };
693 
694 
697  m_parent( parent )
698 {
699  wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
700 
701  // Get all symbols from the list of schematic sheets
703 
704  m_bRefresh->SetBitmap( KiBitmap( refresh_xpm ) );
705 
706  m_fieldsCtrl->AppendTextColumn( _( "Field" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
707  m_fieldsCtrl->AppendToggleColumn( _( "Show" ), wxDATAVIEW_CELL_ACTIVATABLE, 0, wxALIGN_CENTER,
708  0 );
709  m_fieldsCtrl->AppendToggleColumn( _( "Group By" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
710  wxALIGN_CENTER, 0 );
711  m_fieldsCtrl->AppendTextColumn( _( "Name" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
712 
713  // SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails here on GTK, so we calculate the title sizes and
714  // set the column widths ourselves.
715  wxDataViewColumn* column = m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN );
716  m_showColWidth = KIUI::GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
717  column->SetMinWidth( m_showColWidth );
718 
719  column = m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN );
720  m_groupByColWidth = KIUI::GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
721  column->SetMinWidth( m_groupByColWidth );
722 
723  // The fact that we're a list should keep the control from reserving space for the
724  // expander buttons... but it doesn't. Fix by forcing the indent to 0.
725  m_fieldsCtrl->SetIndent( 0 );
726 
728 
729  LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel
730 
731  // Now that the fields are loaded we can set the initial location of the splitter
732  // based on the list width. Again, SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails us on GTK.
733  int nameColWidth = 0;
735 
736  for( int row = 0; row < m_fieldsCtrl->GetItemCount(); ++row )
737  {
738  const wxString& fieldName = m_fieldsCtrl->GetTextValue( row, DISPLAY_NAME_COLUMN );
739  nameColWidth = std::max( nameColWidth, KIUI::GetTextSize( fieldName, m_fieldsCtrl ).x );
740  const wxString& canon_Name = m_fieldsCtrl->GetTextValue( row, CANONICAL_NAME_COLUMN );
742  KIUI::GetTextSize( canon_Name, m_fieldsCtrl ).x );
743  }
744 
746 
747  int fieldsMinWidth = nameColWidth + m_canonicalNameColWidth +
749 
750  m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( nameColWidth );
752 
753  m_splitterMainWindow->SetMinimumPaneSize( fieldsMinWidth );
754  m_splitterMainWindow->SetSashPosition( fieldsMinWidth + 40 );
755 
757  m_dataModel->Sort( 0, true );
758 
759  // wxGrid's column moving is buggy with native headers and this is one dialog where you'd
760  // really like to be able to rearrange columns.
761  m_grid->UseNativeColHeader( false );
762  m_grid->SetTable( m_dataModel, true );
763 
764  // must be done after SetTable(), which appears to re-set it
765  m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
766 
767  // sync m_grid's column visibilities to Show checkboxes in m_fieldsCtrl
768  for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
769  {
770  if( m_fieldsCtrl->GetToggleValue( i, 1 ) )
771  m_grid->ShowCol( i );
772  else
773  m_grid->HideCol( i );
774  }
775 
776  // add Cut, Copy, and Paste to wxGrid
777  m_grid->PushEventHandler( new FIELDS_EDITOR_GRID_TRICKS( this, m_grid, m_fieldsCtrl ) );
778 
779  // give a bit more room for comboboxes
780  m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
781 
782  // set reference column attributes
783  wxGridCellAttr* attr = new wxGridCellAttr;
784  attr->SetReadOnly();
785  m_grid->SetColAttr( REFERENCE_FIELD, attr );
786 
787  // set footprint column browse button
788  attr = new wxGridCellAttr;
789  attr->SetEditor( new GRID_CELL_FOOTPRINT_ID_EDITOR( this ) );
790  m_grid->SetColAttr( FOOTPRINT_FIELD, attr );
791 
792  // set datasheet column viewer button
793  attr = new wxGridCellAttr;
794  attr->SetEditor( new GRID_CELL_URL_EDITOR( this ) );
795  m_grid->SetColAttr( DATASHEET_FIELD, attr );
796 
797  // set quantities column attributes
798  attr = new wxGridCellAttr;
799  attr->SetReadOnly();
800  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
801  m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
802  m_grid->AutoSizeColumns( false );
803 
804  for( int col = 0; col < m_grid->GetNumberCols(); ++col )
805  {
806  // Columns are hidden by setting their width to 0 so if we resize them they will
807  // become unhidden.
808  if( m_grid->IsColShown( col ) )
809  {
810  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
811  std::string key( m_dataModel->GetCanonicalColLabel( col ).ToUTF8() );
812 
813  if( cfg->m_FieldEditorPanel.column_widths.count( key ) )
814  {
815  int width = cfg->m_FieldEditorPanel.column_widths.at( key );
816  m_grid->SetColSize( col, width );
817  }
818  else
819  {
820  int textWidth = m_dataModel->GetDataWidth( col ) + COLUMN_MARGIN;
821  int maxWidth = defaultDlgSize.x / 3;
822 
823  if( col == m_grid->GetNumberCols() - 1 )
824  m_grid->SetColSize( col, std::min( std::max( 50, textWidth ), maxWidth ) );
825  else
826  m_grid->SetColSize( col, std::min( std::max( 100, textWidth ), maxWidth ) );
827  }
828  }
829  }
830 
831  m_grid->SelectRow( 0 );
832  m_grid->SetGridCursor( 0, 1 );
834 
835  m_sdbSizerOK->SetDefault();
836 
838  SetSize( defaultDlgSize );
839  Center();
840 
841  // Connect Events
842  m_grid->Connect( wxEVT_GRID_COL_SORT,
843  wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this );
844 }
845 
846 
848 {
849  // Disconnect Events
850  m_grid->Disconnect( wxEVT_GRID_COL_SORT,
851  wxGridEventHandler( DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort ), NULL, this );
852 
853  // Delete the GRID_TRICKS.
854  m_grid->PopEventHandler( true );
855 
856  // we gave ownership of m_dataModel to the wxGrid...
857 }
858 
859 
861 {
862  if( !wxDialog::TransferDataFromWindow() )
863  return false;
864 
865  TOOL_MANAGER* toolMgr = m_parent->GetToolManager();
866  EE_SELECTION_TOOL* selectionTool = toolMgr->GetTool<EE_SELECTION_TOOL>();
867  EE_SELECTION& selection = selectionTool->GetSelection();
868  SCH_COMPONENT* symbol = nullptr;
869 
870  if( selection.GetSize() == 1 )
871  {
872  EDA_ITEM* item = selection.Front();
873 
874  if( item->Type() == SCH_COMPONENT_T )
875  symbol = (SCH_COMPONENT*) item;
876  else if( item->GetParent() && item->GetParent()->Type() == SCH_COMPONENT_T )
877  symbol = (SCH_COMPONENT*) item->GetParent();
878  }
879 
880  if( symbol )
881  {
882  for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
883  {
884  std::vector<SCH_REFERENCE> references = m_dataModel->GetRowReferences( row );
885  bool found = false;
886 
887  for( const SCH_REFERENCE& ref : references )
888  {
889  if( ref.GetSymbol() == symbol )
890  {
891  found = true;
892  break;
893  }
894  }
895 
896  if( found )
897  {
898  m_grid->GoToCell( row, 1 );
899  break;
900  }
901  }
902  }
903 
904  return true;
905 }
906 
907 
909 {
910  if( !m_grid->CommitPendingChanges() )
911  return false;
912 
913  if( !wxDialog::TransferDataFromWindow() )
914  return false;
915 
916  SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet();
917 
919 
920  // Reset the view to where we left the user
921  m_parent->SetCurrentSheet( currentSheet );
922  m_parent->SyncView();
923  m_parent->Refresh();
924 
925  m_parent->OnModify();
926 
927  return true;
928 }
929 
930 
931 void DIALOG_FIELDS_EDITOR_GLOBAL::AddField( const wxString& aDisplayName,
932  const wxString& aCanonicalName,
933  bool defaultShow, bool defaultSortBy )
934 {
935  m_dataModel->AddColumn( aCanonicalName );
936 
937  wxVector<wxVariant> fieldsCtrlRow;
938 
939  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
940  bool show = defaultShow;
941  bool sort_by = defaultSortBy;
942 
943  std::string key( aCanonicalName.ToUTF8() );
944 
945  if( cfg->m_FieldEditorPanel.fields_show.count( key ) )
946  show = cfg->m_FieldEditorPanel.fields_show.at( key );
947 
948  if( cfg->m_FieldEditorPanel.fields_group_by.count( key ) )
949  sort_by = cfg->m_FieldEditorPanel.fields_group_by.at( key );
950 
951  // Don't change these to emplace_back: some versions of wxWidgets don't support it
952  fieldsCtrlRow.push_back( wxVariant( aDisplayName ) );
953  fieldsCtrlRow.push_back( wxVariant( show ) );
954  fieldsCtrlRow.push_back( wxVariant( sort_by ) );
955  fieldsCtrlRow.push_back( wxVariant( aCanonicalName ) );
956 
957  m_fieldsCtrl->AppendItem( fieldsCtrlRow );
958 }
959 
960 
966 {
967  std::set<wxString> userFieldNames;
968 
969  for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
970  {
971  SCH_COMPONENT* symbol = m_symbolsList[ i ].GetSymbol();
972 
973  for( int j = MANDATORY_FIELDS; j < symbol->GetFieldCount(); ++j )
974  userFieldNames.insert( symbol->GetField( j )->GetName() );
975  }
976 
977  // Force References to always be shown
978  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
979  wxCHECK( cfg, /*void*/ );
980 
981  cfg->m_FieldEditorPanel.fields_show["Reference"] = true;
982 
983  AddField( _( "Reference" ), wxT( "Reference" ), true, true );
984  AddField( _( "Value" ), wxT( "Value" ), true, true );
985  AddField( _( "Footprint" ), wxT( "Footprint" ), true, true );
986  AddField( _( "Datasheet" ), wxT( "Datasheet" ), true, false );
987 
988  for( const wxString& fieldName : userFieldNames )
989  AddField( fieldName, fieldName, true, false );
990 
991  // Add any templateFieldNames which aren't already present in the userFieldNames
992  for( const TEMPLATE_FIELDNAME& templateFieldname :
994  {
995  if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
996  AddField( templateFieldname.m_Name, templateFieldname.m_Name, false, false );
997  }
998 }
999 
1000 
1001 void DIALOG_FIELDS_EDITOR_GLOBAL::OnAddField( wxCommandEvent& event )
1002 {
1003  // quantities column will become new field column, so it needs to be reset
1004  auto attr = new wxGridCellAttr;
1005  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
1006  m_grid->SetColFormatCustom( m_dataModel->GetColsCount() - 1, wxGRID_VALUE_STRING );
1007 
1008  wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Add Field" ) );
1009 
1010  if( dlg.ShowModal() != wxID_OK )
1011  return;
1012 
1013  wxString fieldName = dlg.GetValue();
1014 
1015  if( fieldName.IsEmpty() )
1016  {
1017  DisplayError( this, _( "Field must have a name." ) );
1018  return;
1019  }
1020 
1021  for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
1022  {
1023  if( fieldName == m_dataModel->GetColLabelValue( i ) )
1024  {
1025  DisplayError( this, wxString::Format( _( "Field name \"%s\" already in use." ),
1026  fieldName ) );
1027  return;
1028  }
1029  }
1030 
1031  std::string key( fieldName.ToUTF8() );
1032 
1033  auto cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1034  cfg->m_FieldEditorPanel.fields_show[key] = true;
1035 
1036  AddField( fieldName, fieldName, true, false );
1037 
1038  wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_INSERTED,
1039  m_fieldsCtrl->GetItemCount(), 1 );
1040  m_grid->ProcessTableMessage( msg );
1041 
1042  // set up attributes on the new quantities column
1043  attr = new wxGridCellAttr;
1044  attr->SetReadOnly();
1045  m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
1046  m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
1047  m_grid->SetColSize( m_dataModel->GetColsCount() - 1, 50 );
1048 }
1049 
1050 
1052 {
1053  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1054  wxDataViewItem item = event.GetItem();
1055 
1056  int row = m_fieldsCtrl->ItemToRow( item );
1057  int col = event.GetColumn();
1058 
1059  switch ( col )
1060  {
1061  default:
1062  break;
1063 
1064  case SHOW_FIELD_COLUMN:
1065  {
1066  bool value = m_fieldsCtrl->GetToggleValue( row, col );
1067 
1068  if( row == REFERENCE_FIELD && !value )
1069  {
1070  DisplayError( this, _( "The Reference column cannot be hidden." ) );
1071 
1072  value = true;
1073  m_fieldsCtrl->SetToggleValue( value, row, col );
1074  }
1075 
1076  std::string fieldName( m_fieldsCtrl->GetTextValue( row, CANONICAL_NAME_COLUMN ).ToUTF8() );
1077  cfg->m_FieldEditorPanel.fields_show[fieldName] = value;
1078 
1079  if( value )
1080  m_grid->ShowCol( row );
1081  else
1082  m_grid->HideCol( row ); // grid's columns map to fieldsCtrl's rows
1083  break;
1084  }
1085 
1086  case GROUP_BY_COLUMN:
1087  {
1088  bool value = m_fieldsCtrl->GetToggleValue( row, col );
1089  std::string fieldName( m_fieldsCtrl->GetTextValue( row, CANONICAL_NAME_COLUMN ).ToUTF8() );
1090  cfg->m_FieldEditorPanel.fields_group_by[fieldName] = value;
1091 
1093  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1094  m_grid->ForceRefresh();
1095  break;
1096  }
1097  }
1098 }
1099 
1100 
1102 {
1104  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1105  m_grid->ForceRefresh();
1106 }
1107 
1108 
1109 void DIALOG_FIELDS_EDITOR_GLOBAL::OnColSort( wxGridEvent& aEvent )
1110 {
1111  int sortCol = aEvent.GetCol();
1112  bool ascending;
1113 
1114  // This is bonkers, but wxWidgets doesn't tell us ascending/descending in the
1115  // event, and if we ask it will give us pre-event info.
1116  if( m_grid->IsSortingBy( sortCol ) )
1117  // same column; invert ascending
1118  ascending = !m_grid->IsSortOrderAscending();
1119  else
1120  // different column; start with ascending
1121  ascending = true;
1122 
1123  m_dataModel->Sort( sortCol, ascending );
1124  m_grid->ForceRefresh();
1125 }
1126 
1127 
1129 {
1130  m_grid->ForceRefresh();
1131 }
1132 
1133 
1134 void DIALOG_FIELDS_EDITOR_GLOBAL::OnTableColSize( wxGridSizeEvent& aEvent )
1135 {
1136  EESCHEMA_SETTINGS* cfg = static_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
1137  int col = aEvent.GetRowOrCol();
1138  std::string key( m_dataModel->GetCanonicalColLabel( col ).ToUTF8() );
1139 
1140  if( m_grid->GetColSize( col ) )
1141  cfg->m_FieldEditorPanel.column_widths[ key ] = m_grid->GetColSize( col );
1142 
1143  aEvent.Skip();
1144 }
1145 
1146 
1148 {
1150  m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
1151  m_grid->ForceRefresh();
1152 }
1153 
1154 
1156 {
1157  if( event.GetCol() == REFERENCE_FIELD )
1158  {
1159  m_grid->ClearSelection();
1160  m_grid->SetGridCursor( event.GetRow(), event.GetCol() );
1161 
1162  m_dataModel->ExpandCollapseRow( event.GetRow() );
1163  std::vector<SCH_REFERENCE> refs = m_dataModel->GetRowReferences( event.GetRow() );
1164 
1165  // Focus Eeschema view on the symbol selected in the dialog
1166  if( refs.size() == 1 )
1167  {
1169 
1170  editor->FindComponentAndItem( refs[0].GetRef() + refs[0].GetRefNumber(), true,
1171  HIGHLIGHT_COMPONENT, wxEmptyString );
1172  }
1173  }
1174  else
1175  {
1176  event.Skip();
1177  }
1178 }
1179 
1180 
1182 {
1183  // TODO: Option to select footprint if FOOTPRINT column selected
1184 
1185  event.Skip();
1186 }
1187 
1188 
1190 {
1191  int nameColWidth = event.GetSize().GetX() - m_showColWidth
1193 
1194  // GTK loses its head and messes these up when resizing the splitter bar:
1195  m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN )->SetWidth( m_showColWidth );
1196  m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN )->SetWidth( m_groupByColWidth );
1197 
1198  m_fieldsCtrl->GetColumn( CANONICAL_NAME_COLUMN )->SetWidth( m_canonicalNameColWidth );
1199  m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( nameColWidth );
1200 
1201  event.Skip();
1202 }
1203 
1204 
1206 {
1207  if( TransferDataFromWindow() )
1208  m_parent->SaveProject();
1209 }
1210 
1211 
1212 void DIALOG_FIELDS_EDITOR_GLOBAL::OnCancel( wxCommandEvent& event )
1213 {
1214  Close();
1215 }
1216 
1217 
1218 void DIALOG_FIELDS_EDITOR_GLOBAL::OnClose( wxCloseEvent& event )
1219 {
1220  // This is a cancel, so commit quietly as we're going to throw the results away anyway.
1221  m_grid->CommitPendingChanges( true );
1222 
1223  if( m_dataModel->IsEdited() )
1224  {
1225  if( !HandleUnsavedChanges( this, _( "Save changes?" ),
1226  [&]()->bool { return TransferDataFromWindow(); } ) )
1227  {
1228  event.Veto();
1229  return;
1230  }
1231  }
1232 
1233  event.Skip();
1234 }
void SetCurrentSheet(const SCH_SHEET_PATH &aSheet)
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:240
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:202
bool GetAssociatedDocument(wxWindow *aParent, const wxString &aDocName, PROJECT *aProject)
Function GetAssociatedDocument open a document (file) with the suitable browser.
Definition: eda_doc.cpp:79
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:61
SCH_FIELD * FindField(const wxString &aFieldName, bool aIncludeDefaultFields=true)
Search for a SCH_FIELD with aFieldName.
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_holder.h:56
void OnColumnItemToggled(wxDataViewEvent &event) override
void AddColumn(const wxString &aFieldName)
void LoadFieldNames()
Constructs the rows of m_fieldsCtrl and the columns of m_dataModel from a union of all field names in...
SCH_SHEET_LIST GetSheets() const
Builds and returns an updated schematic hierarchy TODO: can this be cached?
Definition: schematic.h:97
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
The first 4 are mandatory, and must be instantiated in SCH_COMPONENT and LIB_PART constructors.
std::map< KIID, std::map< wxString, wxString > > m_dataStore
TEMPLATES m_TemplateFieldNames
void OnAddField(wxCommandEvent &event) override
Collection of utility functions for component reference designators (refdes)
GRID_TRICKS is used to add mouse and command handling (such as cut, copy, and paste) to a WX_GRID ins...
Definition: grid_tricks.h:52
int GetId() const
Definition: sch_field.h:120
Schematic editor (Eeschema) main window.
static wxString Shorthand(std::vector< SCH_REFERENCE > aList)
Function Shorthand Returns a shorthand string representing all the references in the list.
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:114
std::vector< SCH_REFERENCE > GetRowReferences(int aRow) const
void OnGroupSymbolsToggled(wxCommandEvent &event) override
name of datasheet
SCH_REFERENCE_LIST is used to create a flattened list of symbols because in a complex hierarchy,...
Field Value of part, i.e. "3.3K".
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:59
EE_SELECTION & GetSelection()
Function GetSelection()
int RefDesStringCompare(const wxString &aFirst, const wxString &aSecond)
Acts just like the strcmp function but treats numbers within the string text correctly for sorting.
SCH_EDITOR_CONTROL.
wxString GetRef() const
TOOL_MANAGER.
Definition: tool_manager.h:51
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp: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)
Finds a component in the schematic and an item in this component.
void OnSizeFieldList(wxSizeEvent &event) override
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
#define NULL
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:345
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:596
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:57
void SyncView()
Mark all items for refresh.
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
SCHEMATIC & Schematic() const
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, const wxPoint &aTransformPoint=wxPoint(0, 0))
Create a copy of the current schematic item, and put it in the undo list.
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void OnClose(wxCloseEvent &event) override
void OnTableCellClick(wxGridEvent &event) override
EDA_ITEM * GetParent() const
Definition: eda_item.h:183
void showPopupMenu(wxMenu &menu) override
bool unitMatch(const SCH_REFERENCE &lhRef, const SCH_REFERENCE &rhRef)
static const wxString GetDefaultFieldName(int aFieldNdx, bool aTranslate=true)
Function GetDefaultFieldName returns a default symbol field name for field aFieldNdx for all componen...
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:180
void Sort(int aColumn, bool ascending)
std::map< std::string, int > column_widths
int GetFieldCount() const
Return the number of fields in this symbol.
const BITMAP_OPAQUE refresh_xpm[1]
Definition: refresh.cpp:28
SCH_COMPONENT * GetSymbol() const
Field Name Module PCB, i.e. "16DIP300".
#define SHOW_FIELD_COLUMN
const KIID m_Uuid
Definition: eda_item.h:151
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
unsigned GetCount() const
SCH_FIELD * GetField(int aFieldNdx)
Returns a field in this symbol.
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
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.
FIELDS_EDITOR_GRID_DATA_MODEL * m_dataModel
virtual void doPopupSelection(wxCommandEvent &event)
#define QUANTITY_COLUMN
virtual void showPopupMenu(wxMenu &menu)
void SplitReferences()
Function SplitReferences attempts to split all reference designators into a name (U) and number (1).
#define _(s)
Definition: 3d_actions.cpp:33
static bool cmp(const DATA_MODEL_ROW &lhGroup, const DATA_MODEL_ROW &rhGroup, FIELDS_EDITOR_GRID_DATA_MODEL *dataModel, int sortCol, bool ascending)
wxString GetName(bool aUseDefaultName=true) const
Function GetName returns the field name.
Definition: sch_field.cpp:504
Schematic symbol object.
Definition: sch_component.h:79
wxPoint GetPosition() const override
void RemoveField(const wxString &aFieldName)
Removes a user field from the symbol.
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
#define COLUMN_MARGIN
Struct TEMPLATE_FIELDNAME holds a name of a component's field, field value, and default visibility.
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void SetValue(int aRow, int aCol, const wxString &aValue) override
#define GROUP_BY_COLUMN
SCH_SHEET_PATH & GetCurrentSheet() const
void OnTableColSize(wxGridSizeEvent &event) override
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:76
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)
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
Field Reference of part, i.e. "IC21".
void OnTableValueChanged(wxGridEvent &event) override
virtual bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
#define DISPLAY_NAME_COLUMN
void SetFootprint(const SCH_SHEET_PATH *sheet, const wxString &aFootprint)
const TEMPLATE_FIELDNAMES & GetTemplateFieldNames()
Function GetTemplateFieldName returns a template fieldnames list for read only access.
std::vector< DATA_MODEL_ROW > m_rows
SCH_REFERENCE is used as a helper to define a symbol's reference designator in a schematic.
KICAD_T Type() const
Function Type()
Definition: eda_item.h:181