KiCad PCB EDA Suite
Loading...
Searching...
No Matches
fields_data_model.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) 2023 <author>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#include <wx/string.h>
21#include <wx/debug.h>
22#include <wx/grid.h>
23#include <common.h>
24#include <widgets/wx_grid.h>
25#include <sch_reference_list.h>
26#include <sch_commit.h>
27#include <sch_screen.h>
28#include "string_utils.h"
29
30#include "fields_data_model.h"
31
32
34{
35 switch( aCol )
36 {
37 case DISPLAY_NAME_COLUMN: return _( "Field" );
38 case LABEL_COLUMN: return m_forBOM ? _( "BOM Name" ) : _( "Label" );
39 case SHOW_FIELD_COLUMN: return _( "Include" );
40 case GROUP_BY_COLUMN: return _( "Group By" );
41 default: return wxT( "unknown column" );
42 };
43}
44
45
46wxString VIEW_CONTROLS_GRID_DATA_MODEL::GetValue( int aRow, int aCol )
47{
48 wxCHECK( aRow < GetNumberRows(), wxT( "bad row!" ) );
49
50 BOM_FIELD& rowData = m_fields[aRow];
51
52 switch( aCol )
53 {
55 for( FIELD_T fieldId : MANDATORY_FIELDS )
56 {
57 if( GetDefaultFieldName( fieldId, !DO_TRANSLATE ) == rowData.name )
58 return GetDefaultFieldName( fieldId, DO_TRANSLATE );
59 }
60
61 return rowData.name;
62
63 case LABEL_COLUMN:
64 return rowData.label;
65
66 default:
67 // we can't assert here because wxWidgets sometimes calls this without checking
68 // the column type when trying to see if there's an overflow
69 return wxT( "bad wxWidgets!" );
70 }
71}
72
73
75{
76 wxCHECK( aRow < GetNumberRows(), false );
77
78 BOM_FIELD& rowData = m_fields[aRow];
79
80 switch( aCol )
81 {
82 case SHOW_FIELD_COLUMN: return rowData.show;
83 case GROUP_BY_COLUMN: return rowData.groupBy;
84
85 default:
86 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
87 return false;
88 }
89}
90
91
92void VIEW_CONTROLS_GRID_DATA_MODEL::SetValue( int aRow, int aCol, const wxString &aValue )
93{
94 wxCHECK( aRow < GetNumberRows(), /*void*/ );
95
96 BOM_FIELD& rowData = m_fields[aRow];
97
98 switch( aCol )
99 {
101 // Not editable
102 break;
103
104 case LABEL_COLUMN:
105 rowData.label = aValue;
106 break;
107
108 default:
109 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
110 }
111
112 GetView()->Refresh();
113}
114
115
116void VIEW_CONTROLS_GRID_DATA_MODEL::SetValueAsBool( int aRow, int aCol, bool aValue )
117{
118 wxCHECK( aRow < GetNumberRows(), /*void*/ );
119
120 BOM_FIELD& rowData = m_fields[aRow];
121
122 switch( aCol )
123 {
124 case SHOW_FIELD_COLUMN: rowData.show = aValue; break;
125 case GROUP_BY_COLUMN: rowData.groupBy = aValue; break;
126
127 default:
128 wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
129 }
130}
131
132
133void VIEW_CONTROLS_GRID_DATA_MODEL::AppendRow( const wxString& aFieldName, const wxString& aBOMName,
134 bool aShow, bool aGroupBy )
135{
136 m_fields.emplace_back( BOM_FIELD{ aFieldName, aBOMName, aShow, aGroupBy } );
137
138 if( wxGrid* grid = GetView() )
139 {
140 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, 1 );
141 grid->ProcessTableMessage( msg );
142 }
143}
144
145
147{
148 wxCHECK( aRow >= 0 && aRow < GetNumberRows(), /* void */ );
149
150 m_fields.erase( m_fields.begin() + aRow );
151
152 if( wxGrid* grid = GetView() )
153 {
154 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow, 1 );
155 grid->ProcessTableMessage( msg );
156 }
157}
158
159
161{
162 wxCHECK( aRow >= 0 && aRow < GetNumberRows(), wxEmptyString );
163
164 BOM_FIELD& rowData = m_fields[aRow];
165
166 return rowData.name;
167}
168
169
170void VIEW_CONTROLS_GRID_DATA_MODEL::SetCanonicalFieldName( int aRow, const wxString& aName )
171{
172 wxCHECK( aRow >= 0 && aRow < GetNumberRows(), /* void */ );
173
174 BOM_FIELD& rowData = m_fields[aRow];
175
176 rowData.name = aName;
177}
178
179
180const wxString FIELDS_EDITOR_GRID_DATA_MODEL::QUANTITY_VARIABLE = wxS( "${QUANTITY}" );
181const wxString FIELDS_EDITOR_GRID_DATA_MODEL::ITEM_NUMBER_VARIABLE = wxS( "${ITEM_NUMBER}" );
182
183
184void FIELDS_EDITOR_GRID_DATA_MODEL::AddColumn( const wxString& aFieldName, const wxString& aLabel,
185 bool aAddedByUser )
186{
187 // Don't add a field twice
188 if( GetFieldNameCol( aFieldName ) != -1 )
189 return;
190
191 m_cols.push_back( { aFieldName, aLabel, aAddedByUser, false, false } );
192
193 for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
194 {
195 if( SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol() )
196 updateDataStoreSymbolField( *symbol, aFieldName );
197 }
198}
199
200
202 const wxString& aFieldName )
203{
204 if( isAttribute( aFieldName ) )
205 {
206 m_dataStore[aSymbol.m_Uuid][aFieldName] = getAttributeValue( aSymbol, aFieldName );
207 }
208 else if( const SCH_FIELD* field = aSymbol.GetField( aFieldName ) )
209 {
210 if( field->IsPrivate() )
211 {
212 m_dataStore[aSymbol.m_Uuid][aFieldName] = wxEmptyString;
213 return;
214 }
215
216 wxString value = aSymbol.Schematic()->ConvertKIIDsToRefs( field->GetText() );
217 m_dataStore[aSymbol.m_Uuid][aFieldName] = value;
218 }
219 else if( IsGeneratedField( aFieldName ) )
220 {
221 // Handle generated fields with variables as names (e.g. ${QUANTITY}) that are not present in
222 // the symbol by giving them the correct value
223 m_dataStore[aSymbol.m_Uuid][aFieldName] = aFieldName;
224 }
225 else
226 {
227 m_dataStore[aSymbol.m_Uuid][aFieldName] = wxEmptyString;
228 }
229}
230
231
233{
234 for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
235 {
236 if( SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol() )
237 m_dataStore[symbol->m_Uuid].erase( m_cols[aCol].m_fieldName );
238 }
239
240 m_cols.erase( m_cols.begin() + aCol );
241}
242
243
244void FIELDS_EDITOR_GRID_DATA_MODEL::RenameColumn( int aCol, const wxString& newName )
245{
246 for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
247 {
248 SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol();
249
250 // Careful; field may have already been renamed from another sheet instance
251 if( auto node = m_dataStore[symbol->m_Uuid].extract( m_cols[aCol].m_fieldName ) )
252 {
253 node.key() = newName;
254 m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
255 }
256 }
257
258 m_cols[aCol].m_fieldName = newName;
259 m_cols[aCol].m_label = newName;
260}
261
262
263int FIELDS_EDITOR_GRID_DATA_MODEL::GetFieldNameCol( const wxString& aFieldName ) const
264{
265 for( size_t i = 0; i < m_cols.size(); i++ )
266 {
267 if( m_cols[i].m_fieldName == aFieldName )
268 return static_cast<int>( i );
269 }
270
271 return -1;
272}
273
274
276{
277 std::vector<BOM_FIELD> fields;
278
279 for( const DATA_MODEL_COL& col : m_cols )
280 fields.push_back( { col.m_fieldName, col.m_label, col.m_show, col.m_group } );
281
282 return fields;
283}
284
285
286void FIELDS_EDITOR_GRID_DATA_MODEL::SetFieldsOrder( const std::vector<wxString>& aNewOrder )
287{
288 size_t foundCount = 0;
289
290 for( const wxString& newField : aNewOrder )
291 {
292 if( foundCount >= m_cols.size() )
293 break;
294
295 for( DATA_MODEL_COL& col : m_cols )
296 {
297 if( col.m_fieldName == newField )
298 {
299 std::swap( m_cols[foundCount], col );
300 foundCount++;
301 break;
302 }
303 }
304 }
305}
306
307
308wxString FIELDS_EDITOR_GRID_DATA_MODEL::GetValue( int aRow, int aCol )
309{
310 if( ColIsReference( aCol ) )
311 {
312 // Poor-man's tree controls
313 if( m_rows[aRow].m_Flag == GROUP_COLLAPSED )
314 return wxT( "> " ) + GetValue( m_rows[aRow], aCol );
315 else if( m_rows[aRow].m_Flag == GROUP_EXPANDED )
316 return wxT( "v " ) + GetValue( m_rows[aRow], aCol );
317 else if( m_rows[aRow].m_Flag == CHILD_ITEM )
318 return wxT( " " ) + GetValue( m_rows[aRow], aCol );
319 else
320 return wxT( " " ) + GetValue( m_rows[aRow], aCol );
321 }
322 else
323 {
324 return GetValue( m_rows[aRow], aCol );
325 }
326}
327
328
329wxGridCellAttr* FIELDS_EDITOR_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
330{
332 || IsURL( GetValue( m_rows[aRow], aCol ) ) )
333 {
334 if( m_urlEditor )
335 {
336 m_urlEditor->IncRef();
337 return enhanceAttr( m_urlEditor, aRow, aCol, aKind );
338 }
339 }
340
341 return WX_GRID_TABLE_BASE::GetAttr( aRow, aCol, aKind );
342}
343
344
346 const wxString& refDelimiter,
347 const wxString& refRangeDelimiter,
348 bool resolveVars,
349 bool listMixedValues )
350{
351 std::vector<SCH_REFERENCE> references;
352 std::set<wxString> mixedValues;
353 wxString fieldValue;
354
355 for( const SCH_REFERENCE& ref : group.m_Refs )
356 {
357 if( ColIsReference( aCol ) || ColIsQuantity( aCol ) || ColIsItemNumber( aCol ) )
358 {
359 references.push_back( ref );
360 }
361 else // Other columns are either a single value or ROW_MULTI_ITEMS
362 {
363 const KIID& symbolID = ref.GetSymbol()->m_Uuid;
364
365 if( !m_dataStore.contains( symbolID ) || !m_dataStore[symbolID].contains( m_cols[aCol].m_fieldName ) )
366 return INDETERMINATE_STATE;
367
368 wxString refFieldValue = m_dataStore[symbolID][m_cols[aCol].m_fieldName];
369
370 if( resolveVars )
371 {
372 if( IsGeneratedField( m_cols[aCol].m_fieldName ) )
373 {
374 // Generated fields (e.g. ${QUANTITY}) can't have un-applied values as they're
375 // read-only. Resolve them against the field.
376 refFieldValue = getFieldShownText( ref, m_cols[aCol].m_fieldName );
377 }
378 else if( refFieldValue.Contains( wxT( "${" ) ) )
379 {
380 // Resolve variables in the un-applied value using the parent symbol and instance
381 // data.
382 std::function<bool( wxString* )> symbolResolver =
383 [&]( wxString* token ) -> bool
384 {
385 return ref.GetSymbol()->ResolveTextVar( &ref.GetSheetPath(), token );
386 };
387
388 refFieldValue = ExpandTextVars( refFieldValue, & symbolResolver );
389 }
390 }
391
392 if( listMixedValues )
393 mixedValues.insert( refFieldValue );
394 else if( &ref == &group.m_Refs.front() )
395 fieldValue = refFieldValue;
396 else if( fieldValue != refFieldValue )
397 return INDETERMINATE_STATE;
398 }
399 }
400
401 if( listMixedValues )
402 {
403 fieldValue = wxEmptyString;
404
405 for( const wxString& value : mixedValues )
406 {
407 if( value.IsEmpty() )
408 continue;
409 else if( fieldValue.IsEmpty() )
410 fieldValue = value;
411 else
412 fieldValue += "," + value;
413 }
414 }
415
416 if( ColIsReference( aCol ) || ColIsQuantity( aCol ) || ColIsItemNumber( aCol ) )
417 {
418 // Remove duplicates (other units of multi-unit parts)
419 std::sort( references.begin(), references.end(),
420 []( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
421 {
422 wxString l_ref( l.GetRef() << l.GetRefNumber() );
423 wxString r_ref( r.GetRef() << r.GetRefNumber() );
424 return StrNumCmp( l_ref, r_ref, true ) < 0;
425 } );
426
427 auto logicalEnd = std::unique( references.begin(), references.end(),
428 []( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
429 {
430 // If unannotated then we can't tell what units belong together
431 // so we have to leave them all
432 if( l.GetRefNumber() == wxT( "?" ) )
433 return false;
434
435 wxString l_ref( l.GetRef() << l.GetRefNumber() );
436 wxString r_ref( r.GetRef() << r.GetRefNumber() );
437 return l_ref == r_ref;
438 } );
439
440 references.erase( logicalEnd, references.end() );
441 }
442
443 if( ColIsReference( aCol ) )
444 fieldValue = SCH_REFERENCE_LIST::Shorthand( references, refDelimiter, refRangeDelimiter );
445 else if( ColIsQuantity( aCol ) )
446 fieldValue = wxString::Format( wxT( "%d" ), (int) references.size() );
447 else if( ColIsItemNumber( aCol ) && group.m_Flag != CHILD_ITEM )
448 fieldValue = wxString::Format( wxT( "%d" ), group.m_ItemNumber );
449
450 return fieldValue;
451}
452
453
454void FIELDS_EDITOR_GRID_DATA_MODEL::SetValue( int aRow, int aCol, const wxString& aValue )
455{
456 wxCHECK_RET( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), wxS( "Invalid column number" ) );
457
458 // Can't modify references or generated fields (e.g. ${QUANTITY})
459 if( ColIsReference( aCol )
460 || ( IsGeneratedField( m_cols[aCol].m_fieldName ) && !ColIsAttribute( aCol ) ) )
461 {
462 return;
463 }
464
465 DATA_MODEL_ROW& rowGroup = m_rows[aRow];
466
467 for( const SCH_REFERENCE& ref : rowGroup.m_Refs )
468 m_dataStore[ref.GetSymbol()->m_Uuid][m_cols[aCol].m_fieldName] = aValue;
469
470 m_edited = true;
471}
472
473
475{
476 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
477 return m_cols[aCol].m_fieldName == GetCanonicalFieldName( FIELD_T::REFERENCE );
478}
479
480
482{
483 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
484 return m_cols[aCol].m_fieldName == GetCanonicalFieldName( FIELD_T::VALUE );
485}
486
487
489{
490 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
491 return m_cols[aCol].m_fieldName == QUANTITY_VARIABLE;
492}
493
494
496{
497 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
498 return m_cols[aCol].m_fieldName == ITEM_NUMBER_VARIABLE;
499}
500
501
503{
504 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
505 return isAttribute( m_cols[aCol].m_fieldName );
506}
507
508
510 const DATA_MODEL_ROW& rhGroup,
511 FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol,
512 bool ascending )
513{
514 // Empty rows always go to the bottom, whether ascending or descending
515 if( lhGroup.m_Refs.size() == 0 )
516 return true;
517 else if( rhGroup.m_Refs.size() == 0 )
518 return false;
519
520 // N.B. To meet the iterator sort conditions, we cannot simply invert the truth
521 // to get the opposite sort. i.e. ~(a<b) != (a>b)
522 auto local_cmp =
523 [ ascending ]( const auto a, const auto b )
524 {
525 if( ascending )
526 return a < b;
527 else
528 return a > b;
529 };
530
531 // Primary sort key is sortCol; secondary is always REFERENCE (column 0)
532 if( sortCol < 0 || sortCol >= dataModel->GetNumberCols() )
533 sortCol = 0;
534
535 wxString lhs = dataModel->GetValue( lhGroup, sortCol ).Trim( true ).Trim( false );
536 wxString rhs = dataModel->GetValue( rhGroup, sortCol ).Trim( true ).Trim( false );
537
538 if( lhs == rhs || dataModel->ColIsReference( sortCol ) )
539 {
540 wxString lhRef = lhGroup.m_Refs[0].GetRef() + lhGroup.m_Refs[0].GetRefNumber();
541 wxString rhRef = rhGroup.m_Refs[0].GetRef() + rhGroup.m_Refs[0].GetRefNumber();
542 return local_cmp( StrNumCmp( lhRef, rhRef, true ), 0 );
543 }
544 else
545 {
546 return local_cmp( ValueStringCompare( lhs, rhs ), 0 );
547 }
548}
549
550
552{
554
555 // We're going to sort the rows based on their first reference, so the first reference
556 // had better be the lowest one.
557 for( DATA_MODEL_ROW& row : m_rows )
558 {
559 std::sort( row.m_Refs.begin(), row.m_Refs.end(),
560 []( const SCH_REFERENCE& lhs, const SCH_REFERENCE& rhs )
561 {
562 wxString lhs_ref( lhs.GetRef() << lhs.GetRefNumber() );
563 wxString rhs_ref( rhs.GetRef() << rhs.GetRefNumber() );
564 return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
565 } );
566 }
567
568 std::sort( m_rows.begin(), m_rows.end(),
569 [this]( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
570 {
571 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
572 } );
573
574 // Time to renumber the item numbers
575 int itemNumber = 1;
576 for( DATA_MODEL_ROW& row : m_rows )
577 {
578 row.m_ItemNumber = itemNumber++;
579 }
580
582}
583
584
586{
587 // If items are unannotated then we can't tell if they're units of the same symbol or not
588 if( lhRef.GetRefNumber() == wxT( "?" ) )
589 return false;
590
591 return ( lhRef.GetRef() == rhRef.GetRef() && lhRef.GetRefNumber() == rhRef.GetRefNumber() );
592}
593
594
596{
598 bool matchFound = false;
599
600 if( refCol == -1 )
601 return false;
602
603 // First check the reference column. This can be done directly out of the
604 // SCH_REFERENCEs as the references can't be edited in the grid.
605 if( m_cols[refCol].m_group )
606 {
607 // if we're grouping by reference, then only the prefix must match
608 if( lhRef.GetRef() != rhRef.GetRef() )
609 return false;
610
611 matchFound = true;
612 }
613
614 const KIID& lhRefID = lhRef.GetSymbol()->m_Uuid;
615 const KIID& rhRefID = rhRef.GetSymbol()->m_Uuid;
616
617 // Now check all the other columns.
618 for( size_t i = 0; i < m_cols.size(); ++i )
619 {
620 //Handled already
621 if( static_cast<int>( i ) == refCol )
622 continue;
623
624 if( !m_cols[i].m_group )
625 continue;
626
627 // If the field is generated (e.g. ${QUANTITY}), we need to resolve it through the symbol
628 // to get the actual current value; otherwise we need to pull it out of the store so the
629 // refresh can regroup based on values that haven't been applied to the schematic yet.
630 wxString lh, rh;
631
632 if( IsGeneratedField( m_cols[i].m_fieldName )
633 || IsGeneratedField( m_dataStore[lhRefID][m_cols[i].m_fieldName] ) )
634 {
635 lh = getFieldShownText( lhRef, m_cols[i].m_fieldName );
636 }
637 else
638 {
639 lh = m_dataStore[lhRefID][m_cols[i].m_fieldName];
640 }
641
642 if( IsGeneratedField( m_cols[i].m_fieldName )
643 || IsGeneratedField( m_dataStore[rhRefID][m_cols[i].m_fieldName] ) )
644 {
645 rh = getFieldShownText( rhRef, m_cols[i].m_fieldName );
646 }
647 else
648 {
649 rh = m_dataStore[rhRefID][m_cols[i].m_fieldName];
650 }
651
652 wxString fieldName = m_cols[i].m_fieldName;
653
654 if( lh != rh )
655 return false;
656
657 matchFound = true;
658 }
659
660 return matchFound;
661}
662
663
665 const wxString& aFieldName )
666{
667 SCH_FIELD* field = aRef.GetSymbol()->GetField( aFieldName );
668
669 if( field )
670 {
671 if( field->IsPrivate() )
672 return wxEmptyString;
673 else
674 return field->GetShownText( &aRef.GetSheetPath(), false );
675 }
676
677 // Handle generated fields with variables as names (e.g. ${QUANTITY}) that are not present in
678 // the symbol by giving them the correct value by resolving against the symbol
679 if( IsGeneratedField( aFieldName ) )
680 {
681 int depth = 0;
682 const SCH_SHEET_PATH& path = aRef.GetSheetPath();
683
684 std::function<bool( wxString* )> symbolResolver =
685 [&]( wxString* token ) -> bool
686 {
687 return aRef.GetSymbol()->ResolveTextVar( &path, token, depth + 1 );
688 };
689
690 return ExpandTextVars( aFieldName, &symbolResolver );
691 }
692
693 return wxEmptyString;
694}
695
696
697bool FIELDS_EDITOR_GRID_DATA_MODEL::isAttribute( const wxString& aFieldName )
698{
699 return aFieldName == wxS( "${DNP}" )
700 || aFieldName == wxS( "${EXCLUDE_FROM_BOARD}" )
701 || aFieldName == wxS( "${EXCLUDE_FROM_BOM}" )
702 || aFieldName == wxS( "${EXCLUDE_FROM_SIM}" );
703}
704
705
706wxString FIELDS_EDITOR_GRID_DATA_MODEL::getAttributeValue( const SCH_SYMBOL& aSymbol, const wxString& aAttributeName )
707{
708 if( aAttributeName == wxS( "${DNP}" ) )
709 return aSymbol.GetDNP() ? wxS( "1" ) : wxS( "0" );
710
711 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
712 return aSymbol.GetExcludedFromBoard() ? wxS( "1" ) : wxS( "0" );
713
714 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
715 return aSymbol.GetExcludedFromBOM() ? wxS( "1" ) : wxS( "0" );
716
717 if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
718 return aSymbol.GetExcludedFromSim() ? wxS( "1" ) : wxS( "0" );
719
720 return wxS( "0" );
721}
722
723
725 const wxString& aAttributeName,
726 const wxString& aValue )
727{
728 bool attrChanged = false;
729 bool newValue = aValue == wxS( "1" );
730
731 if( aAttributeName == wxS( "${DNP}" ) )
732 {
733 attrChanged = aSymbol.GetDNP() != newValue;
734 aSymbol.SetDNP( newValue );
735 }
736 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
737 {
738 attrChanged = aSymbol.GetExcludedFromBoard() != newValue;
739 aSymbol.SetExcludedFromBoard( newValue );
740 }
741 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
742 {
743 attrChanged = aSymbol.GetExcludedFromBOM() != newValue;
744 aSymbol.SetExcludedFromBOM( newValue );
745 }
746 else if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
747 {
748 attrChanged = aSymbol.GetExcludedFromSim() != newValue;
749 aSymbol.SetExcludedFromSim( newValue );
750 }
751
752 return attrChanged;
753}
754
755
760
761
766
767
769{
770 if( !m_rebuildsEnabled )
771 return;
772
773 if( GetView() )
774 {
775 // Commit any pending in-place edits before the row gets moved out from under
776 // the editor.
777 static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
778
779 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
780 GetView()->ProcessTableMessage( msg );
781 }
782
783 m_rows.clear();
784
785 EDA_COMBINED_MATCHER matcher( m_filter.Lower(), CTX_SEARCH );
786
787 for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
788 {
790
791 if( !m_filter.IsEmpty() && !matcher.Find( ref.GetFullRef().Lower() ) )
792 continue;
793
794 if( m_excludeDNP && ( ref.GetSymbol()->GetDNP()
795 || ref.GetSheetPath().GetDNP() ) )
796 {
797 continue;
798 }
799
801 || ref.GetSheetPath().GetExcludedFromBOM() ) )
802 {
803 continue;
804 }
805
806 // Check if the symbol if on the current sheet or, in the sheet path somewhere
807 // depending on scope
808 if( ( m_scope == SCOPE::SCOPE_SHEET && ref.GetSheetPath() != m_path )
809 || ( m_scope == SCOPE::SCOPE_SHEET_RECURSIVE
810 && !ref.GetSheetPath().IsContainedWithin( m_path ) ) )
811 {
812 continue;
813 }
814
815 bool matchFound = false;
816
817 // Performance optimization for ungrouped case to skip the N^2 for loop
818 if( !m_groupingEnabled && !ref.IsMultiUnit() )
819 {
820 m_rows.emplace_back( DATA_MODEL_ROW( ref, GROUP_SINGLETON ) );
821 continue;
822 }
823
824 // See if we already have a row which this symbol fits into
825 for( DATA_MODEL_ROW& row : m_rows )
826 {
827 // all group members must have identical refs so just use the first one
828 SCH_REFERENCE rowRef = row.m_Refs[0];
829
830 if( unitMatch( ref, rowRef ) )
831 {
832 matchFound = true;
833 row.m_Refs.push_back( ref );
834 break;
835 }
836 else if( m_groupingEnabled && groupMatch( ref, rowRef ) )
837 {
838 matchFound = true;
839 row.m_Refs.push_back( ref );
840 row.m_Flag = GROUP_COLLAPSED;
841 break;
842 }
843 }
844
845 if( !matchFound )
846 m_rows.emplace_back( DATA_MODEL_ROW( ref, GROUP_SINGLETON ) );
847 }
848
849 if( GetView() )
850 {
851 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
852 GetView()->ProcessTableMessage( msg );
853 }
854
855 Sort();
856}
857
858
860{
861 std::vector<DATA_MODEL_ROW> children;
862
863 for( SCH_REFERENCE& ref : m_rows[aRow].m_Refs )
864 {
865 bool matchFound = false;
866
867 // See if we already have a child group which this symbol fits into
868 for( DATA_MODEL_ROW& child : children )
869 {
870 // group members are by definition all matching, so just check
871 // against the first member
872 if( unitMatch( ref, child.m_Refs[0] ) )
873 {
874 matchFound = true;
875 child.m_Refs.push_back( ref );
876 break;
877 }
878 }
879
880 if( !matchFound )
881 children.emplace_back( DATA_MODEL_ROW( ref, CHILD_ITEM ) );
882 }
883
884 if( children.size() < 2 )
885 return;
886
887 std::sort( children.begin(), children.end(),
888 [this]( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
889 {
890 return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
891 } );
892
893 m_rows[aRow].m_Flag = GROUP_EXPANDED;
894 m_rows.insert( m_rows.begin() + aRow + 1, children.begin(), children.end() );
895
896 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, children.size() );
897 GetView()->ProcessTableMessage( msg );
898}
899
900
902{
903 auto firstChild = m_rows.begin() + aRow + 1;
904 auto afterLastChild = firstChild;
905 int deleted = 0;
906
907 while( afterLastChild != m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
908 {
909 deleted++;
910 afterLastChild++;
911 }
912
913 m_rows[aRow].m_Flag = GROUP_COLLAPSED;
914 m_rows.erase( firstChild, afterLastChild );
915
916 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
917 GetView()->ProcessTableMessage( msg );
918}
919
920
922{
923 DATA_MODEL_ROW& group = m_rows[aRow];
924
925 if( group.m_Flag == GROUP_COLLAPSED )
926 ExpandRow( aRow );
927 else if( group.m_Flag == GROUP_EXPANDED )
928 CollapseRow( aRow );
929}
930
931
933{
934 for( size_t i = 0; i < m_rows.size(); ++i )
935 {
936 if( m_rows[i].m_Flag == GROUP_EXPANDED )
937 {
938 CollapseRow( i );
940 }
941 }
942}
943
944
946{
947 for( size_t i = 0; i < m_rows.size(); ++i )
948 {
949 if( m_rows[i].m_Flag == GROUP_COLLAPSED_DURING_SORT )
950 ExpandRow( i );
951 }
952}
953
954
956{
957 bool symbolModified = false;
958 std::unique_ptr<SCH_SYMBOL> symbolCopy;
959
960 for( size_t i = 0; i < m_symbolsList.GetCount(); i++ )
961 {
962 SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol();
963 SCH_SYMBOL* nextSymbol = nullptr;
964
965 if( ( i + 1 ) < m_symbolsList.GetCount() )
966 nextSymbol = m_symbolsList[i + 1].GetSymbol();
967
968 if( i == 0 )
969 symbolCopy = std::make_unique<SCH_SYMBOL>( *symbol );
970
971 const std::map<wxString, wxString>& fieldStore = m_dataStore[symbol->m_Uuid];
972
973 for( const auto& [srcName, srcValue] : fieldStore )
974 {
975 // Attributes bypass the field logic, so handle them first
976 if( isAttribute( srcName ) )
977 {
978 symbolModified |= setAttributeValue( *symbol, srcName, srcValue );
979 continue;
980 }
981
982 // Skip generated fields with variables as names (e.g. ${QUANTITY});
983 // they can't be edited
984 if( IsGeneratedField( srcName ) )
985 continue;
986
987 SCH_FIELD* destField = symbol->GetField( srcName );
988
989 if( destField && destField->IsPrivate() )
990 {
991 if( srcValue.IsEmpty() )
992 continue;
993 else
994 destField->SetPrivate( false );
995 }
996
997 int col = GetFieldNameCol( srcName );
998 bool userAdded = ( col != -1 && m_cols[col].m_userAdded );
999
1000 // Add a not existing field if it has a value for this symbol
1001 bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
1002
1003 if( createField )
1004 {
1005 destField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, srcName ) );
1006 destField->SetTextAngle( symbol->GetField( FIELD_T::REFERENCE )->GetTextAngle() );
1007
1008 if( const TEMPLATE_FIELDNAME* srcTemplate = aTemplateFieldnames.GetFieldName( srcName ) )
1009 destField->SetVisible( srcTemplate->m_Visible );
1010 else
1011 destField->SetVisible( false );
1012
1013 destField->SetTextPos( symbol->GetPosition() );
1014 symbolModified = true;
1015 }
1016
1017 if( !destField )
1018 continue;
1019
1020 if( destField->GetId() == FIELD_T::REFERENCE )
1021 {
1022 // Reference is not editable from this dialog
1023 continue;
1024 }
1025
1026 wxString previousValue = destField->GetText();
1027
1028 destField->SetText( symbol->Schematic()->ConvertRefsToKIIDs( srcValue ) );
1029
1030 if( !createField && ( previousValue != srcValue ) )
1031 symbolModified = true;
1032 }
1033
1034 for( int ii = static_cast<int>( symbol->GetFields().size() ) - 1; ii >= 0; ii-- )
1035 {
1036 if( symbol->GetFields()[ii].IsMandatory() || symbol->GetFields()[ii].IsPrivate() )
1037 continue;
1038
1039 if( fieldStore.count( symbol->GetFields()[ii].GetName() ) == 0 )
1040 {
1041 symbol->GetFields().erase( symbol->GetFields().begin() + ii );
1042 symbolModified = true;
1043 }
1044 }
1045
1046 if( symbolModified && ( symbol != nextSymbol ) )
1047 aCommit.Modified( symbol, symbolCopy.release(), m_symbolsList[i].GetSheetPath().LastScreen() );
1048
1049 // Only reset the modified flag and next symbol copy if the next symbol is different from the current one.
1050 if( symbol != nextSymbol )
1051 {
1052 if( nextSymbol )
1053 symbolCopy = std::make_unique<SCH_SYMBOL>( *nextSymbol );
1054 else
1055 symbolCopy.reset( nullptr );
1056
1057 symbolModified = false;
1058 }
1059 }
1060
1061 m_edited = false;
1062}
1063
1064
1066{
1067 int width = 0;
1068
1069 if( ColIsReference( aCol ) )
1070 {
1071 for( int row = 0; row < GetNumberRows(); ++row )
1072 width = std::max( width, KIUI::GetTextSize( GetValue( row, aCol ), GetView() ).x );
1073 }
1074 else
1075 {
1076 wxString fieldName = GetColFieldName( aCol ); // symbol fieldName or Qty string
1077
1078 for( unsigned symbolRef = 0; symbolRef < m_symbolsList.GetCount(); ++symbolRef )
1079 {
1080 const KIID& symbolID = m_symbolsList[symbolRef].GetSymbol()->m_Uuid;
1081 wxString text = m_dataStore[symbolID][fieldName];
1082
1083 width = std::max( width, KIUI::GetTextSize( text, GetView() ).x );
1084 }
1085 }
1086
1087 return width;
1088}
1089
1090
1092{
1093 // Hide and un-group everything by default
1094 for( size_t i = 0; i < m_cols.size(); i++ )
1095 {
1096 SetShowColumn( i, false );
1097 SetGroupColumn( i, false );
1098 }
1099
1100 std::set<wxString> seen;
1101 std::vector<wxString> order;
1102
1103 // Set columns that are present and shown
1104 for( const BOM_FIELD& field : aPreset.fieldsOrdered )
1105 {
1106 // Ignore empty fields
1107 if( !field.name || seen.count( field.name ) )
1108 continue;
1109
1110 seen.insert( field.name );
1111 order.emplace_back( field.name );
1112
1113 int col = GetFieldNameCol( field.name );
1114
1115 // Add any missing fields, if the user doesn't add any data
1116 // they won't be saved to the symbols anyway
1117 if( col == -1 )
1118 {
1119 AddColumn( field.name, field.label, true );
1120 col = GetFieldNameCol( field.name );
1121 }
1122 else
1123 {
1124 SetColLabelValue( col, field.label );
1125 }
1126
1127 SetGroupColumn( col, field.groupBy );
1128 SetShowColumn( col, field.show );
1129 }
1130
1131 // Set grouping columns
1133
1134 SetFieldsOrder( order );
1135
1136 // Set our sorting
1137 int sortCol = GetFieldNameCol( aPreset.sortField );
1138
1139 if( sortCol == -1 )
1141
1142 SetSorting( sortCol, aPreset.sortAsc );
1143
1144 SetFilter( aPreset.filterString );
1145 SetExcludeDNP( aPreset.excludeDNP );
1147
1148 RebuildRows();
1149}
1150
1151
1153{
1154 BOM_PRESET current;
1155 current.readOnly = false;
1156 current.fieldsOrdered = GetFieldsOrdered();
1157
1158 if( GetSortCol() >= 0 && GetSortCol() < GetNumberCols() )
1159 current.sortField = GetColFieldName( GetSortCol() );
1160
1161 current.sortAsc = GetSortAsc();
1162 current.filterString = GetFilter();
1163 current.groupSymbols = GetGroupingEnabled();
1164 current.excludeDNP = GetExcludeDNP();
1166
1167 return current;
1168}
1169
1170
1172{
1173 wxString out;
1174
1175 if( m_cols.empty() )
1176 return out;
1177
1178 int last_col = -1;
1179
1180 // Find the location for the line terminator
1181 for( size_t col = 0; col < m_cols.size(); col++ )
1182 {
1183 if( m_cols[col].m_show )
1184 last_col = static_cast<int>( col );
1185 }
1186
1187 // No shown columns
1188 if( last_col == -1 )
1189 return out;
1190
1191 auto formatField =
1192 [&]( wxString field, bool last ) -> wxString
1193 {
1194 if( !settings.keepLineBreaks )
1195 {
1196 field.Replace( wxS( "\r" ), wxS( "" ) );
1197 field.Replace( wxS( "\n" ), wxS( "" ) );
1198 }
1199
1200 if( !settings.keepTabs )
1201 {
1202 field.Replace( wxS( "\t" ), wxS( "" ) );
1203 }
1204
1205 if( !settings.stringDelimiter.IsEmpty() )
1206 {
1207 field.Replace( settings.stringDelimiter,
1208 settings.stringDelimiter + settings.stringDelimiter );
1209 }
1210
1211 return settings.stringDelimiter + field + settings.stringDelimiter
1212 + ( last ? wxString( wxS( "\n" ) ) : settings.fieldDelimiter );
1213 };
1214
1215 // Column names
1216 for( size_t col = 0; col < m_cols.size(); col++ )
1217 {
1218 if( !m_cols[col].m_show )
1219 continue;
1220
1221 out.Append( formatField( m_cols[col].m_label, col == static_cast<size_t>( last_col ) ) );
1222 }
1223
1224 // Data rows
1225 for( size_t row = 0; row < m_rows.size(); row++ )
1226 {
1227 // Don't output child rows
1228 if( GetRowFlags( static_cast<int>( row ) ) == CHILD_ITEM )
1229 continue;
1230
1231 for( size_t col = 0; col < m_cols.size(); col++ )
1232 {
1233 if( !m_cols[col].m_show )
1234 continue;
1235
1236 // Get the unannotated version of the field, e.g. no "> " or "v " by
1237 out.Append( formatField( GetExportValue( static_cast<int>( row ), static_cast<int>( col ),
1238 settings.refDelimiter, settings.refRangeDelimiter ),
1239 col == static_cast<size_t>( last_col ) ) );
1240 }
1241 }
1242
1243 return out;
1244}
1245
1246
1248{
1249 bool refListChanged = false;
1250
1251 for( const SCH_REFERENCE& ref : aRefs )
1252 {
1253 if( !m_symbolsList.Contains( ref ) )
1254 {
1255 SCH_SYMBOL* symbol = ref.GetSymbol();
1256
1257 m_symbolsList.AddItem( ref );
1258
1259 // Update the fields of every reference
1260 for( const SCH_FIELD& field : symbol->GetFields() )
1261 {
1262 if( !field.IsPrivate() )
1263 {
1264 wxString name = field.GetCanonicalName();
1265 wxString value = symbol->Schematic()->ConvertKIIDsToRefs( field.GetText() );
1266
1267 m_dataStore[symbol->m_Uuid][name] = value;
1268 }
1269 }
1270
1271 refListChanged = true;
1272 }
1273 }
1274
1275 if( refListChanged )
1276 m_symbolsList.SortBySymbolPtr();
1277}
1278
1279
1281{
1282 // The schematic event listener passes us the symbol after it has been removed,
1283 // so we can't just work with a SCH_REFERENCE_LIST like the other handlers as the
1284 // references are already gone. Instead we need to prune our list.
1285 m_dataStore[aSymbol.m_Uuid].clear();
1286
1287 // Remove all refs that match this symbol using remove_if
1288 m_symbolsList.erase( std::remove_if( m_symbolsList.begin(), m_symbolsList.end(),
1289 [&aSymbol]( const SCH_REFERENCE& ref ) -> bool
1290 {
1291 return ref.GetSymbol()->m_Uuid == aSymbol.m_Uuid;
1292 } ),
1293 m_symbolsList.end() );
1294}
1295
1296
1298{
1299 for( const SCH_REFERENCE& ref : aRefs )
1300 {
1301 int index = m_symbolsList.FindRefByFullPath( ref.GetFullPath() );
1302
1303 if( index != -1 )
1304 {
1305 m_symbolsList.RemoveItem( index );
1306
1307 // If we're out of instances then remove the symbol, too
1308 if( ref.GetSymbol()->GetInstances().empty() )
1309 m_dataStore.erase( ref.GetSymbol()->m_Uuid );
1310 }
1311 }
1312}
1313
1314
1316{
1317 bool refListChanged = false;
1318
1319 for( const SCH_REFERENCE& ref : aRefs )
1320 {
1321 // Update the fields of every reference. Do this by iterating through the data model
1322 // columns; we must have all fields in the symbol added to the data model at this point,
1323 // and some of the data model columns may be variables that are not present in the symbol
1324 for( const DATA_MODEL_COL& col : m_cols )
1325 updateDataStoreSymbolField( *ref.GetSymbol(), col.m_fieldName );
1326
1327 if( !m_symbolsList.Contains( ref ) )
1328 {
1329 m_symbolsList.AddItem( ref );
1330 refListChanged = true;
1331 }
1332 }
1333
1334 if( refListChanged )
1335 m_symbolsList.SortBySymbolPtr();
1336}
const char * name
COMMIT & Modified(EDA_ITEM *aItem, EDA_ITEM *aCopy, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition commit.cpp:156
bool Find(const wxString &aTerm, int &aMatchersTriggered, int &aPosition)
Look in all existing matchers, return the earliest match of any of the existing.
const KIID m_Uuid
Definition eda_item.h:516
const EDA_ANGLE & GetTextAngle() const
Definition eda_text.h:146
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:97
void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:579
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:387
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:300
int GetFieldNameCol(const wxString &aFieldName) const
std::vector< DATA_MODEL_ROW > m_rows
void ApplyBomPreset(const BOM_PRESET &preset)
void SetFieldsOrder(const std::vector< wxString > &aNewOrder)
SCH_REFERENCE_LIST m_symbolsList
The flattened by hierarchy list of symbols.
wxString getAttributeValue(const SCH_SYMBOL &, const wxString &aAttributeName)
void updateDataStoreSymbolField(const SCH_SYMBOL &aSymbol, const wxString &aFieldName)
bool groupMatch(const SCH_REFERENCE &lhRef, const SCH_REFERENCE &rhRef)
bool unitMatch(const SCH_REFERENCE &lhRef, const SCH_REFERENCE &rhRef)
wxString GetExportValue(int aRow, int aCol, const wxString &refDelimiter, const wxString &refRangeDelimiter)
wxString getFieldShownText(const SCH_REFERENCE &aRef, const wxString &aFieldName)
void RenameColumn(int aCol, const wxString &newName)
FIELDS_EDITOR_GRID_DATA_MODEL(const SCH_REFERENCE_LIST &aSymbolsList, wxGridCellAttr *aURLEditor)
wxString Export(const BOM_FMT_PRESET &settings)
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser)
std::vector< DATA_MODEL_COL > m_cols
void SetSorting(int aCol, bool ascending)
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
void SetFilter(const wxString &aFilter)
bool setAttributeValue(SCH_SYMBOL &aSymbol, const wxString &aAttributeName, const wxString &aValue)
Set the attribute value.
static bool cmp(const DATA_MODEL_ROW &lhGroup, const DATA_MODEL_ROW &rhGroup, FIELDS_EDITOR_GRID_DATA_MODEL *dataModel, int sortCol, bool ascending)
static const wxString ITEM_NUMBER_VARIABLE
void ApplyData(SCH_COMMIT &aCommit, TEMPLATES &aTemplateFieldnames)
void SetIncludeExcludedFromBOM(bool include)
bool isAttribute(const wxString &aFieldName)
wxString GetValue(int aRow, int aCol) override
void UpdateReferences(const SCH_REFERENCE_LIST &aRefs)
std::map< KIID, std::map< wxString, wxString > > m_dataStore
static const wxString QUANTITY_VARIABLE
void SetGroupColumn(int aCol, bool group)
void RemoveSymbol(const SCH_SYMBOL &aSymbol)
std::vector< BOM_FIELD > GetFieldsOrdered()
void SetValue(int aRow, int aCol, const wxString &aValue) override
void SetColLabelValue(int aCol, const wxString &aLabel) override
void RemoveReferences(const SCH_REFERENCE_LIST &aRefs)
void SetShowColumn(int aCol, bool show)
void AddReferences(const SCH_REFERENCE_LIST &aRefs)
Definition kiid.h:49
wxString ConvertKIIDsToRefs(const wxString &aSource) const
wxString ConvertRefsToKIIDs(const wxString &aSource) const
FIELD_T GetId() const
Definition sch_field.h:116
wxString GetShownText(const SCH_SHEET_PATH *aPath, bool aAllowExtraText, int aDepth=0) const
void SetText(const wxString &aText) override
void SetPrivate(bool aPrivate)
Definition sch_item.h:249
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition sch_item.cpp:217
bool IsPrivate() const
Definition sch_item.h:250
Container to create a flattened list of symbols because in a complex hierarchy, a symbol can be used ...
static wxString Shorthand(std::vector< SCH_REFERENCE > aList, const wxString &refDelimiter, const wxString &refRangeDelimiter)
Return a shorthand string representing all the references in the list.
A helper to define a symbol's reference designator in a schematic.
const SCH_SHEET_PATH & GetSheetPath() const
SCH_SYMBOL * GetSymbol() const
wxString GetRef() const
wxString GetFullRef(bool aIncludeUnit=true) const
Return reference name with unit altogether.
bool IsMultiUnit() const
wxString GetRefNumber() const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
bool GetExcludedFromBOM() const
bool IsContainedWithin(const SCH_SHEET_PATH &aSheetPathToTest) const
Check if this path is contained inside aSheetPathToTest.
bool GetDNP() const
Schematic symbol object.
Definition sch_symbol.h:75
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
VECTOR2I GetPosition() const override
Definition sch_symbol.h:760
bool ResolveTextVar(const SCH_SHEET_PATH *aPath, wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the symbol.
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
void SetExcludedFromBoard(bool aExcludeFromBoard) override
Set or clear exclude from board netlist flag.
Definition symbol.h:191
void SetDNP(bool aDNP) override
Definition symbol.h:198
void SetExcludedFromSim(bool aExcludeFromSim) override
Set or clear the exclude from simulation flag.
Definition symbol.h:175
bool GetExcludedFromBoard() const override
Definition symbol.h:192
void SetExcludedFromBOM(bool aExcludeFromBOM) override
Set or clear the exclude from schematic bill of materials flag.
Definition symbol.h:185
bool GetDNP() const override
Set or clear the 'Do Not Populate' flag.
Definition symbol.h:197
bool GetExcludedFromBOM() const override
Definition symbol.h:186
bool GetExcludedFromSim() const override
Definition symbol.h:180
const TEMPLATE_FIELDNAME * GetFieldName(const wxString &aName)
Search for aName in the template field name list.
void SetValueAsBool(int aRow, int aCol, bool aValue) override
wxString GetColLabelValue(int aCol) override
std::vector< BOM_FIELD > m_fields
void SetValue(int aRow, int aCol, const wxString &aValue) override
void AppendRow(const wxString &aFieldName, const wxString &aBOMName, bool aShow, bool aGroupBy)
bool GetValueAsBool(int aRow, int aCol) override
void SetCanonicalFieldName(int aRow, const wxString &aName)
wxString GetValue(int aRow, int aCol) override
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
Definition wx_grid.cpp:45
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
Definition wx_grid.h:57
wxString ExpandTextVars(const wxString &aSource, const PROJECT *aProject, int aFlags)
Definition common.cpp:59
bool IsGeneratedField(const wxString &aSource)
Returns true if the string is generated, e.g contains a single text var reference.
Definition common.cpp:136
The common library.
#define _(s)
@ CTX_SEARCH
@ GROUP_COLLAPSED_DURING_SORT
@ GROUP_EXPANDED
@ GROUP_COLLAPSED
@ GROUP_SINGLETON
@ CHILD_ITEM
#define LABEL_COLUMN
#define DISPLAY_NAME_COLUMN
#define GROUP_BY_COLUMN
#define SHOW_FIELD_COLUMN
KICOMMON_API 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:78
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
int ValueStringCompare(const wxString &strFWord, const wxString &strSWord)
Compare strings like the strcmp function but handle numbers and modifiers within the string text corr...
bool IsURL(wxString aStr)
Performs a URL sniff-test on a string.
wxString label
wxString name
wxString fieldDelimiter
wxString stringDelimiter
wxString refRangeDelimiter
wxString refDelimiter
wxString sortField
bool groupSymbols
std::vector< BOM_FIELD > fieldsOrdered
bool includeExcludedFromBOM
bool excludeDNP
wxString filterString
std::vector< SCH_REFERENCE > m_Refs
Hold a name of a symbol's field, field value, and default visibility.
wxString GetDefaultFieldName(FIELD_T aFieldId, bool aTranslateForHI)
Return a default symbol field name for a mandatory field type.
#define DO_TRANSLATE
#define MANDATORY_FIELDS
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
wxString GetCanonicalFieldName(FIELD_T aFieldType)
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46