KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_drawing_sheet_reactive.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#define BOOST_TEST_NO_MAIN
21#include <boost/test/unit_test.hpp>
22
23#include <algorithm>
24#include <base_units.h>
29#include <page_info.h>
30#include <text_var_dependency.h>
31#include <title_block.h>
32
33
34namespace
35{
36struct DefaultLayoutFixture
37{
38 DefaultLayoutFixture()
39 {
40 // The drawing-sheet system is singleton-based; tests depend on a
41 // populated default layout to find text items to scan.
43 }
44};
45}
46
47
48BOOST_FIXTURE_TEST_SUITE( DrawingSheetReactive, DefaultLayoutFixture )
49
50
51BOOST_AUTO_TEST_CASE( CollectKeysFindsTitleBlockSources )
52{
53 // Default drawing sheet template references PROJECTNAME, REVISION, TITLE,
54 // COMMENT[1..9], ISSUE_DATE, COMPANY, etc. — the set is defined by the
55 // drawing sheet parser. Collect them and confirm several well-known ones
56 // are present.
57 PAGE_INFO page;
58 TITLE_BLOCK tb;
59
60 DS_PROXY_VIEW_ITEM proxy( unityScale, &page, nullptr, &tb, nullptr );
61
62 const auto keys = proxy.CollectTextVarKeys();
63
64 auto hasKey = [&]( TEXT_VAR_REF_KEY::KIND k, const wxString& primary )
65 {
66 return std::any_of( keys.begin(), keys.end(),
67 [&]( const TEXT_VAR_REF_KEY& key )
68 { return key.kind == k && key.primary == primary; } );
69 };
70
71 // The default drawing sheet always surfaces at least these tokens.
72 BOOST_CHECK( hasKey( TEXT_VAR_REF_KEY::KIND::TITLE_BLOCK, wxT( "REVISION" ) ) );
73 BOOST_CHECK( hasKey( TEXT_VAR_REF_KEY::KIND::TITLE_BLOCK, wxT( "TITLE" ) ) );
74 BOOST_CHECK( hasKey( TEXT_VAR_REF_KEY::KIND::TITLE_BLOCK, wxT( "COMPANY" ) ) );
75}
76
77
78BOOST_AUTO_TEST_CASE( AttachRegistersProxyAsDependent )
79{
80 PAGE_INFO page;
81 TITLE_BLOCK tb;
82
83 DS_PROXY_VIEW_ITEM proxy( unityScale, &page, nullptr, &tb, nullptr );
84
85 TEXT_VAR_TRACKER tracker;
86 proxy.AttachToTracker( &tracker );
87
88 // The proxy should be registered as a dependent on every title-block key
89 // its template references.
90 BOOST_CHECK(
91 tracker.Index().DependentCount(
92 TEXT_VAR_REF_KEY::FromToken( wxT( "REVISION" ) ) ) > 0u );
93 BOOST_CHECK(
94 tracker.Index().DependentCount(
95 TEXT_VAR_REF_KEY::FromToken( wxT( "TITLE" ) ) ) > 0u );
96}
97
98
99BOOST_AUTO_TEST_CASE( InvalidationReachesProxyViaListener )
100{
101 PAGE_INFO page;
102 TITLE_BLOCK tb;
103
104 DS_PROXY_VIEW_ITEM proxy( unityScale, &page, nullptr, &tb, nullptr );
105 TEXT_VAR_TRACKER tracker;
106 proxy.AttachToTracker( &tracker );
107
108 // Frames install a long-lived listener that routes invalidations to the
109 // current drawing sheet proxy. Verify the dispatch semantics with a
110 // minimal listener.
111 EDA_ITEM* seenDep = nullptr;
112 (void) tracker.AddInvalidateListener(
113 [&]( EDA_ITEM* dep, const TEXT_VAR_REF_KEY& )
114 {
115 if( dep == &proxy )
116 seenDep = dep;
117 } );
118
119 tracker.InvalidateKey( TEXT_VAR_REF_KEY::FromToken( wxT( "REVISION" ) ) );
120
121 BOOST_CHECK_EQUAL( seenDep, &proxy );
122}
123
124
125BOOST_AUTO_TEST_CASE( DetachUnregistersProxy )
126{
127 PAGE_INFO page;
128 TITLE_BLOCK tb;
129
130 DS_PROXY_VIEW_ITEM proxy( unityScale, &page, nullptr, &tb, nullptr );
131 TEXT_VAR_TRACKER tracker;
132
133 proxy.AttachToTracker( &tracker );
134 BOOST_CHECK(
135 tracker.Index().DependentCount(
136 TEXT_VAR_REF_KEY::FromToken( wxT( "REVISION" ) ) ) > 0u );
137
138 proxy.AttachToTracker( nullptr );
140 tracker.Index().DependentCount(
141 TEXT_VAR_REF_KEY::FromToken( wxT( "REVISION" ) ) ),
142 0u );
143}
144
145
146BOOST_AUTO_TEST_CASE( DestructorAutoUnregisters )
147{
148 PAGE_INFO page;
149 TITLE_BLOCK tb;
150
151 TEXT_VAR_TRACKER tracker;
152
153 {
154 DS_PROXY_VIEW_ITEM proxy( unityScale, &page, nullptr, &tb, nullptr );
155 proxy.AttachToTracker( &tracker );
156 BOOST_REQUIRE( tracker.Index().ItemCount() > 0u );
157 }
158
159 // Proxy destructor must clean up the index so no dangling pointer remains
160 // for a future invalidation to match against.
161 BOOST_CHECK_EQUAL( tracker.Index().ItemCount(), 0u );
162}
163
164
165BOOST_AUTO_TEST_CASE( RepeatedTextKeepsAllInstancesWithNegativeStep )
166{
167 // Regression: a repeated text used to lose every copy when the step was
168 // negative, because IsInsidePage() tested a phantom end point anchored to
169 // the bottom-right corner (text has no real end point). See #24309.
171 model.ClearList();
172
173 DS_DATA_ITEM_TEXT* text = new DS_DATA_ITEM_TEXT( wxT( "1" ) );
174 text->SetStart( 60.0, 60.0, LT_CORNER );
175 text->m_RepeatCount = 8;
176 text->m_IncrementLabel = 1;
177 text->m_IncrementVector = VECTOR2D( -5.0, -5.0 );
178 model.Append( text );
179
180 PAGE_INFO page;
181 TITLE_BLOCK tb;
182
183 DS_DRAW_ITEM_LIST drawList( unityScale );
184 drawList.BuildDrawItemsList( page, tb );
185
186 int textCount = 0;
187
188 for( DS_DRAW_ITEM_BASE* item = drawList.GetFirst(); item; item = drawList.GetNext() )
189 {
190 if( item->Type() == WSG_TEXT_T )
191 textCount++;
192 }
193
194 BOOST_CHECK_EQUAL( textCount, 8 );
195}
196
197
198static std::vector<wxString> repeatTexts( const wxString& aBase, int aCount, int aLabelStep )
199{
201 model.ClearList();
202
204 text->SetStart( 60.0, 60.0, LT_CORNER );
205 text->m_RepeatCount = aCount;
206 text->m_IncrementLabel = aLabelStep;
207 text->m_IncrementVector = VECTOR2D( 2.0, 2.0 );
208 model.Append( text );
209
210 PAGE_INFO page;
211 TITLE_BLOCK tb;
212
213 DS_DRAW_ITEM_LIST drawList( unityScale );
214 drawList.BuildDrawItemsList( page, tb );
215
216 std::vector<wxString> out;
217
218 for( DS_DRAW_ITEM_BASE* item = drawList.GetFirst(); item; item = drawList.GetNext() )
219 {
220 if( item->Type() == WSG_TEXT_T )
221 out.push_back( static_cast<DS_DRAW_ITEM_TEXT*>( item )->GetText() );
222 }
223
224 return out;
225}
226
227
228BOOST_AUTO_TEST_CASE( RepeatedLabelStepsLettersAndNumbersCleanly )
229{
230 // A trailing letter must roll z -> aa, never into punctuation, and a
231 // trailing multi-digit number must carry (19 -> 20, not 110).
232 const std::vector<wxString> letters = repeatTexts( wxT( "y" ), 5, 1 );
233 const std::vector<wxString> expLetters = { wxT( "y" ), wxT( "z" ), wxT( "aa" ), wxT( "ab" ), wxT( "ac" ) };
234 BOOST_CHECK_EQUAL_COLLECTIONS( letters.begin(), letters.end(), expLetters.begin(), expLetters.end() );
235
236 const std::vector<wxString> numbers = repeatTexts( wxT( "19" ), 3, 1 );
237 const std::vector<wxString> expNumbers = { wxT( "19" ), wxT( "20" ), wxT( "21" ) };
238 BOOST_CHECK_EQUAL_COLLECTIONS( numbers.begin(), numbers.end(), expNumbers.begin(), expNumbers.end() );
239}
240
241
constexpr EDA_IU_SCALE unityScale
Definition base_units.h:124
Handle the graphic items list to draw/plot the frame and title block.
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
Base class to handle basic graphic items.
Store the list of graphic items: rect, lines, polygons and texts to draw/plot the title block and fra...
DS_DRAW_ITEM_BASE * GetFirst()
void BuildDrawItemsList(const PAGE_INFO &aPageInfo, const TITLE_BLOCK &aTitleBlock)
Drawing or plot the drawing sheet.
DS_DRAW_ITEM_BASE * GetNext()
A graphic text.
void AttachToTracker(TEXT_VAR_TRACKER *aTracker)
Register this proxy with aTracker as a dependent on every title-block source variable its current tem...
std::vector< TEXT_VAR_REF_KEY > CollectTextVarKeys() const
Walk the current drawing-sheet definition and collect every ${...} reference encountered in its text ...
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
std::size_t DependentCount(const TEXT_VAR_REF_KEY &aKey) const
Coordinates the dependency index with change notifications.
ListenerHandle AddInvalidateListener(InvalidateCallback aCallback)
Register a listener that fires for every invalidation.
TEXT_VAR_DEPENDENCY_INDEX & Index()
void InvalidateKey(const TEXT_VAR_REF_KEY &aKey)
Fan out invalidation for a single explicit key — used when a non-item source changes (e....
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:37
@ LT_CORNER
Identifies a single resolvable source that a text item's ${...} reference depends on.
static TEXT_VAR_REF_KEY FromToken(const wxString &aToken)
Parse a raw token (the text between ${ and }) into a key using lexical classification only — no looku...
KIND
Categorizes a reference by the source that will produce its value.
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
static std::vector< wxString > repeatTexts(const wxString &aBase, int aCount, int aLabelStep)
BOOST_AUTO_TEST_CASE(CollectKeysFindsTitleBlockSources)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
KIBIS_MODEL * model
BOOST_CHECK_EQUAL(result, "25.4")
@ WSG_TEXT_T
Definition typeinfo.h:216
VECTOR2< double > VECTOR2D
Definition vector2d.h:682