KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_footprint_editor_tabs.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 <memory>
23
24#include <functional>
25#include <vector>
26
27#include <board.h>
28#include <footprint.h>
29#include <lib_id.h>
30#include <pcb_text.h>
31
35
36
38static std::unique_ptr<BOARD> makeFpHolder( const wxString& aLib, const wxString& aName )
39{
40 auto board = std::make_unique<BOARD>();
41 board->SetBoardUse( BOARD_USE::FPHOLDER );
42
43 FOOTPRINT* fp = new FOOTPRINT( board.get() );
44 fp->SetFPID( LIB_ID( aLib, aName ) );
45 board->Add( fp );
46
47 return board;
48}
49
50
53{
54public:
55 explicit INSTRUMENTED_BOARD( int* aDtorCounter ) : m_dtorCounter( aDtorCounter ) {}
56
58 {
59 if( m_dtorCounter )
60 ( *m_dtorCounter )++;
61 }
62
63private:
65};
66
67
68BOOST_AUTO_TEST_SUITE( FootprintEditorTabs )
69
70
71
73BOOST_AUTO_TEST_CASE( ReusedPreviewTabBoardOutlivesInstall )
74{
75 int dtorCount = 0;
76
77 auto oldBoard = std::make_unique<INSTRUMENTED_BOARD>( &dtorCount );
78 oldBoard->SetBoardUse( BOARD_USE::FPHOLDER );
79 BOARD* oldBoardRaw = oldBoard.get();
80
81 std::vector<std::unique_ptr<FOOTPRINT_EDITOR_TAB_CONTEXT>> contexts;
82 contexts.push_back( std::make_unique<FOOTPRINT_EDITOR_TAB_CONTEXT>( wxS( "Lib" ), wxS( "A" ),
83 std::move( oldBoard ) ) );
84
85 auto newCtx = std::make_unique<FOOTPRINT_EDITOR_TAB_CONTEXT>(
86 wxS( "Lib" ), wxS( "B" ), makeFpHolder( wxS( "Lib" ), wxS( "B" ) ) );
87 FOOTPRINT_EDITOR_TAB_CONTEXT* newRaw = newCtx.get();
88
89 int dtorCountDuringInstall = -1;
90 BOARD* protectedBoardDuringInstall = nullptr;
91
93 contexts, 0, std::move( newCtx ),
94 [&]( const FOOTPRINT_EDITOR_TAB_CONTEXT& aDisplaced )
95 {
96 dtorCountDuringInstall = dtorCount;
97 protectedBoardDuringInstall = aDisplaced.GetBoard();
98 } );
99
100 // The displaced board is still alive and identifiable while the successor is installed, and freed only afterwards.
101 BOOST_CHECK_EQUAL( dtorCountDuringInstall, 0 );
102 BOOST_CHECK_EQUAL( protectedBoardDuringInstall, oldBoardRaw );
103 BOOST_CHECK_EQUAL( dtorCount, 1 );
104
105 // The slot holds the successor, stays index-aligned, and is returned raw.
106 BOOST_REQUIRE_EQUAL( contexts.size(), 1u );
107 BOOST_CHECK_EQUAL( contexts[0].get(), newRaw );
108 BOOST_CHECK_EQUAL( installed, newRaw );
109 BOOST_CHECK_EQUAL( contexts[0]->GetName(), wxS( "B" ) );
110}
111
112
115BOOST_AUTO_TEST_CASE( NewFootprintDetachedFromOutgoingBoard )
116{
117 int dtorCount = 0;
118
119 auto outgoing = std::make_unique<INSTRUMENTED_BOARD>( &dtorCount );
120 outgoing->SetBoardUse( BOARD_USE::FPHOLDER );
121
122 // CreateNewFootprint parents the footprint to the board without adding it, and gives it default
123 // text items, so the copy constructor reaches FOOTPRINT::Add() and from there GetBoard().
124 auto fp = std::make_unique<FOOTPRINT>( outgoing.get() );
125 fp->SetFPID( LIB_ID( wxS( "Lib" ), wxS( "Untitled" ) ) );
126 fp->Add( new PCB_TEXT( fp.get() ), ADD_MODE::APPEND );
127
128 BOOST_CHECK( FOOTPRINT_EDIT_FRAME::prepareFootprintTabHandoff( fp.get(), true ) );
129 BOOST_CHECK( fp->GetBoard() == nullptr );
130
131 outgoing.reset();
132 BOOST_REQUIRE_EQUAL( dtorCount, 1 );
133
134 std::unique_ptr<FOOTPRINT> clone( static_cast<FOOTPRINT*>( fp->Clone() ) );
135
136 BOOST_CHECK( clone->GetBoard() == nullptr );
137 BOOST_CHECK_EQUAL( clone->GraphicalItems().size(), 1u );
138}
139
140
143BOOST_AUTO_TEST_CASE( BoardSourcedFootprintKeepsItsBoard )
144{
145 std::unique_ptr<BOARD> board = makeFpHolder( wxS( "Lib" ), wxS( "R_0402" ) );
146
147 FOOTPRINT* fp = board->GetFirstFootprint();
148 fp->SetLink( KIID() );
149
150 BOOST_CHECK( !FOOTPRINT_EDIT_FRAME::prepareFootprintTabHandoff( fp, true ) );
151 BOOST_CHECK_EQUAL( fp->GetBoard(), board.get() );
152}
153
154
157BOOST_AUTO_TEST_CASE( TablessAndAnonymousLoadsKeepTheirBoard )
158{
159 std::unique_ptr<BOARD> board = makeFpHolder( wxS( "Lib" ), wxS( "R_0402" ) );
160
161 FOOTPRINT* fp = board->GetFirstFootprint();
162
163 BOOST_CHECK( !FOOTPRINT_EDIT_FRAME::prepareFootprintTabHandoff( fp, false ) );
164 BOOST_CHECK_EQUAL( fp->GetBoard(), board.get() );
165
166 // An imported footprint carries no nickname, so there is no library tab for it to land on.
167 fp->SetFPID( LIB_ID( wxEmptyString, wxS( "R_0402" ) ) );
168
169 BOOST_CHECK( !FOOTPRINT_EDIT_FRAME::prepareFootprintTabHandoff( fp, true ) );
170 BOOST_CHECK_EQUAL( fp->GetBoard(), board.get() );
171
172 BOOST_CHECK( !FOOTPRINT_EDIT_FRAME::prepareFootprintTabHandoff( nullptr, true ) );
173}
174
175
176BOOST_AUTO_TEST_CASE( ContextIdentityAndDirty )
177{
178 std::unique_ptr<BOARD> board = makeFpHolder( wxS( "Resistors" ), wxS( "R_0402" ) );
179 BOARD* raw = board.get();
180
181 FOOTPRINT_EDITOR_TAB_CONTEXT ctx( wxS( "Resistors" ), wxS( "R_0402" ), std::move( board ) );
182
183 BOOST_CHECK_EQUAL( ctx.GetTabKey(), wxS( "Resistors:R_0402" ) );
184 BOOST_CHECK_EQUAL( ctx.GetDisplayName(), wxS( "R_0402" ) );
185
186 BOOST_CHECK_EQUAL( ctx.GetBoard(), raw );
187
188 BOOST_CHECK( !ctx.IsModified() );
189
190 ctx.SetModified( true );
191 BOOST_CHECK( ctx.IsModified() );
192
193 ctx.SetModified( false );
194 BOOST_CHECK( !ctx.IsModified() );
195}
196
197
198BOOST_AUTO_TEST_CASE( ContextEmptyBoardIsNeverDirty )
199{
200 auto board = std::make_unique<BOARD>();
201 board->SetBoardUse( BOARD_USE::FPHOLDER );
202
203 FOOTPRINT_EDITOR_TAB_CONTEXT ctx( wxS( "Lib" ), wxS( "Empty" ), std::move( board ) );
204
205 ctx.SetModified( true );
206 BOOST_CHECK( !ctx.IsModified() );
207}
208
209
212BOOST_AUTO_TEST_CASE( InstanceTabContextIsTransientAndKeyedByUuid )
213{
214 KIID sourceUuid;
215 std::unique_ptr<BOARD> board = makeFpHolder( wxS( "Resistors" ), wxS( "R_0402" ) );
216 BOARD* raw = board.get();
217
218 FOOTPRINT_EDITOR_TAB_CONTEXT ctx( sourceUuid, wxS( "R5" ), std::move( board ) );
219
220 BOOST_CHECK( ctx.IsTransient() );
221 BOOST_CHECK( ctx.IsFromBoard() );
222 BOOST_CHECK_EQUAL( ctx.GetReference(), wxS( "R5" ) );
223 BOOST_CHECK_EQUAL( ctx.GetSourceUuid().AsString(), sourceUuid.AsString() );
224 BOOST_CHECK_EQUAL( ctx.GetBoard(), raw );
225 BOOST_CHECK_EQUAL( ctx.GetDisplayName(), wxS( "R5" ) );
226
229 BOOST_CHECK( ctx.GetTabKey() != wxS( "Resistors:R_0402" ) );
230 BOOST_CHECK( ctx.GetTabKey().StartsWith( wxString( wxT( "\x01" ) ) ) );
231
232 // The remap is mutable and survives on the context for save-back.
233 KIID editorId, boardId;
234 ctx.BoardFootprintUuids()[editorId] = boardId;
235 BOOST_REQUIRE_EQUAL( ctx.BoardFootprintUuids().count( editorId ), 1u );
236 BOOST_CHECK_EQUAL( ctx.BoardFootprintUuids()[editorId].AsString(), boardId.AsString() );
237}
238
239
240BOOST_AUTO_TEST_CASE( SettingsOpenTabsRoundTrip )
241{
243
244 settings.m_OpenTabs.clear();
245 settings.m_OpenTabs.push_back( { wxS( "Resistors" ), wxS( "R_0402" ) } );
246 settings.m_OpenTabs.push_back( { wxS( "Caps" ), wxS( "C_0603" ) } );
247 settings.m_ActiveTab = wxS( "Caps:C_0603" );
248
249 settings.Store();
250
251 settings.m_OpenTabs.clear();
252 settings.m_ActiveTab = wxEmptyString;
253
254 settings.Load();
255
256 BOOST_REQUIRE_EQUAL( settings.m_OpenTabs.size(), 2u );
257 BOOST_CHECK_EQUAL( settings.m_OpenTabs[0].m_lib, wxS( "Resistors" ) );
258 BOOST_CHECK_EQUAL( settings.m_OpenTabs[0].m_fpName, wxS( "R_0402" ) );
259 BOOST_CHECK_EQUAL( settings.m_OpenTabs[1].m_lib, wxS( "Caps" ) );
260 BOOST_CHECK_EQUAL( settings.m_OpenTabs[1].m_fpName, wxS( "C_0603" ) );
261 BOOST_CHECK_EQUAL( settings.m_ActiveTab, wxS( "Caps:C_0603" ) );
262}
263
264
@ FPHOLDER
Definition board.h:365
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:373
BOARD()
Definition board.cpp:91
wxString m_ActiveTab
Tab key ("lib:fpName") of the tab that was active when the editor last closed.
One open footprint tab owning its fp-holder board, lent to the frame by raw pointer while active.
std::map< KIID, KIID > & BoardFootprintUuids()
Editor-to-board UUID remap captured at load, used by SaveFootprintToBoard to restore the original boa...
bool IsTransient() const
True for a tab that is session-only and never persisted.
BOARD * GetBoard() const
The fp-holder board owned by this context.
wxString GetDisplayName() const override
Short label shown on the tab.
static wxString MakeInstanceTabKey(const KIID &aSourceUuid)
De-duplication key for a placed board footprint, in a namespace disjoint from library keys.
bool IsModified() const override
True only when dirty and the board actually holds a footprint to edit.
wxString GetTabKey() const override
Stable identity for persistence and de-duplication.
static FOOTPRINT_EDITOR_TAB_CONTEXT * placeReusedTabContext(std::vector< std::unique_ptr< FOOTPRINT_EDITOR_TAB_CONTEXT > > &aContexts, int aSlot, std::unique_ptr< FOOTPRINT_EDITOR_TAB_CONTEXT > aNew, const std::function< void(const FOOTPRINT_EDITOR_TAB_CONTEXT &)> &aInstallSuccessor)
Replace the tab context at aSlot with aNew, running aInstallSuccessor before the displaced context is...
static bool prepareFootprintTabHandoff(FOOTPRINT *aFootprint, bool aHasTabs)
Decide whether aFootprint opens in its own tab and, if so, detach it from the board it arrived parent...
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:445
void SetLink(const KIID &aLink)
Definition footprint.h:1192
INSTRUMENTED_BOARD(int *aDtorCounter)
virtual void Load()
Updates the parameters of this object based on the current JSON document contents.
virtual bool Store()
Stores the current parameters into the JSON document represented by this object Note: this doesn't do...
Definition kiid.h:46
wxString AsString() const
Definition kiid.cpp:264
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_CASE(ReusedPreviewTabBoardOutlivesInstall)
Reusing a preview tab must install the successor board before the displaced board is freed,...
static std::unique_ptr< BOARD > makeFpHolder(const wxString &aLib, const wxString &aName)
Build an fp-holder BOARD carrying a single footprint with the given identity.
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")