KiCad PCB EDA Suite
Loading...
Searching...
No Matches
footprint_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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <algorithm>
21#include <memory>
22
23#include <wx/string.h>
24#include <wx/debug.h>
25#include <wx/grid.h>
26#include <wx/settings.h>
27#include <common.h>
28#include <core/kicad_algo.h>
29#include <widgets/wx_grid.h>
30#include <board.h>
31#include <board_commit.h>
32#include <eda_group.h>
33#include <footprint.h>
34#include <pcb_field.h>
35#include <template_fieldnames.h>
36#include <kiid.h>
37#include "string_utils.h"
38
40
41
42const wxString LIB_FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::FOOTPRINT_NAME = wxS( "${FOOTPRINT_NAME}" );
43const wxString LIB_FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::FOOTPRINT_KEYWORDS = wxS( "${FOOTPRINT_KEYWORDS}" );
45 wxS( "${FOOTPRINT_LIBRARY_DESCRIPTION}" );
46
47
52{
53 KIID_PATH key;
54 key.push_back( aItem.GetFootprint().m_Uuid );
55 return key;
56}
57
58
63
64
65wxGridCellAttr* FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
66{
67 wxGridCellAttr* attr = nullptr;
68 bool needsReadOnly = IsCellReadOnly( aRow, aCol );
69 bool needsUrlEditor = cellUsesUrlEditor( aRow, aCol );
70 bool needsVariantHighlight = false;
71 bool needsResolvedTextRenderer = cellUsesResolvedTextRenderer( aRow, aCol );
72 wxColour highlightColor;
73
74 // Check if we need variant highlighting
75 if( !m_currentVariant.IsEmpty() && aRow >= 0 && aRow < (int) m_rows.size() && aCol >= 0
76 && aCol < (int) m_cols.size() )
77 {
78 const wxString& fieldName = m_cols[aCol].m_fieldName;
79
80 // Skip Reference and generated fields (like ${QUANTITY}) for highlighting
81 if( !ColIsReference( aCol ) && !ColIsQuantity( aCol ) && !ColIsItemNumber( aCol ) )
82 {
84
85 // Check if any footprint in this row has a variant-specific value
86 for( const FOOTPRINT_REF& ref : row.m_items )
87 {
88 wxString defaultValue = getDefaultFieldValue( ref, fieldName );
89
90 // Get the current value from the data store
91 wxString currentValue;
92
93 getStoredFieldValue( ref, fieldName, currentValue );
94
95 if( currentValue != defaultValue )
96 {
97 needsVariantHighlight = true;
98
99 wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
100 bool isDark = ( bg.Red() + bg.Green() + bg.Blue() ) < 384;
101
104
105 break;
106 }
107 }
108 }
109 }
110
111 // If we don't need any custom attributes, use the base class behavior
112 if( !needsReadOnly && !needsUrlEditor && !needsVariantHighlight && !needsResolvedTextRenderer )
113 return applyCellDecorations( WX_GRID_TABLE_BASE::GetAttr( aRow, aCol, aKind ), aRow, aCol );
114
115 // URL cells use the Datasheet column's editor. Other cells use their own column attributes.
116 if( needsUrlEditor )
117 {
118 attr = cloneUrlEditorAttr();
119 }
120 else if( m_colAttrs.find( aCol ) != m_colAttrs.end() && m_colAttrs[aCol] )
121 {
122 attr = m_colAttrs[aCol]->Clone();
123 }
124 else
125 {
126 attr = new wxGridCellAttr();
127 }
128
129 if( needsReadOnly )
130 attr->SetReadOnly();
131
132 if( needsVariantHighlight )
133 attr->SetBackgroundColour( highlightColor );
134
135 if( needsResolvedTextRenderer )
136 applyResolvedTextRenderer( attr, !needsVariantHighlight );
137
138 return applyCellDecorations( enhanceAttr( attr, aRow, aCol, aKind ), aRow, aCol );
139}
140
141
142void FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::SetValue( int aRow, int aCol, const wxString& aValue )
143{
144 wxCHECK_RET( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), wxS( "Invalid column number" ) );
145
146 if( IsCellReadOnly( aRow, aCol ) )
147 return;
148
149 if( aValue == INDETERMINATE_STATE )
150 return;
151
153 const wxString& fieldName = m_cols[aCol].m_fieldName;
154
155 for( const FOOTPRINT_REF& ref : row.m_items )
156 setStoredFieldValue( ref, fieldName, aValue );
157
158 m_edited = true;
159}
160
161
163{
165 || ColIsFootprint( aCol )
166 || m_cols[aCol].m_fieldName == wxS( "${EXCLUDE_FROM_BOARD}" );
167}
168
169
171{
172 // Footprints are just pointers and never have multiple units unlike symbols
173 // so just compare
174 return lhItem == rhItem;
175}
176
177
179 const wxString& aFieldName,
180 wxString& aValue )
181{
182 return getLiveFieldValueForVariant( aRef, aFieldName, m_currentVariant, aValue );
183}
184
185
187{
188 return m_footprintsList;
189}
190
191
193 const wxString& aFieldName )
194{
195 FOOTPRINT& footprint = aRef.GetFootprint();
196 PCB_FIELD* field = footprint.GetField( aFieldName );
197
198 if( field )
199 {
200 if( field->IsPrivate() )
201 return wxEmptyString;
202 else
203 return field->GetShownText( INTERNAL, 0 );
204 }
205
206 // Handle generated fields with variables as names (e.g. ${QUANTITY}) that are not present in
207 // the footprint by giving them the correct value by resolving against the footprint
208 if( IsGeneratedField( aFieldName ) )
209 {
210 int depth = 0;
211
212 std::function<bool( wxString* )> footprintResolver =
213 [&]( wxString* token ) -> bool
214 {
215 return footprint.ResolveTextVar( token, m_currentVariant, depth + 1 );
216 };
217
218 return ResolveTextVars( aFieldName, &footprintResolver, depth );
219 }
220
221 return wxEmptyString;
222}
223
224
226{
227 // TODO: this isn't technically correct, this should resolve against the
228 // data store's copy of variables whenever whenever possible,
229 // but currently it is resolving against the footprint's current values.
230 // For instance, if you have "My value is ${VALUE}" in the description field,
231 // ${VALUE} will be resolved against the footprint's live value, not the Value field
232 // stored in the data store.
233 std::function<bool( wxString* )> footprintResolver =
234 [&]( wxString* token ) -> bool
235 {
236 return aRef.GetFootprint().ResolveTextVar( token, m_currentVariant );
237 };
238
239 int depth = 0;
240 return ResolveTextVars( aText, &footprintResolver, depth );
241}
242
243
245 const wxString& aAttributeName,
246 const wxString& aVariantName )
247{
248 if( aAttributeName == wxS( "${DNP}" ) )
249 return aRef.GetFootprint().GetDNPForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
250
251 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
252 return wxS( "0" );
253
254 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
255 return aRef.GetFootprint().GetExcludedFromBOMForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
256
257 if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
258 return aRef.GetFootprint().GetExcludedFromSimForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
259
260 if( aAttributeName == wxS( "${EXCLUDE_FROM_POS_FILES}" ) )
261 return aRef.GetFootprint().GetExcludedFromPosFilesForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
262
263 return wxS( "0" );
264}
265
266
268{
269 // TODO: So if a symbol has DNP set to false, and the sheet is in has DNP set to true,
270 // the symbol will be effectively DNP true. This will propogate to the footprint correctly.
271 //
272 // The symbol fields table dialog shows the overridden sheet-inherited value and does not let
273 // the user modify the symbol DNP value.
274 //
275 // The footprint fields table WILL allow the user to modify the footprint DNP value,
276 // which will be overridden whenever they sync-to-board.
277 //
278 // To have similar behavior we will eventually need to track whether these attributes on
279 // footprints came from the symbol or the sheet.
280 return false;
281}
282
283
285 const wxString& aFieldName,
286 const wxString& aVariantName,
287 wxString& aValue )
288{
289 aValue.clear();
290
291 const FOOTPRINT& footprint = aRef.GetFootprint();
292
293 if( fieldIsAttribute( aFieldName ) )
294 {
295 aValue = getAttributeValue( aRef, aFieldName, aVariantName );
296 return true;
297 }
298
300 {
301 aValue = footprint.GetFPIDAsString();
302 return true;
303 }
304
305 if( const PCB_FIELD* field = footprint.GetField( aFieldName ) )
306 {
307 if( field->IsPrivate() )
308 return false;
309
310 aValue = footprint.GetFieldValueForVariant( aVariantName, aFieldName );
311
312 if( footprint.GetBoard() )
313 // Cross part references e.g. ${U2:MyField} stored in U1 are converted
314 // to KIIDs transparently e.g. ${KIID:MyField} so reannotating U2->U3 doesn't
315 // break the the variable resolution
316 aValue = footprint.GetBoard()->ConvertKIIDsToCrossReferences( aValue );
317
318 return true;
319 }
320
321 // For generated fields, return the field name itself
322 if( IsGeneratedField( aFieldName ) )
323 {
324 aValue = aFieldName;
325 return true;
326 }
327
328 return false;
329}
330
331
333 const wxString& aFieldName )
334{
335 wxString value;
336 getLiveFieldValueForVariant( aRef, aFieldName, wxEmptyString, value );
337 return value;
338}
339
340
342 const wxString& aAttributeName,
343 const wxString& aValue,
344 const wxString& aVariantName )
345{
346 bool attrChanged = false;
347 bool newValue = aValue == wxS( "1" );
348 bool defaultVariant = aVariantName.IsEmpty()
349 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0;
350
351 if( aAttributeName == wxS( "${DNP}" ) )
352 {
353 attrChanged = aRef.GetFootprint().GetDNPForVariant( aVariantName ) != newValue;
354
355 if( attrChanged )
356 {
357 // TODO: fix footprint API to match symbol
358 if( defaultVariant )
359 aRef.GetFootprint().SetDNP( newValue );
360 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
361 variant->SetDNP( newValue );
362 }
363 }
364 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
365 {
366 attrChanged = false;
367 }
368 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
369 {
370 attrChanged = aRef.GetFootprint().GetExcludedFromBOMForVariant( aVariantName ) != newValue;
371
372 if( attrChanged )
373 {
374 // TODO: fix footprint API to match symbol
375 if( defaultVariant )
376 aRef.GetFootprint().SetExcludedFromBOM( newValue );
377 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
378 variant->SetExcludedFromBOM( newValue );
379 }
380 }
381 else if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
382 {
383 attrChanged = aRef.GetFootprint().GetExcludedFromSimForVariant( aVariantName ) != newValue;
384
385 if( attrChanged )
386 {
387 // TODO: fix footprint API to match symbol
388 if( defaultVariant )
389 aRef.GetFootprint().SetExcludedFromSim( newValue );
390 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
391 variant->SetExcludedFromSim( newValue );
392 }
393 }
394 else if( aAttributeName == wxS( "${EXCLUDE_FROM_POS_FILES}" ) )
395 {
396 attrChanged = aRef.GetFootprint().GetExcludedFromPosFilesForVariant( aVariantName ) != newValue;
397
398 if( attrChanged )
399 {
400 // TODO: fix footprint API to match symbol
401 if( defaultVariant )
402 aRef.GetFootprint().SetExcludedFromPosFiles( newValue );
403 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
404 variant->SetExcludedFromPosFiles( newValue );
405 }
406 }
407
408 return attrChanged;
409}
410
411
413{
414 if( !m_rebuildsEnabled )
415 return;
416
417 if( GetView() )
418 {
419 // Commit any pending in-place edits before the row gets moved out from under
420 // the editor.
421 static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
422
423 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
424 GetView()->ProcessTableMessage( msg );
425 }
426
427 m_rows.clear();
428
429 EDA_COMBINED_MATCHER matcher( m_filter.Lower(), CTX_SEARCH );
430
431 for( const FOOTPRINT_REF& ref : m_footprintsList )
432 {
433 const FOOTPRINT& footprint = ref.GetFootprint();
434
435 if( m_scope == SCOPE::SCOPE_SELECTION
436 && !m_selectionItems.contains( getDataStoreKey( ref ) ) )
437 {
438 continue;
439 }
440
441 if( !MatchesFilter( ref, getItemIdentifier( ref ), matcher ) )
442 continue;
443
444 if( m_excludeDNP )
445 {
446 bool isDNP = false;
447
448 if( !m_variantNames.empty() )
449 {
450 for( const wxString& variantName : m_variantNames )
451 {
452 if( footprint.GetDNPForVariant( variantName ) )
453 {
454 isDNP = true;
455 break;
456 }
457 }
458 }
459 else
460 {
461 isDNP = footprint.GetDNPForVariant( m_currentVariant );
462 }
463
464 if( isDNP )
465 continue;
466 }
467
468 if( !m_includeExcluded )
469 {
470 bool isExcluded = false;
471
472 if( !m_variantNames.empty() )
473 {
474 for( const wxString& variantName : m_variantNames )
475 {
476 if( footprint.GetExcludedFromBOMForVariant( variantName ) )
477 {
478 isExcluded = true;
479 break;
480 }
481 }
482 }
483 else
484 {
485 isExcluded = footprint.GetExcludedFromBOMForVariant( m_currentVariant );
486 }
487
488 if( isExcluded )
489 continue;
490 }
491
492 KIID_PATH footprintSheetPath = footprint.GetPath();
493
494 if( !footprintSheetPath.empty() )
495 footprintSheetPath.pop_back();
496
497 if( ( m_scope == SCOPE::SCOPE_SHEET && footprintSheetPath != m_path )
498 || ( m_scope == SCOPE::SCOPE_SHEET_RECURSIVE
499 && !footprintSheetPath.IsContainedWithin( m_path ) ) )
500 {
501 continue;
502 }
503
504 bool matchFound = false;
505
506 // Performance optimization for ungrouped case to skip the N^2 for loop
507 if( !m_groupingEnabled )
508 {
509 m_rows.emplace_back( FOOTPRINT_FIELDS_TABLE_DATA_MODEL_ROW( ref, ROW_STATE::NON_EXPANDABLE ) );
510 continue;
511 }
512
513 // See if we already have a row which this footprint fits into
515 {
516 // all group members must have identical refs so just use the first one
517 const FOOTPRINT_REF& rowRef = row.m_items[0];
518
519 if( unitMatch( ref, rowRef ) )
520 {
521 matchFound = true;
522 row.m_items.push_back( ref );
523 break;
524 }
525 else if( m_groupingEnabled && groupMatch( ref, rowRef ) )
526 {
527 matchFound = true;
528 row.m_items.push_back( ref );
529 row.m_state = ROW_STATE::COLLAPSED;
530 break;
531 }
532 }
533
534 if( !matchFound )
535 m_rows.emplace_back( FOOTPRINT_FIELDS_TABLE_DATA_MODEL_ROW( ref, ROW_STATE::NON_EXPANDABLE ) );
536 }
537
538 if( GetView() )
539 {
540 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
541 GetView()->ProcessTableMessage( msg );
542 }
543
544 Sort();
545}
546
547
549 FOOTPRINT& aDestFootprint,
550 TEMPLATES* aTemplateFieldnames,
551 const wxString& aVariantName )
552{
553 bool defaultVariant = aVariantName.IsEmpty()
554 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0;
555 bool footprintModified = false;
556
557 FOOTPRINT_REF destRef( aDestFootprint );
558
559 const std::map<wxString, wxString>& fieldStore = getStoredFields( aSourceRef );
560
561 for( const auto& [srcName, srcValue] : fieldStore )
562 {
563 // Attributes bypass the field logic, so handle them first
564 if( fieldIsAttribute( srcName ) )
565 {
566 footprintModified |= setAttributeValue( destRef, srcName, srcValue, aVariantName );
567 continue;
568 }
569
570 // Lib footprint fields models exposes extra footprint properties like lib description
571 // that aren't fields
572 if( fieldIsItemProperty( srcName ) )
573 continue;
574
575 // Skip generated fields with variables as names (e.g. ${QUANTITY});
576 // they can't be edited
577 if( IsGeneratedField( srcName ) )
578 continue;
579
580 // Don't apply footprint fields to footprints
582 continue;
583
584 int col = GetFieldNameCol( srcName );
585
586 // Footprint names are not editable (from the fields table dialogs)
587 if( col != -1 && ColIsItemIdentifier( col ) )
588 continue;
589
590 PCB_FIELD* destField = aDestFootprint.GetField( srcName );
591
592 if( destField && destField->IsPrivate() )
593 {
594 if( srcValue.IsEmpty() )
595 continue;
596 else
597 {
598 destField->SetPrivate( false );
599 footprintModified = true;
600 }
601 }
602
603 // Reaching this point means the data store field is at least marked present,
604 // so add the field to the footprint even when its stored value is empty.
605 bool createField = !destField;
606
607 if( createField )
608 {
609 destField = new PCB_FIELD( &aDestFootprint, FIELD_T::USER, srcName );
610 destField->SetLayer( aDestFootprint.GetLayer() == F_Cu ? F_Fab : B_Fab );
611 destField->SetFPRelativePosition( { 0, 0 } );
612
613 if( BOARD* board = aDestFootprint.GetBoard() )
614 destField->StyleFromSettings( board->GetDesignSettings(), true );
615
616 if( aTemplateFieldnames )
617 {
618 if( const TEMPLATE_FIELDNAME* srcTemplate = aTemplateFieldnames->GetFieldName( srcName ) )
619 destField->SetVisible( srcTemplate->m_Visible );
620 else
621 destField->SetVisible( false );
622 }
623 else
624 destField->SetVisible( false );
625
626 aDestFootprint.Add( destField );
627 footprintModified = true;
628 }
629
630 if( !destField )
631 continue;
632
633 wxString previousValue = aDestFootprint.GetFieldValueForVariant( aVariantName, srcName );
634 wxString newValue = srcValue;
635
636 // Board work is optional, not preset for lib fp fields table
637 if( BOARD* board = aDestFootprint.GetBoard() )
638 newValue = board->ConvertCrossReferencesToKIIDs( srcValue );
639
640 if( previousValue != newValue )
641 {
642 // Lib footprints pass a wxEmptyString variant and always apply straight to the field
643 if( defaultVariant )
644 {
645 destField->SetText( newValue );
646 footprintModified = true;
647 }
648 else if( FOOTPRINT_VARIANT* variant = aDestFootprint.AddVariant( aVariantName ) )
649 {
650 variant->SetFieldValue( srcName, newValue );
651 footprintModified = true;
652 }
653 }
654 }
655
656 for( int ii = static_cast<int>( aDestFootprint.GetFields().size() ) - 1; ii >= 0; ii-- )
657 {
658 PCB_FIELD* field = aDestFootprint.GetFields()[ii];
659
660 if( field->IsMandatory() || field->IsPrivate() )
661 continue;
662
663 if( !fieldStore.contains( field->GetUntranslatedName() ) )
664 {
665 // TODO: unlike symbols/SCH_FIELD, footprint PCB_FIELD
666 // can be grouped so we need to remove it from the group before deleting it
667 // In general, I'm not sure letting PCB_FIELDs associated with a footprint
668 // be grouped separately from the footprint is a good idea.
669 if( EDA_GROUP* parentGroup = field->GetParentGroup() )
670 parentGroup->RemoveItem( field );
671
672 aDestFootprint.Remove( field );
673 delete field;
674 footprintModified = true;
675 }
676 }
677
678 return footprintModified;
679}
680
681
683 const wxString& aVariantName )
684{
685 for( const FOOTPRINT_REF& ref : m_footprintsList )
686 {
687 FOOTPRINT& footprint = ref.GetFootprint();
688
689 // commit will delete the copy properly as needed, and we will delete it when
690 // we go out of scope if we fail to apply the data
691 std::unique_ptr<FOOTPRINT> footprintCopy = std::make_unique<FOOTPRINT>( footprint );
692 footprintCopy->SetParentGroup( nullptr );
693
694 // Only commit if the footprint was actually modified
695 if( applyDataToFootprint( ref, footprint, &aTemplateFieldnames, aVariantName ) )
696 aCommit.Modified( &footprint, footprintCopy.release() );
697 }
698
699 m_edited = false;
700}
701
702
704{
705 for( const FOOTPRINT_REF& ref : aRefs )
706 {
707 if( !alg::contains( m_footprintsList, ref ) )
708 {
709 m_footprintsList.push_back( ref );
710
712 }
713 }
714}
715
716
718{
719 m_dataStore.erase( getDataStoreKey( aFootprint ) );
720
721 m_footprintsList.erase( std::remove_if( m_footprintsList.begin(), m_footprintsList.end(),
722 [&aFootprint]( const FOOTPRINT_REF& ref ) -> bool
723 {
724 return ref == aFootprint;
725 } ),
726 m_footprintsList.end() );
727}
728
729
731{
732 for( const FOOTPRINT_REF& ref : aRefs )
733 RemoveFootprint( ref );
734}
735
736
738{
739 for( const FOOTPRINT_REF& ref : aRefs )
740 {
741 // Update the fields of every reference. Do this by iterating through the data model
742 // columns; we must have all fields in the footprint added to the data model at this point,
743 // and some of the data model columns may be variables that are not present in the footprint
745
746 if( !alg::contains( m_footprintsList, ref ) )
747 m_footprintsList.push_back( ref );
748 }
749}
750
751
752bool FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::DeleteRows( size_t aPosition, size_t aNumRows )
753{
754 size_t curNumRows = m_rows.size();
755
756 if( aPosition >= curNumRows )
757 {
758 wxFAIL_MSG( wxString::Format( wxT( "Called FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::DeleteRows(aPosition=%lu, "
759 "aNumRows=%lu)\nPosition value is invalid for present table with %lu rows" ),
760 (unsigned long) aPosition, (unsigned long) aNumRows,
761 (unsigned long) curNumRows ) );
762
763 return false;
764 }
765
766 if( aNumRows > curNumRows - aPosition )
767 {
768 aNumRows = curNumRows - aPosition;
769 }
770
771 if( aNumRows >= curNumRows )
772 {
773 m_rows.clear();
774 m_dataStore.clear();
775 m_footprintsList.clear();
776
777 if( GetView() )
778 {
779 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aPosition, aNumRows );
780 GetView()->ProcessTableMessage( msg );
781 }
782 }
783 else
784 {
785 // Note: this code is currently dead, as all current usage calls the clear path above,
786 // which is left because it is faster. This code *should* be correct but is untested.
787 auto first = m_rows.begin() + aPosition;
788 auto last = first + aNumRows;
789
790 FOOTPRINT_REFERENCE_LIST refsToDelete;
791 for( auto it = first; it != last && it != m_rows.end(); ++it )
792 {
793 for( const FOOTPRINT_REF& ref : it->m_items )
794 refsToDelete.push_back( ref );
795 }
796
797 RemoveReferences( refsToDelete );
798 // This will also notify the view
799 RebuildRows();
800 }
801
802 return true;
803}
804
805
812
813
815{
816 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
817 return m_cols[aCol].m_fieldName == FOOTPRINT_NAME;
818}
819
820
822{
823 return aFieldName == FOOTPRINT_NAME || aFieldName == FOOTPRINT_KEYWORDS
824 || aFieldName == FOOTPRINT_LIBRARY_DESCRIPTION
826}
827
828
830 const wxString& aFieldName, wxString& aValue )
831{
832 const FOOTPRINT& footprint = aRef.GetFootprint();
833
834 if( aFieldName == FOOTPRINT_NAME )
835 {
836 aValue = footprint.GetName();
837 return true;
838 }
839 else if( aFieldName == FOOTPRINT_KEYWORDS )
840 {
841 aValue = footprint.GetKeywords();
842 return true;
843 }
844 else if( aFieldName == FOOTPRINT_LIBRARY_DESCRIPTION )
845 {
846 aValue = footprint.GetLibDescription();
847 return true;
848 }
849
850 return FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::getLiveFieldValue( aRef, aFieldName, aValue );
851}
852
853
858
859
861 FOOTPRINT& aFootprint )
862{
863 bool footprintModified = false;
864 wxString value;
865
866 if( getStoredFieldValue( aRef, FOOTPRINT_KEYWORDS, value )
867 && aFootprint.GetKeywords() != value )
868 {
869 aFootprint.SetKeywords( value );
870 footprintModified = true;
871 }
872
874 && aFootprint.GetLibDescription() != value )
875 {
876 aFootprint.SetLibDescription( value );
877 footprintModified = true;
878 }
879
881 aRef, aFootprint, nullptr, wxEmptyString );
882
883 return footprintModified;
884}
885
886
887bool LIB_FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( std::function<bool( FOOTPRINT& )> aChangeHandler )
888{
889 bool allChangesApplied = true;
890
891 for( const FOOTPRINT_REF& ref : m_footprintsList )
892 {
893 // This works the opposite of the non-lib footprint fields table,
894 // here we just make a copy on the stack and let it pop off regardless of what
895 // happens; the actual footprint in source ref gets overwritten when we've
896 // determined that the change were applied
897 FOOTPRINT changedFootprint( ref.GetFootprint() );
898
899 if( !applyDataToFootprint( ref, changedFootprint ) )
900 {
901 // An empty staged public field may collide with an existing private field and
902 // be ignored. Re-sync from live so the no-op does not leave the model edited.
903 // A non-empty public field that collides with a private field is taken to be
904 // an explicit request to make it non-private, so that case isn't what we're
905 // checking for here, only the empty public/existing private mismatch.
906 for( const DATA_MODEL_COL& col : m_cols )
907 updateDataStoreItemFieldFromLive( ref, col.m_fieldName );
908
909 continue;
910 }
911
912 if( !aChangeHandler( changedFootprint ) )
913 {
914 allChangesApplied = false;
915 break;
916 }
917
918 ref.GetFootprint() = changedFootprint;
919
920 // Update the data store with the new live values after applying changes
921 for( const DATA_MODEL_COL& col : m_cols )
922 updateDataStoreItemFieldFromLive( ref, col.m_fieldName );
923 }
924
925 m_edited = false;
926
927 for( const FOOTPRINT_REF& ref : m_footprintsList )
928 {
929 for( const DATA_MODEL_COL& col : m_cols )
930 {
931 if( fieldIsModified( ref, col.m_fieldName ) )
932 {
933 m_edited = true;
934 return allChangesApplied;
935 }
936 }
937 }
938
939 return allChangesApplied;
940}
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:374
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
void SetFPRelativePosition(const VECTOR2I &aPos)
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition board.cpp:2631
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:221
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
const KIID m_Uuid
Definition eda_item.h:597
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:342
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:231
virtual bool fieldIsItemProperty(const wxString &aFieldName) const
void applyResolvedTextRenderer(wxGridCellAttr *aAttr, bool aApplyTint)
virtual bool ColIsReadOnly(int aCol) const
virtual bool fieldIsAttribute(const wxString &aFieldName) const
wxGridCellAttr * applyCellDecorations(wxGridCellAttr *aAttr, int aRow, int aCol)
int GetFieldNameCol(const wxString &aFieldName) const
std::unordered_set< KIID_PATH > m_selectionItems
std::map< KIID_PATH, std::map< wxString, wxString > > m_dataStore
bool groupMatch(const FOOTPRINT_REF &lhItem, const FOOTPRINT_REF &rhItem)
void setStoredFieldValue(const FOOTPRINT_REF &aItem, const wxString &aFieldName, const wxString &aValue)
bool fieldIsModified(const FOOTPRINT_REF &aItem, const wxString &aFieldName)
const std::map< wxString, wxString > & getStoredFields(const FOOTPRINT_REF &aItem) const
void initializeDataStoreItem(const FOOTPRINT_REF &aItem)
bool getStoredFieldValue(const FOOTPRINT_REF &aItem, const wxString &aFieldName, wxString &aValue) const
std::vector< DATA_MODEL_ROW< FOOTPRINT_REF > > m_rows
bool IsCellReadOnly(int aRow, int aCol) override
bool MatchesFilter(const FOOTPRINT_REF &aItem, const wxString &aReference, EDA_COMBINED_MATCHER &aMatcher)
void updateDataStoreItemFieldFromLive(const FOOTPRINT_REF &aItem, const wxString &aFieldName)
bool getLiveFieldValue(const FOOTPRINT_REF &aRef, const wxString &aFieldName, wxString &aValue) override
Gets the current value of the field from the live item, e.g.
KIID_PATH getDataStoreKey(const FOOTPRINT_REF &aItem) const override
Data store UUID for a footprint is just the footprint's UUID, since footprints are unique across the ...
bool DeleteRows(size_t aPosition=0, size_t aNumRows=1) override
std::vector< FOOTPRINT_REF > getAllItems() const override
bool setAttributeValue(const FOOTPRINT_REF &aRef, const wxString &aAttributeName, const wxString &aValue, const wxString &aVariantName=wxEmptyString)
Set the attribute value.
bool unitMatch(const FOOTPRINT_REF &lhItem, const FOOTPRINT_REF &rhItem) override
FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL(const FOOTPRINT_REFERENCE_LIST &aFootprintReferenceList)
void UpdateReferences(const FOOTPRINT_REFERENCE_LIST &aRefs)
wxString getDefaultFieldValue(const FOOTPRINT_REF &aRef, const wxString &aFieldName)
Get the default (non-variant) value for a field.
void AddReferences(const FOOTPRINT_REFERENCE_LIST &aRefs)
void ApplyData(BOARD_COMMIT &aCommit, TEMPLATES &aTemplateFieldnames, const wxString &aVariantName)
void RemoveReferences(const FOOTPRINT_REFERENCE_LIST &aRefs)
bool attributeForcedOnBySheet(const FOOTPRINT_REF &aRef, const wxString &aAttributeName) const override
Footprint attributes are don't currently track when they are inherited from the sheet,...
wxString getAttributeValue(const FOOTPRINT_REF &aRef, const wxString &aAttributeName, const wxString &aVariantNames)
bool getLiveFieldValueForVariant(const FOOTPRINT_REF &aRef, const wxString &aFieldName, const wxString &aVariantName, wxString &aValue)
wxString getItemIdentifier(const FOOTPRINT_REF &aItem) const override
wxString getFieldResolvedLiveValue(const FOOTPRINT_REF &aRef, const wxString &aFieldName) override
Explicitly bypasses the data store's field values and retries them from the item's current field valu...
wxString resolveTextVars(const FOOTPRINT_REF &aRef, const wxString &aText) override
void SetValue(int aRow, int aCol, const wxString &aValue) override
bool applyDataToFootprint(const FOOTPRINT_REF &aSourceRef, FOOTPRINT &aDestFootprint, TEMPLATES *aTemplateFieldnames, const wxString &aVariantName)
Returns whether or the the aDestFootprint was changed by applying the data from aSourceRef.
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
This is the minimal equivalent to the SCH_REFERENCE so we can provide similar non-null guarantees thr...
FOOTPRINT & GetFootprint() const
Variant information for a footprint.
Definition footprint.h:227
wxString GetLibDescription() const
Definition footprint.h:490
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
void SetDNP(bool aDNP=true)
Definition footprint.h:1056
bool GetExcludedFromSimForVariant(const wxString &aVariantName) const
Get the exclude-from-simulation status for a specific variant.
void SetExcludedFromSim(bool aExclude=true)
Definition footprint.h:1047
void SetExcludedFromBOM(bool aExclude=true)
Definition footprint.h:1038
void SetKeywords(const wxString &aKeywords)
Definition footprint.h:494
void SetExcludedFromPosFiles(bool aExclude=true)
Definition footprint.h:1029
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:449
wxString GetFPIDAsString() const
Definition footprint.h:479
wxString GetFieldValueForVariant(const wxString &aVariantName, const wxString &aFieldName) const
Get a field value for a specific variant.
wxString GetReferenceAsString() const
Definition footprint.h:910
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
bool GetDNPForVariant(const wxString &aVariantName) const
Get the DNP status for a specific variant.
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
wxString GetName() const override
Definition footprint.h:484
void SetLibDescription(const wxString &aDesc)
Definition footprint.h:491
bool GetExcludedFromPosFilesForVariant(const wxString &aVariantName) const
Get the exclude-from-position-files status for a specific variant.
FOOTPRINT_VARIANT * AddVariant(const wxString &aVariantName)
Add a new variant with the given name.
bool GetExcludedFromBOMForVariant(const wxString &aVariantName) const
Get the exclude-from-BOM status for a specific variant.
const KIID_PATH & GetPath() const
Definition footprint.h:496
wxString GetKeywords() const
Definition footprint.h:493
bool IsContainedWithin(const KIID_PATH &aParentPath) const
Definition kiid.h:193
LIB_FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL(const FOOTPRINT_REFERENCE_LIST &aFootprints)
bool getLiveFieldValue(const FOOTPRINT_REF &aRef, const wxString &aFieldName, wxString &aValue) override
Gets the current value of the field from the live item, e.g.
bool ColIsItemIdentifier(int aCol) const override
Reference for symbol/fields tables, lib_id for lib tables.
bool fieldIsItemProperty(const wxString &aFieldName) const override
bool ApplyData(std::function< bool(FOOTPRINT &)> aChangeHandler)
bool applyDataToFootprint(const FOOTPRINT_REF &aRef, FOOTPRINT &aFootprint)
wxString getItemIdentifier(const FOOTPRINT_REF &aRef) const override
virtual wxString GetFootprint()
For items with footprint fields.
bool IsMandatory() const
wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
Return the string actually shown after processing of the base text.
void SetPrivate(bool aPrivate)
Definition pcb_field.h:81
wxString GetUntranslatedName() const
Get the untranslated field name for storage, variable look-up, etc.
bool IsPrivate() const
Definition pcb_field.h:80
void StyleFromSettings(const BOARD_DESIGN_SETTINGS &settings, bool aCheckSide) override
Definition pcb_text.cpp:371
const TEMPLATE_FIELDNAME * GetFieldName(const wxString &aName)
Search for aName in the template field name list.
wxGridCellAttr * enhanceAttr(wxGridCellAttr *aInputAttr, int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind)
Definition wx_grid.cpp:43
std::map< int, wxGridCellAttr * > m_colAttrs
Definition wx_grid.h:108
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
Definition wx_grid.h:72
bool IsGeneratedField(const wxString &aFieldName)
Returns true if the entire string is generated, e.g is a single text var reference.
Definition common.cpp:494
wxString ResolveTextVars(const wxString &aSource, const std::function< bool(wxString *)> *aResolver, int &aDepth)
Multi-pass text variable expansion and math expression evaluation.
Definition common.cpp:333
@ INTERNAL
Definition common.h:92
@ CTX_SEARCH
std::vector< FOOTPRINT_REF > FOOTPRINT_REFERENCE_LIST
DATA_MODEL_ROW< FOOTPRINT_REF > FOOTPRINT_FIELDS_TABLE_DATA_MODEL_ROW
@ F_Fab
Definition layer_ids.h:115
@ F_Cu
Definition layer_ids.h:60
@ B_Fab
Definition layer_ids.h:114
const wxColour VARIANT_FIELD_OVERRIDE_DARK_YELLOW(80, 80, 40)
const wxColour VARIANT_FIELD_OVERRIDE_LIGHT_YELLOW(255, 255, 200)
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
wxString GetDefaultVariantName()
The point of the data model classes is fundamentally to represent three things:
std::vector< ITEM_TYPE > m_items
Hold a name of a symbol's field, field value, and default visibility.
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
@ USER
The field ID hasn't been set yet; field is invalid.
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ UNTRANSLATED
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46