KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_action_manager.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 along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
22#include <vector>
23
24#include <tool/action_manager.h>
25#include <tool/selection.h>
27#include <tool/tool_action.h>
28
29BOOST_AUTO_TEST_SUITE( ActionManagerDispatch )
30
31BOOST_AUTO_TEST_CASE( UserBoundDetection_DefaultUntouched )
32{
33 TOOL_ACTION action(
34 TOOL_ACTION_ARGS().Name( "common.test" ).FriendlyName( "Test" ).Scope( AS_GLOBAL ).DefaultHotkey( 'A' ) );
35
36 BOOST_CHECK( !action.IsHotKeyUserBound( 'A' ) );
37}
38
39BOOST_AUTO_TEST_CASE( UserBoundDetection_CustomValue )
40{
41 TOOL_ACTION action(
42 TOOL_ACTION_ARGS().Name( "common.test" ).FriendlyName( "Test" ).Scope( AS_GLOBAL ).DefaultHotkey( 'A' ) );
43
44 action.SetHotKey( 'B' );
45
46 BOOST_CHECK( action.IsHotKeyUserBound( 'B' ) );
47 BOOST_CHECK( !action.IsHotKeyUserBound( 'A' ) );
48}
49
50BOOST_AUTO_TEST_CASE( UserBoundDetection_IdentityRebindIsIndistinguishable )
51{
52 // Known heuristic limit: explicitly assigning the default value cannot
53 // be distinguished from never touching the action. Document via test.
54 TOOL_ACTION action(
55 TOOL_ACTION_ARGS().Name( "common.test" ).FriendlyName( "Test" ).Scope( AS_GLOBAL ).DefaultHotkey( 'A' ) );
56
57 action.SetHotKey( 'A' );
58
59 BOOST_CHECK( !action.IsHotKeyUserBound( 'A' ) );
60}
61
62BOOST_AUTO_TEST_CASE( UserBoundDetection_AltSlotIndependent )
63{
64 TOOL_ACTION action(
65 TOOL_ACTION_ARGS().Name( "common.test" ).FriendlyName( "Test" ).Scope( AS_GLOBAL ).DefaultHotkey( 'A' ) );
66
67 action.SetHotKey( 'A', 'B' );
68
69 BOOST_CHECK( !action.IsHotKeyUserBound( 'A' ) );
70 BOOST_CHECK( action.IsHotKeyUserBound( 'B' ) );
71}
72
73BOOST_AUTO_TEST_CASE( UserBoundDetection_SharedDefaultCollisionPreserved )
74{
75 // common.* vs frame.* both shipped with the same default key (e.g. 'D'
76 // for common.showDatasheet and pcbnew.Drag45Degree). Neither is
77 // user-bound, so promotion must not fire and original ordering stays.
78 TOOL_ACTION commonAction( TOOL_ACTION_ARGS()
79 .Name( "common.showDatasheet" )
80 .FriendlyName( "Show Datasheet" )
81 .Scope( AS_GLOBAL )
82 .DefaultHotkey( 'D' ) );
83 TOOL_ACTION frameAction( TOOL_ACTION_ARGS()
84 .Name( "pcbnew.dragMove45" )
85 .FriendlyName( "Drag 45" )
86 .Scope( AS_GLOBAL )
87 .DefaultHotkey( 'D' ) );
88
89 BOOST_CHECK( !commonAction.IsHotKeyUserBound( 'D' ) );
90 BOOST_CHECK( !frameAction.IsHotKeyUserBound( 'D' ) );
91}
92
93BOOST_AUTO_TEST_CASE( Promotion_UserBoundFrameActionWins )
94{
95 TOOL_ACTION commonCopy( TOOL_ACTION_ARGS()
96 .Name( "common.Interactive.copy" )
97 .FriendlyName( "Copy" )
98 .Scope( AS_GLOBAL )
99 .DefaultHotkey( 'C' ) );
100 TOOL_ACTION frameCopy( TOOL_ACTION_ARGS()
101 .Name( "pcbnew.InteractiveMove.copyWithReference" )
102 .FriendlyName( "Copy With Reference" )
103 .Scope( AS_GLOBAL )
104 .DefaultHotkey( 'X' ) );
105
106 // User re-binds the frame action onto the key common.Interactive.copy ships with.
107 frameCopy.SetHotKey( 'C' );
108
109 std::vector<const TOOL_ACTION*> global{ &commonCopy, &frameCopy };
110
112
113 BOOST_CHECK_EQUAL( global.front()->GetName(), "pcbnew.InteractiveMove.copyWithReference" );
114}
115
116BOOST_AUTO_TEST_CASE( Promotion_OtherFrameLeavesOrderUnchanged )
117{
118 TOOL_ACTION commonCopy( TOOL_ACTION_ARGS()
119 .Name( "common.Interactive.copy" )
120 .FriendlyName( "Copy" )
121 .Scope( AS_GLOBAL )
122 .DefaultHotkey( 'C' ) );
123 TOOL_ACTION frameCopy( TOOL_ACTION_ARGS()
124 .Name( "pcbnew.InteractiveMove.copyWithReference" )
125 .FriendlyName( "Copy With Reference" )
126 .Scope( AS_GLOBAL )
127 .DefaultHotkey( 'X' ) );
128
129 frameCopy.SetHotKey( 'C' );
130
131 std::vector<const TOOL_ACTION*> global{ &commonCopy, &frameCopy };
132
134
135 BOOST_CHECK_EQUAL( global.front()->GetName(), "common.Interactive.copy" );
136}
137
138BOOST_AUTO_TEST_CASE( Promotion_DefaultBindingLeavesOrderUnchanged )
139{
140 TOOL_ACTION commonCopy( TOOL_ACTION_ARGS()
141 .Name( "common.Interactive.copy" )
142 .FriendlyName( "Copy" )
143 .Scope( AS_GLOBAL )
144 .DefaultHotkey( 'C' ) );
145 TOOL_ACTION frameCopy( TOOL_ACTION_ARGS()
146 .Name( "pcbnew.InteractiveMove.copyWithReference" )
147 .FriendlyName( "Copy With Reference" )
148 .Scope( AS_GLOBAL )
149 .DefaultHotkey( 'C' ) );
150
151 std::vector<const TOOL_ACTION*> global{ &commonCopy, &frameCopy };
152
154
155 BOOST_CHECK_EQUAL( global.front()->GetName(), "common.Interactive.copy" );
156}
157
158BOOST_AUTO_TEST_CASE( HotkeyCondition_FallsBackToEnableWhenUnset )
159{
160 // Without a separate hotkey condition, RunHotKey() must reuse enableCondition,
161 // preserving behavior for the vast majority of actions.
164
166
167 BOOST_CHECK( !cond.enableCondition( empty ) );
168 BOOST_CHECK( !cond.GetHotkeyCondition()( empty ) );
169}
170
171BOOST_AUTO_TEST_CASE( HotkeyCondition_DivergesFromEnableWhenSet )
172{
173 // The #13366 fix greys out the menu (enableCondition) on an empty selection while
174 // immediate-mode rotate/mirror still fire (hotkeyCondition). The two conditions must
175 // be evaluated independently for the same selection.
176 auto alwaysTrue = []( const SELECTION& ) { return true; };
177
180
182
183 BOOST_CHECK( !cond.enableCondition( empty ) ); // menu item greyed out
184 BOOST_CHECK( cond.GetHotkeyCondition()( empty ) ); // hotkey still fires
185}
186
static void PromoteUserBoundFrameAction(std::vector< const TOOL_ACTION * > &aGlobalActions, FRAME_T aFrameType, int aMatchedHotKey)
Reorder global actions sharing a hotkey so that one native to the given frame is tried first when the...
static bool NotEmpty(const SELECTION &aSelection)
Test if there are any items selected.
Build up the properties of a TOOL_ACTION in an incremental manner that is static-construction safe.
Represent a single user action.
bool IsHotKeyUserBound(int aMatchedHotKey) const
Return true if the matched hotkey slot (primary or alternate) holds a value different from its compil...
void SetHotKey(int aKeycode, int aKeycodeAlt=0)
static bool empty(const wxTextEntryBase *aCtrl)
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ FRAME_SCH
Definition frame_type.h:30
Functors that can be used to figure out how the action controls should be displayed in the UI and if ...
SELECTION_CONDITION enableCondition
Returns true if the UI control should be enabled.
ACTION_CONDITIONS & HotkeyEnable(const SELECTION_CONDITION &aCondition)
Set a separate condition for direct command dispatch (hotkeys and navlib buttons).
ACTION_CONDITIONS & Enable(const SELECTION_CONDITION &aCondition)
const SELECTION_CONDITION & GetHotkeyCondition() const
Return the condition that direct command dispatch should use, falling back to enableCondition when no...
BOOST_AUTO_TEST_CASE(UserBoundDetection_DefaultUntouched)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(result, "25.4")
@ AS_GLOBAL
Global action (toolbar/main menu event, global shortcut)
Definition tool_action.h:45