KiCad PCB EDA Suite
Loading...
Searching...
No Matches
board_text_var_adapter.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
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 */
20
22
23#include <eda_text.h>
24#include <footprint.h>
25#include <pcb_field.h>
26#include <pcb_text.h>
27#include <pcb_textbox.h>
28
29
31 m_board( aBoard )
32{
33 m_tracker.SetSourceKeyExtractor(
34 [this]( EDA_ITEM* aItem ) -> std::vector<TEXT_VAR_REF_KEY>
35 { return ExtractSourceKeys( aItem ); } );
36}
37
38
40{
41 if( !aItem )
42 return;
43
44 // Route the dynamic_cast through the pcbnew DSO where RTTI for EDA_TEXT is
45 // visible. The kicommon-side tracker stays RTTI-free.
46 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
47
48 if( !text )
49 {
50 // FOOTPRINTs aren't themselves EDA_TEXT. Walk both their fields AND
51 // their graphical items — silkscreen/copper/courtyard layers can
52 // carry PCB_TEXT/PCB_TEXTBOX that reference `${...}`.
53 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem ) )
54 {
55 for( PCB_FIELD* field : fp->GetFields() )
56 registerItem( field );
57
58 for( BOARD_ITEM* child : fp->GraphicalItems() )
59 registerItem( child );
60 }
61
62 return;
63 }
64
65 m_tracker.RegisterItem( aItem, FilterTrackable( text->GetTextVarReferences() ) );
66}
67
68
70{
71 if( !aItem )
72 return;
73
74 m_tracker.UnregisterItem( aItem );
75
76 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem ) )
77 {
78 for( PCB_FIELD* field : fp->GetFields() )
79 m_tracker.UnregisterItem( field );
80
81 for( BOARD_ITEM* child : fp->GraphicalItems() )
82 unregisterItem( child );
83 }
84}
85
86
91
92
93void BOARD_TEXT_VAR_ADAPTER::OnBoardItemsAdded( BOARD&, std::vector<BOARD_ITEM*>& aItems )
94{
95 for( BOARD_ITEM* item : aItems )
96 registerItem( item );
97}
98
99
104
105
106void BOARD_TEXT_VAR_ADAPTER::OnBoardItemsRemoved( BOARD&, std::vector<BOARD_ITEM*>& aItems )
107{
108 for( BOARD_ITEM* item : aItems )
109 unregisterItem( item );
110}
111
112
114{
115 if( !aItem )
116 return;
117
118 // Re-register the item's own refs (its text may have changed), then fan
119 // out any cross-ref keys this item could source so dependents refresh.
120 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
121
122 if( text )
123 {
124 std::vector<TEXT_VAR_REF_KEY> updated = FilterTrackable( text->GetTextVarReferences() );
125 m_tracker.HandleItemChanged( aItem, updated );
126 }
127 else
128 {
129 // Non-text item (e.g., FOOTPRINT) — its own children were registered
130 // separately on add, so we only need the fan-out for source keys.
131 m_tracker.HandleItemChanged( aItem, {} );
132
133 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem ) )
134 {
135 // Footprint fields may themselves have been edited (value/ref
136 // change). Re-register each so the dependency graph stays current.
137 for( PCB_FIELD* field : fp->GetFields() )
138 {
139 std::vector<TEXT_VAR_REF_KEY> fieldRefs = FilterTrackable( field->GetTextVarReferences() );
140 m_tracker.RegisterItem( field, fieldRefs );
141 }
142
143 // Graphical items (silkscreen text etc.) may also reference
144 // text vars and may have been edited out-of-band.
145 for( BOARD_ITEM* child : fp->GraphicalItems() )
146 {
147 if( EDA_TEXT* childText = dynamic_cast<EDA_TEXT*>( child ) )
148 {
149 m_tracker.RegisterItem( child,
150 FilterTrackable( childText->GetTextVarReferences() ) );
151 }
152 }
153 }
154 }
155}
156
157
158void BOARD_TEXT_VAR_ADAPTER::OnBoardItemsChanged( BOARD& aBoard, std::vector<BOARD_ITEM*>& aItems )
159{
160 for( BOARD_ITEM* item : aItems )
161 OnBoardItemChanged( aBoard, item );
162}
163
164
166 std::vector<BOARD_ITEM*>& aAdded,
167 std::vector<BOARD_ITEM*>& aRemoved,
168 std::vector<BOARD_ITEM*>& aChanged )
169{
170 // Apply in order: remove, add, change. Removals first so re-added items
171 // with recycled pointers don't collide in the index. Changes last so
172 // fan-outs see the updated board state.
173 for( BOARD_ITEM* item : aRemoved )
174 unregisterItem( item );
175
176 for( BOARD_ITEM* item : aAdded )
177 registerItem( item );
178
179 for( BOARD_ITEM* item : aChanged )
180 OnBoardItemChanged( aBoard, item );
181}
182
183
185{
186 m_tracker.Clear();
187
188 for( FOOTPRINT* fp : m_board.Footprints() )
189 registerItem( fp );
190
191 for( BOARD_ITEM* item : m_board.Drawings() )
192 registerItem( item );
193}
194
195
196std::vector<TEXT_VAR_REF_KEY> BOARD_TEXT_VAR_ADAPTER::ExtractSourceKeys( EDA_ITEM* aItem ) const
197{
198 std::vector<TEXT_VAR_REF_KEY> out;
199
200 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem );
201
202 if( !fp )
203 return out;
204
205 // A footprint U1 sources `${U1:<FIELDNAME>}` for every named field it
206 // carries. This is a conservative over-approximation — an edit to any
207 // footprint field fans out to every dependent on ${U1:*}, even if the
208 // specific field they reference wasn't the one that changed. The blast
209 // radius is bounded by the number of actual dependents, so over-
210 // invalidation is cheap relative to the alternative (per-field diff
211 // against a pre-image snapshot, which would couple the adapter to the
212 // commit system).
213 const wxString refdes = fp->GetReference();
214
215 if( refdes.IsEmpty() )
216 return out;
217
218 out.reserve( fp->GetFields().size() );
219
220 for( PCB_FIELD* field : fp->GetFields() )
221 {
224 key.primary = refdes;
225 key.secondary = field->GetName();
226 out.push_back( key );
227 }
228
229 return out;
230}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
void OnBoardItemsAdded(BOARD &aBoard, std::vector< BOARD_ITEM * > &aItems) override
void OnBoardItemRemoved(BOARD &aBoard, BOARD_ITEM *aItem) override
void OnBoardCompositeUpdate(BOARD &aBoard, std::vector< BOARD_ITEM * > &aAdded, std::vector< BOARD_ITEM * > &aRemoved, std::vector< BOARD_ITEM * > &aChanged) override
void OnBoardItemsChanged(BOARD &aBoard, std::vector< BOARD_ITEM * > &aItems) override
void unregisterItem(BOARD_ITEM *aItem)
void OnBoardItemChanged(BOARD &aBoard, BOARD_ITEM *aItem) override
void OnBoardItemsRemoved(BOARD &aBoard, std::vector< BOARD_ITEM * > &aItems) override
void registerItem(BOARD_ITEM *aItem)
void RebuildIndex()
Scan the whole board and register every text-bearing item.
void OnBoardItemAdded(BOARD &aBoard, BOARD_ITEM *aItem) override
std::vector< TEXT_VAR_REF_KEY > ExtractSourceKeys(EDA_ITEM *aItem) const
Return the keys aItem could source as a cross-reference target.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:323
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:100
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:93
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
const wxString & GetReference() const
Definition footprint.h:829
Identifies a single resolvable source that a text item's ${...} reference depends on.
std::vector< TEXT_VAR_REF_KEY > FilterTrackable(const std::vector< TEXT_VAR_REF_KEY > &aRefs)
Filter aRefs down to the subset that should be registered in the index (drops OP and any future non-t...