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{
174 && aFieldName != wxS( "${EXCLUDE_FROM_BOARD}" );
175}
176
177
179{
180 // Footprints are just pointers and never have multiple units unlike symbols
181 // so just compare
182 return lhItem == rhItem;
183}
184
185
187 const wxString& aFieldName,
188 wxString& aValue )
189{
191 aValue );
192}
193
194
196{
197 return m_footprintsList;
198}
199
200
202 const wxString& aFieldName )
203{
204 FOOTPRINT& footprint = aRef.GetFootprint();
205 PCB_FIELD* field = footprint.GetField( aFieldName );
206
207 if( field )
208 {
209 if( field->IsPrivate() )
210 return wxEmptyString;
211 else
212 return field->GetShownText( INTERNAL, 0 );
213 }
214
215 // Handle generated fields with variables as names (e.g. ${QUANTITY}) that are not present in
216 // the footprint by giving them the correct value by resolving against the footprint
217 if( IsGeneratedField( aFieldName ) )
218 {
219 int depth = 0;
220
221 std::function<bool( wxString* )> footprintResolver =
222 [&]( wxString* token ) -> bool
223 {
224 return footprint.ResolveTextVar( token, m_currentVariant, depth + 1 );
225 };
226
227 return ResolveTextVars( aFieldName, &footprintResolver, depth );
228 }
229
230 return wxEmptyString;
231}
232
233
235{
236 int depth = 0;
237
238 std::function<bool( wxString* )> footprintResolver =
239 [&]( wxString* token ) -> bool
240 {
241 // Footprint user field names are case-sensitive; VALUE is a built-in alias.
242 wxString fieldToken = *token == wxS( "VALUE" )
244
245 if( resolveStoredTextVar( aRef, &fieldToken, true ) )
246 {
247 *token = fieldToken;
248 return true;
249 }
250
251 return aRef.GetFootprint().ResolveTextVar( token, m_currentVariant, depth );
252 };
253
254 return ResolveTextVars( aText, &footprintResolver, depth );
255}
256
257
259 const wxString& aAttributeName,
260 const wxString& aVariantName )
261{
262 if( aAttributeName == wxS( "${DNP}" ) )
263 return aRef.GetFootprint().GetDNPForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
264
265 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
266 return wxS( "0" );
267
268 if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
269 return aRef.GetFootprint().GetExcludedFromBOMForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
270
271 if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
272 return aRef.GetFootprint().GetExcludedFromSimForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
273
274 if( aAttributeName == wxS( "${EXCLUDE_FROM_POS_FILES}" ) )
275 return aRef.GetFootprint().GetExcludedFromPosFilesForVariant( aVariantName ) ? wxS( "1" ) : wxS( "0" );
276
277 return wxS( "0" );
278}
279
280
282 const wxString& ) const
283{
284 // TODO: So if a symbol has DNP set to false, and the sheet is in has DNP set to true,
285 // the symbol will be effectively DNP true. This will propogate to the footprint correctly.
286 //
287 // The symbol fields table dialog shows the overridden sheet-inherited value and does not let
288 // the user modify the symbol DNP value.
289 //
290 // The footprint fields table WILL allow the user to modify the footprint DNP value,
291 // which will be overridden whenever they sync-to-board.
292 //
293 // To have similar behavior we will eventually need to track whether these attributes on
294 // footprints came from the symbol or the sheet.
295 return false;
296}
297
298
300 const wxString& aFieldName,
301 const wxString& aVariantName,
302 wxString& aValue )
303{
304 aValue.clear();
305
306 const FOOTPRINT& footprint = aRef.GetFootprint();
307
308 if( fieldIsAttribute( aFieldName ) )
309 {
310 aValue = getAttributeValue( aRef, aFieldName, aVariantName );
311 return true;
312 }
313
315 {
316 aValue = footprint.GetFPIDAsString();
317 return true;
318 }
319
320 if( const PCB_FIELD* field = footprint.GetField( aFieldName ) )
321 {
322 if( field->IsPrivate() )
323 return false;
324
325 aValue = footprint.GetFieldValueForVariant( aVariantName, aFieldName );
326
327 if( footprint.GetBoard() )
328 // Cross part references e.g. ${U2:MyField} stored in U1 are converted
329 // to KIIDs transparently e.g. ${KIID:MyField} so reannotating U2->U3 doesn't
330 // break the the variable resolution
331 aValue = footprint.GetBoard()->ConvertKIIDsToCrossReferences( aValue );
332
333 return true;
334 }
335
336 // For generated fields, return the field name itself
337 if( IsGeneratedField( aFieldName ) )
338 {
339 aValue = aFieldName;
340 return true;
341 }
342
343 return false;
344}
345
346
348 const wxString& aFieldName )
349{
350 wxString value;
351 getLiveFieldValueForVariant( aRef, aFieldName, wxEmptyString, value );
352 return value;
353}
354
355
357 const wxString& aAttributeName,
358 const wxString& aValue,
359 const wxString& aVariantName )
360{
361 bool attrChanged = false;
362 bool newValue = aValue == wxS( "1" );
363 bool defaultVariant = aVariantName.IsEmpty()
364 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0;
365
366 if( aAttributeName == wxS( "${DNP}" ) )
367 {
368 attrChanged = aRef.GetFootprint().GetDNPForVariant( aVariantName ) != newValue;
369
370 if( attrChanged )
371 {
372 // TODO: fix footprint API to match symbol
373 if( defaultVariant )
374 aRef.GetFootprint().SetDNP( newValue );
375 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
376 variant->SetDNP( newValue );
377 }
378 }
379 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOARD}" ) )
380 {
381 attrChanged = false;
382 }
383 else if( aAttributeName == wxS( "${EXCLUDE_FROM_BOM}" ) )
384 {
385 attrChanged = aRef.GetFootprint().GetExcludedFromBOMForVariant( aVariantName ) != newValue;
386
387 if( attrChanged )
388 {
389 // TODO: fix footprint API to match symbol
390 if( defaultVariant )
391 aRef.GetFootprint().SetExcludedFromBOM( newValue );
392 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
393 variant->SetExcludedFromBOM( newValue );
394 }
395 }
396 else if( aAttributeName == wxS( "${EXCLUDE_FROM_SIM}" ) )
397 {
398 attrChanged = aRef.GetFootprint().GetExcludedFromSimForVariant( aVariantName ) != newValue;
399
400 if( attrChanged )
401 {
402 // TODO: fix footprint API to match symbol
403 if( defaultVariant )
404 aRef.GetFootprint().SetExcludedFromSim( newValue );
405 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
406 variant->SetExcludedFromSim( newValue );
407 }
408 }
409 else if( aAttributeName == wxS( "${EXCLUDE_FROM_POS_FILES}" ) )
410 {
411 attrChanged = aRef.GetFootprint().GetExcludedFromPosFilesForVariant( aVariantName ) != newValue;
412
413 if( attrChanged )
414 {
415 // TODO: fix footprint API to match symbol
416 if( defaultVariant )
417 aRef.GetFootprint().SetExcludedFromPosFiles( newValue );
418 else if( FOOTPRINT_VARIANT* variant = aRef.GetFootprint().AddVariant( aVariantName ) )
419 variant->SetExcludedFromPosFiles( newValue );
420 }
421 }
422
423 return attrChanged;
424}
425
426
428{
429 if( !m_rebuildsEnabled )
430 return;
431
432 if( GetView() )
433 {
434 // Commit any pending in-place edits before the row gets moved out from under
435 // the editor.
436 static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
437
438 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
439 GetView()->ProcessTableMessage( msg );
440 }
441
442 m_rows.clear();
443
444 EDA_COMBINED_MATCHER matcher( m_filter.Lower(), CTX_SEARCH );
445
446 for( const FOOTPRINT_REF& ref : m_footprintsList )
447 {
448 const FOOTPRINT& footprint = ref.GetFootprint();
449
450 if( m_scope == SCOPE::SCOPE_SELECTION
451 && !m_selectionItems.contains( getDataStoreKey( ref ) ) )
452 {
453 continue;
454 }
455
456 if( !MatchesFilter( ref, getItemIdentifier( ref ), matcher ) )
457 continue;
458
459 if( m_excludeDNP )
460 {
461 bool isDNP = false;
462
463 if( !m_variantNames.empty() )
464 {
465 for( const wxString& variantName : m_variantNames )
466 {
467 if( footprint.GetDNPForVariant( variantName ) )
468 {
469 isDNP = true;
470 break;
471 }
472 }
473 }
474 else
475 {
476 isDNP = footprint.GetDNPForVariant( m_currentVariant );
477 }
478
479 if( isDNP )
480 continue;
481 }
482
483 if( !m_includeExcluded )
484 {
485 bool isExcluded = false;
486
487 if( !m_variantNames.empty() )
488 {
489 for( const wxString& variantName : m_variantNames )
490 {
491 if( footprint.GetExcludedFromBOMForVariant( variantName ) )
492 {
493 isExcluded = true;
494 break;
495 }
496 }
497 }
498 else
499 {
500 isExcluded = footprint.GetExcludedFromBOMForVariant( m_currentVariant );
501 }
502
503 if( isExcluded )
504 continue;
505 }
506
507 KIID_PATH footprintSheetPath = footprint.GetPath();
508
509 if( !footprintSheetPath.empty() )
510 footprintSheetPath.pop_back();
511
512 if( ( m_scope == SCOPE::SCOPE_SHEET && footprintSheetPath != m_path )
513 || ( m_scope == SCOPE::SCOPE_SHEET_RECURSIVE
514 && !footprintSheetPath.IsContainedWithin( m_path ) ) )
515 {
516 continue;
517 }
518
519 bool matchFound = false;
520
521 // Performance optimization for ungrouped case to skip the N^2 for loop
522 if( !m_groupingEnabled )
523 {
524 m_rows.emplace_back( FOOTPRINT_FIELDS_TABLE_DATA_MODEL_ROW( ref, ROW_STATE::NON_EXPANDABLE ) );
525 continue;
526 }
527
528 // See if we already have a row which this footprint fits into
530 {
531 // all group members must have identical refs so just use the first one
532 const FOOTPRINT_REF& rowRef = row.m_items[0];
533
534 if( unitMatch( ref, rowRef ) )
535 {
536 matchFound = true;
537 row.m_items.push_back( ref );
538 break;
539 }
540 else if( m_groupingEnabled && groupMatch( ref, rowRef ) )
541 {
542 matchFound = true;
543 row.m_items.push_back( ref );
544 row.m_state = ROW_STATE::GROUP_COLLAPSED;
545 break;
546 }
547 }
548
549 if( !matchFound )
550 m_rows.emplace_back( FOOTPRINT_FIELDS_TABLE_DATA_MODEL_ROW( ref, ROW_STATE::NON_EXPANDABLE ) );
551 }
552
553 if( GetView() )
554 {
555 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
556 GetView()->ProcessTableMessage( msg );
557 }
558
559 Sort();
560}
561
562
564 FOOTPRINT& aDestFootprint,
565 TEMPLATES* aTemplateFieldnames,
566 const wxString& aVariantName )
567{
568 bool defaultVariant = aVariantName.IsEmpty()
569 || aVariantName.CmpNoCase( GetDefaultVariantName() ) == 0;
570 bool footprintModified = false;
571
572 FOOTPRINT_REF destRef( aDestFootprint );
573
574 const std::map<wxString, wxString> fieldStore = getStoredFields( aSourceRef, aVariantName );
575
576 for( const auto& [srcName, srcValue] : fieldStore )
577 {
578 // Attributes bypass the field logic, so handle them first
579 if( fieldIsAttribute( srcName ) )
580 {
581 footprintModified |= setAttributeValue( destRef, srcName, srcValue, aVariantName );
582 continue;
583 }
584
585 // Lib footprint fields models exposes extra footprint properties like lib description
586 // that aren't fields
587 if( fieldIsItemProperty( srcName ) )
588 continue;
589
590 // Skip generated fields with variables as names (e.g. ${QUANTITY});
591 // they can't be edited
592 if( IsGeneratedField( srcName ) )
593 continue;
594
595 // Don't apply footprint fields to footprints
597 continue;
598
599 int col = GetFieldNameCol( srcName );
600
601 // Footprint names are not editable (from the fields table dialogs)
602 if( col != -1 && ColIsItemIdentifier( col ) )
603 continue;
604
605 PCB_FIELD* destField = aDestFootprint.GetField( srcName );
606
607 if( destField && destField->IsPrivate() )
608 {
609 if( srcValue.IsEmpty() )
610 continue;
611 else
612 {
613 destField->SetPrivate( false );
614 footprintModified = true;
615 }
616 }
617
618 // Reaching this point means the data store field is at least marked present,
619 // so add the field to the footprint even when its stored value is empty.
620 bool createField = !destField;
621
622 if( createField )
623 {
624 destField = new PCB_FIELD( &aDestFootprint, FIELD_T::USER, srcName );
625 destField->SetLayer( aDestFootprint.GetLayer() == F_Cu ? F_Fab : B_Fab );
626 destField->SetFPRelativePosition( { 0, 0 } );
627
628 if( BOARD* board = aDestFootprint.GetBoard() )
629 destField->StyleFromSettings( board->GetDesignSettings(), true );
630
631 if( aTemplateFieldnames )
632 {
633 if( const TEMPLATE_FIELDNAME* srcTemplate = aTemplateFieldnames->GetFieldName( srcName ) )
634 destField->SetVisible( srcTemplate->m_Visible );
635 else
636 destField->SetVisible( false );
637 }
638 else
639 destField->SetVisible( false );
640
641 aDestFootprint.Add( destField );
642 footprintModified = true;
643 }
644
645 if( !destField )
646 continue;
647
648 wxString previousValue = aDestFootprint.GetFieldValueForVariant( aVariantName, srcName );
649 wxString newValue = srcValue;
650
651 // Board work is optional, not preset for lib fp fields table
652 if( BOARD* board = aDestFootprint.GetBoard() )
653 newValue = board->ConvertCrossReferencesToKIIDs( srcValue );
654
655 if( previousValue != newValue )
656 {
657 // Lib footprints pass a wxEmptyString variant and always apply straight to the field
658 if( defaultVariant )
659 {
660 destField->SetText( newValue );
661 footprintModified = true;
662 }
663 else if( FOOTPRINT_VARIANT* variant = aDestFootprint.AddVariant( aVariantName ) )
664 {
665 variant->SetFieldValue( srcName, newValue );
666 footprintModified = true;
667 }
668 }
669 }
670
671 for( int ii = static_cast<int>( aDestFootprint.GetFields().size() ) - 1; ii >= 0; ii-- )
672 {
673 PCB_FIELD* field = aDestFootprint.GetFields()[ii];
674
675 if( field->IsMandatory() || field->IsPrivate() )
676 continue;
677
678 if( storedFieldIsRemoved( aSourceRef, field->GetUntranslatedName() ) )
679 {
680 // TODO: unlike symbols/SCH_FIELD, footprint PCB_FIELD
681 // can be grouped so we need to remove it from the group before deleting it
682 // In general, I'm not sure letting PCB_FIELDs associated with a footprint
683 // be grouped separately from the footprint is a good idea.
684 if( EDA_GROUP* parentGroup = field->GetParentGroup() )
685 parentGroup->RemoveItem( field );
686
687 aDestFootprint.Remove( field );
688 delete field;
689 footprintModified = true;
690 }
691 }
692
693 return footprintModified;
694}
695
696
698{
699 for( const FOOTPRINT_REF& ref : m_footprintsList )
701
702 for( const FOOTPRINT_REF& ref : m_footprintsList )
703 {
704 FOOTPRINT& footprint = ref.GetFootprint();
705
706 // commit will delete the copy properly as needed, and we will delete it when
707 // we go out of scope if we fail to apply the data
708 std::unique_ptr<FOOTPRINT> footprintCopy = std::make_unique<FOOTPRINT>( footprint );
709 footprintCopy->SetParentGroup( nullptr );
710
711 // Only commit if the footprint was actually modified
712 bool modified = false;
713
714 for( const wxString& variant : storedVariants( ref ) )
715 modified |= applyDataToFootprint( ref, footprint, &aTemplateFieldnames, variant );
716
717 if( modified )
718 aCommit.Modified( &footprint, footprintCopy.release() );
719
720 acceptDataStoreItem( ref );
721 }
722
723 m_edited = false;
724}
725
726
728{
729 for( const FOOTPRINT_REF& ref : aRefs )
730 {
731 if( !alg::contains( m_footprintsList, ref ) )
732 {
733 m_footprintsList.push_back( ref );
734
736 }
737 }
738}
739
740
742{
743 m_dataStore.erase( getDataStoreKey( aFootprint ) );
744
745 m_footprintsList.erase( std::remove_if( m_footprintsList.begin(), m_footprintsList.end(),
746 [&aFootprint]( const FOOTPRINT_REF& ref ) -> bool
747 {
748 return ref == aFootprint;
749 } ),
750 m_footprintsList.end() );
751}
752
753
755{
756 for( const FOOTPRINT_REF& ref : aRefs )
757 RemoveFootprint( ref );
758}
759
760
762{
763 for( const FOOTPRINT_REF& ref : aRefs )
764 {
765 // Update the fields of every reference. Do this by iterating through the data model
766 // columns; we must have all fields in the footprint added to the data model at this point,
767 // and some of the data model columns may be variables that are not present in the footprint
769
770 if( !alg::contains( m_footprintsList, ref ) )
771 m_footprintsList.push_back( ref );
772 }
773
775}
776
777
778bool FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::DeleteRows( size_t aPosition, size_t aNumRows )
779{
780 size_t curNumRows = m_rows.size();
781
782 if( aPosition >= curNumRows )
783 {
784 wxFAIL_MSG( wxString::Format( wxT( "Called FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::DeleteRows(aPosition=%lu, "
785 "aNumRows=%lu)\nPosition value is invalid for present table with %lu rows" ),
786 (unsigned long) aPosition, (unsigned long) aNumRows,
787 (unsigned long) curNumRows ) );
788
789 return false;
790 }
791
792 if( aNumRows > curNumRows - aPosition )
793 {
794 aNumRows = curNumRows - aPosition;
795 }
796
797 if( aNumRows >= curNumRows )
798 {
799 m_rows.clear();
800 m_dataStore.clear();
801 m_footprintsList.clear();
802
803 if( GetView() )
804 {
805 wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aPosition, aNumRows );
806 GetView()->ProcessTableMessage( msg );
807 }
808 }
809 else
810 {
811 // Note: this code is currently dead, as all current usage calls the clear path above,
812 // which is left because it is faster. This code *should* be correct but is untested.
813 auto first = m_rows.begin() + aPosition;
814 auto last = first + aNumRows;
815
816 FOOTPRINT_REFERENCE_LIST refsToDelete;
817 for( auto it = first; it != last && it != m_rows.end(); ++it )
818 {
819 for( const FOOTPRINT_REF& ref : it->m_items )
820 refsToDelete.push_back( ref );
821 }
822
823 RemoveReferences( refsToDelete );
824 // This will also notify the view
825 RebuildRows();
826 }
827
828 return true;
829}
830
831
838
839
841{
842 wxCHECK( aCol >= 0 && aCol < static_cast<int>( m_cols.size() ), false );
843 return m_cols[aCol].m_fieldName == FOOTPRINT_NAME;
844}
845
846
848{
849 return aFieldName == FOOTPRINT_NAME || aFieldName == FOOTPRINT_KEYWORDS
850 || aFieldName == FOOTPRINT_LIBRARY_DESCRIPTION
852}
853
854
856 const wxString& aFieldName, wxString& aValue )
857{
858 const FOOTPRINT& footprint = aRef.GetFootprint();
859
860 if( aFieldName == FOOTPRINT_NAME )
861 {
862 aValue = footprint.GetName();
863 return true;
864 }
865 else if( aFieldName == FOOTPRINT_KEYWORDS )
866 {
867 aValue = footprint.GetKeywords();
868 return true;
869 }
870 else if( aFieldName == FOOTPRINT_LIBRARY_DESCRIPTION )
871 {
872 aValue = footprint.GetLibDescription();
873 return true;
874 }
875
876 return FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::getLiveFieldValue( aRef, aFieldName, aValue );
877}
878
879
884
885
887 FOOTPRINT& aFootprint )
888{
889 bool footprintModified = false;
890 wxString value;
891
892 if( getStoredFieldValue( aRef, FOOTPRINT_KEYWORDS, value )
893 && aFootprint.GetKeywords() != value )
894 {
895 aFootprint.SetKeywords( value );
896 footprintModified = true;
897 }
898
900 && aFootprint.GetLibDescription() != value )
901 {
902 aFootprint.SetLibDescription( value );
903 footprintModified = true;
904 }
905
907 aRef, aFootprint, nullptr, wxEmptyString );
908
909 return footprintModified;
910}
911
912
913bool LIB_FOOTPRINT_FIELDS_EDITOR_GRID_DATA_MODEL::ApplyData( std::function<bool( FOOTPRINT& )> aChangeHandler )
914{
915 bool allChangesApplied = true;
916
917 for( const FOOTPRINT_REF& ref : m_footprintsList )
918 {
919 // This works the opposite of the non-lib footprint fields table,
920 // here we just make a copy on the stack and let it pop off regardless of what
921 // happens; the actual footprint in source ref gets overwritten when we've
922 // determined that the change were applied
923 FOOTPRINT changedFootprint( ref.GetFootprint() );
924
925 if( !applyDataToFootprint( ref, changedFootprint ) )
926 {
927 // An empty staged public field may collide with an existing private field and
928 // be ignored. Re-sync from live so the no-op does not leave the model edited.
929 // A non-empty public field that collides with a private field is taken to be
930 // an explicit request to make it non-private, so that case isn't what we're
931 // checking for here, only the empty public/existing private mismatch.
932 acceptDataStoreItem( ref );
933
934 continue;
935 }
936
937 if( !aChangeHandler( changedFootprint ) )
938 {
939 allChangesApplied = false;
940 break;
941 }
942
943 ref.GetFootprint() = changedFootprint;
944
945 // Update the data store with the new live values after applying changes
946 acceptDataStoreItem( ref );
947 }
948
950
951 return allChangesApplied;
952}
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:410
wxString ConvertKIIDsToCrossReferences(const wxString &aSource) const
Definition board.cpp:2652
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:224
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
const KIID m_Uuid
Definition eda_item.h:599
virtual EDA_GROUP * GetParentGroup() const
Definition eda_item.h:116
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:236
virtual bool fieldIsItemProperty(const wxString &aFieldName) const
std::map< KIID_PATH, std::map< wxString, FIELD_STORE_VALUE > > m_dataStore
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
bool groupMatch(const FOOTPRINT_REF &lhItem, const FOOTPRINT_REF &rhItem)
void setStoredFieldValue(const FOOTPRINT_REF &aItem, const wxString &aFieldName, const wxString &aValue)
void initializeDataStoreItem(const FOOTPRINT_REF &aItem)
bool storedFieldIsRemoved(const FOOTPRINT_REF &aItem, const wxString &aName) const
bool getStoredFieldValue(const FOOTPRINT_REF &aItem, const wxString &aFieldName, wxString &aValue) const
std::vector< DATA_MODEL_ROW< FOOTPRINT_REF > > m_rows
bool resolveStoredTextVar(const FOOTPRINT_REF &aItem, wxString *aToken, bool aCaseSensitive=false) const
bool IsCellReadOnly(int aRow, int aCol) override
std::map< wxString, wxString > getStoredFields(const FOOTPRINT_REF &aItem, const wxString &aVariant) const
void refreshDataStoreItem(const FOOTPRINT_REF &aItem)
bool MatchesFilter(const FOOTPRINT_REF &aItem, const wxString &aReference, EDA_COMBINED_MATCHER &aMatcher)
void acceptDataStoreItem(const FOOTPRINT_REF &aItem)
std::set< wxString > storedVariants(const FOOTPRINT_REF &aItem) const
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 fieldSupportsVariants(const wxString &aFieldName) const override
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 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.
bool attributeForcedOnBySheet(const FOOTPRINT_REF &aRef, const wxString &aAttributeName, const wxString &aVariantName) const override
Footprint attributes are don't currently track when they are inherited from the sheet,...
void AddReferences(const FOOTPRINT_REFERENCE_LIST &aRefs)
void RemoveReferences(const FOOTPRINT_REFERENCE_LIST &aRefs)
void ApplyData(BOARD_COMMIT &aCommit, TEMPLATES &aTemplateFieldnames)
bool setAttributeValue(const FOOTPRINT_REF &aReference, const wxString &aAttributeName, const wxString &aValue, const wxString &aVariantName=wxEmptyString)
Set the attribute value.
wxString getAttributeValue(const FOOTPRINT_REF &aRef, const wxString &aAttributeName, const wxString &aVariantNames)
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.
bool getLiveFieldValueForVariant(const FOOTPRINT_REF &aRef, const wxString &aFieldName, const wxString &aVariantName, wxString &aValue) override
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:228
wxString GetLibDescription() const
Definition footprint.h:491
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:1064
bool GetExcludedFromSimForVariant(const wxString &aVariantName) const
Get the exclude-from-simulation status for a specific variant.
void SetExcludedFromSim(bool aExclude=true)
Definition footprint.h:1055
void SetExcludedFromBOM(bool aExclude=true)
Definition footprint.h:1046
void SetKeywords(const wxString &aKeywords)
Definition footprint.h:495
void SetExcludedFromPosFiles(bool aExclude=true)
Definition footprint.h:1037
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:450
bool ResolveTextVar(wxString *aToken, int aDepth=0) const
Resolve any references to system tokens supported by the component.
wxString GetFPIDAsString() const
Definition footprint.h:480
wxString GetFieldValueForVariant(const wxString &aVariantName, const wxString &aFieldName) const
Get a field value for a specific variant.
wxString GetReferenceAsString() const
Definition footprint.h:918
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Adds an item to 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:485
void SetLibDescription(const wxString &aDesc)
Definition footprint.h:492
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:497
wxString GetKeywords() const
Definition footprint.h:494
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() const
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:133
wxGridCellAttr * GetAttr(int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind) override
Definition wx_grid.h:96
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:94
@ 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()
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".
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
@ UNTRANSLATED
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
Definition ui_common.h:46