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, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <eda_text.h>
23#include <footprint.h>
24#include <pcb_barcode.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 // PCB_BARCODE wraps an EDA_TEXT internally; register the barcode itself
51 // (not its inner PCB_TEXT) so invalidation callbacks receive the barcode
52 // as the dependent and the view can repaint it.
53 if( PCB_BARCODE* bc = dynamic_cast<PCB_BARCODE*>( aItem ) )
54 {
55 m_tracker.RegisterItem( aItem, FilterTrackable( bc->GetTextVarReferences() ) );
56 return;
57 }
58
59 // FOOTPRINTs aren't themselves EDA_TEXT. Walk both their fields AND
60 // their graphical items — silkscreen/copper/courtyard layers can
61 // carry PCB_TEXT/PCB_TEXTBOX that reference `${...}`.
62 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem ) )
63 {
64 for( PCB_FIELD* field : fp->GetFields() )
65 registerItem( field );
66
67 for( BOARD_ITEM* child : fp->GraphicalItems() )
68 registerItem( child );
69 }
70
71 return;
72 }
73
74 m_tracker.RegisterItem( aItem, FilterTrackable( text->GetTextVarReferences() ) );
75}
76
77
79{
80 if( !aItem )
81 return;
82
83 m_tracker.UnregisterItem( aItem );
84
85 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem ) )
86 {
87 for( PCB_FIELD* field : fp->GetFields() )
88 m_tracker.UnregisterItem( field );
89
90 for( BOARD_ITEM* child : fp->GraphicalItems() )
91 unregisterItem( child );
92 }
93}
94
95
100
101
102void BOARD_TEXT_VAR_ADAPTER::OnBoardItemsAdded( BOARD&, std::vector<BOARD_ITEM*>& aItems )
103{
104 for( BOARD_ITEM* item : aItems )
105 registerItem( item );
106}
107
108
113
114
115void BOARD_TEXT_VAR_ADAPTER::OnBoardItemsRemoved( BOARD&, std::vector<BOARD_ITEM*>& aItems )
116{
117 for( BOARD_ITEM* item : aItems )
118 unregisterItem( item );
119}
120
121
123{
124 if( !aItem )
125 return;
126
127 // Re-register the item's own refs (its text may have changed), then fan
128 // out any cross-ref keys this item could source so dependents refresh.
129 EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
130
131 if( text )
132 {
133 std::vector<TEXT_VAR_REF_KEY> updated = FilterTrackable( text->GetTextVarReferences() );
134 m_tracker.HandleItemChanged( aItem, updated );
135 }
136 else if( PCB_BARCODE* bc = dynamic_cast<PCB_BARCODE*>( aItem ) )
137 {
138 m_tracker.HandleItemChanged( aItem, FilterTrackable( bc->GetTextVarReferences() ) );
139 }
140 else
141 {
142 // Non-text item (e.g., FOOTPRINT) — its own children were registered
143 // separately on add, so we only need the fan-out for source keys.
144 m_tracker.HandleItemChanged( aItem, {} );
145
146 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem ) )
147 {
148 // Footprint fields may themselves have been edited (value/ref
149 // change). Re-register each so the dependency graph stays current.
150 for( PCB_FIELD* field : fp->GetFields() )
151 {
152 std::vector<TEXT_VAR_REF_KEY> fieldRefs = FilterTrackable( field->GetTextVarReferences() );
153 m_tracker.RegisterItem( field, fieldRefs );
154 }
155
156 // Graphical items (silkscreen text etc.) may also reference
157 // text vars and may have been edited out-of-band.
158 for( BOARD_ITEM* child : fp->GraphicalItems() )
159 {
160 if( EDA_TEXT* childText = dynamic_cast<EDA_TEXT*>( child ) )
161 {
162 m_tracker.RegisterItem( child,
163 FilterTrackable( childText->GetTextVarReferences() ) );
164 }
165 }
166 }
167 }
168}
169
170
171void BOARD_TEXT_VAR_ADAPTER::OnBoardItemsChanged( BOARD& aBoard, std::vector<BOARD_ITEM*>& aItems )
172{
173 for( BOARD_ITEM* item : aItems )
174 OnBoardItemChanged( aBoard, item );
175}
176
177
179 std::vector<BOARD_ITEM*>& aAdded,
180 std::vector<BOARD_ITEM*>& aRemoved,
181 std::vector<BOARD_ITEM*>& aChanged )
182{
183 // Apply in order: remove, add, change. Removals first so re-added items
184 // with recycled pointers don't collide in the index. Changes last so
185 // fan-outs see the updated board state.
186 for( BOARD_ITEM* item : aRemoved )
187 unregisterItem( item );
188
189 for( BOARD_ITEM* item : aAdded )
190 registerItem( item );
191
192 for( BOARD_ITEM* item : aChanged )
193 OnBoardItemChanged( aBoard, item );
194}
195
196
198{
199 m_tracker.Clear();
200
201 for( FOOTPRINT* fp : m_board.Footprints() )
202 registerItem( fp );
203
204 for( BOARD_ITEM* item : m_board.Drawings() )
205 registerItem( item );
206}
207
208
209std::vector<TEXT_VAR_REF_KEY> BOARD_TEXT_VAR_ADAPTER::ExtractSourceKeys( EDA_ITEM* aItem ) const
210{
211 std::vector<TEXT_VAR_REF_KEY> out;
212
213 FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem );
214
215 if( !fp )
216 return out;
217
218 // A footprint U1 sources `${U1:<FIELDNAME>}` for every named field it
219 // carries. This is a conservative over-approximation — an edit to any
220 // footprint field fans out to every dependent on ${U1:*}, even if the
221 // specific field they reference wasn't the one that changed. The blast
222 // radius is bounded by the number of actual dependents, so over-
223 // invalidation is cheap relative to the alternative (per-field diff
224 // against a pre-image snapshot, which would couple the adapter to the
225 // commit system).
226 const wxString refdes = fp->GetReference();
227
228 if( refdes.IsEmpty() )
229 return out;
230
231 out.reserve( fp->GetFields().size() );
232
233 for( PCB_FIELD* field : fp->GetFields() )
234 {
237 key.primary = refdes;
238 key.secondary = field->GetName();
239 out.push_back( key );
240 }
241
242 return out;
243}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:81
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:372
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
const wxString & GetReference() const
Definition footprint.h:841
BARCODE class definition.
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...