KiCad PCB EDA Suite
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 (C) 2013 CERN
5  * Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Maciej Suminski <maciej.suminski@cern.ch>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include <eda_draw_frame.h>
27 #include <tool/action_manager.h>
28 #include <tool/tool_action.h>
29 #include <tool/tool_manager.h>
30 #include <trace_helpers.h>
31 
32 #include <hotkeys_basic.h>
33 #include <cctype>
34 
36  m_toolMgr( aToolManager )
37 {
38  // Register known actions
39  std::list<TOOL_ACTION*>& actionList = GetActionList();
40 
41  for( TOOL_ACTION* action : actionList )
42  {
43  if( action->m_id == -1 )
44  action->m_id = MakeActionId( action->m_name );
45 
46  RegisterAction( action );
47  }
48 }
49 
50 
52 {
53 }
54 
55 
57 {
58  // TOOL_ACTIONs are supposed to be named [appName.]toolName.actionName (with dots between)
59  // action name without specifying at least toolName is not valid
60  wxASSERT( aAction->GetName().find( '.', 0 ) != std::string::npos );
61 
62  // TOOL_ACTIONs must have unique names & ids
63  wxASSERT( m_actionNameIndex.find( aAction->m_name ) == m_actionNameIndex.end() );
64 
65  m_actionNameIndex[aAction->m_name] = aAction;
66 }
67 
68 
69 int ACTION_MANAGER::MakeActionId( const std::string& aActionName )
70 {
71  static int currentActionId = 1;
72 
73  return currentActionId++;
74 }
75 
76 
77 TOOL_ACTION* ACTION_MANAGER::FindAction( const std::string& aActionName ) const
78 {
79  std::map<std::string, TOOL_ACTION*>::const_iterator it = m_actionNameIndex.find( aActionName );
80 
81  if( it != m_actionNameIndex.end() )
82  return it->second;
83 
84  return NULL;
85 }
86 
87 
88 bool ACTION_MANAGER::RunHotKey( int aHotKey ) const
89 {
90  int key = aHotKey & ~MD_MODIFIER_MASK;
91  int mod = aHotKey & MD_MODIFIER_MASK;
92 
93  if( key >= 'a' && key <= 'z' )
94  key = std::toupper( key );
95 
96  wxLogTrace( kicadTraceToolStack, "ACTION_MANAGER::RunHotKey Key: %s",
97  KeyNameFromKeyCode( aHotKey ) );
98 
99  HOTKEY_LIST::const_iterator it = m_actionHotKeys.find( key | mod );
100 
101  // If no luck, try without Shift, to handle keys that require it
102  // e.g. to get ? you need to press Shift+/ without US keyboard layout
103  // Hardcoding ? as Shift+/ is a bad idea, as on another layout you may need to press a
104  // different combination
105  if( it == m_actionHotKeys.end() )
106  {
107  wxLogTrace( kicadTraceToolStack,
108  "ACTION_MANAGER::RunHotKey No actions found, searching with key: %s",
109  KeyNameFromKeyCode( key | ( mod & ~MD_SHIFT ) ) );
110 
111  it = m_actionHotKeys.find( key | ( mod & ~MD_SHIFT ) );
112 
113  if( it == m_actionHotKeys.end() )
114  return false; // no appropriate action found for the hotkey
115  }
116 
117  const std::list<TOOL_ACTION*>& actions = it->second;
118 
119  // Choose the action that has the highest priority on the active tools stack
120  // If there is none, run the global action associated with the hot key
121  int highestPriority = -1, priority = -1;
122  const TOOL_ACTION* context = NULL; // pointer to context action of the highest priority tool
123  std::vector<const TOOL_ACTION*> global; // pointers to global actions
124  // if there is no context action
125 
126  for( const TOOL_ACTION* action : actions )
127  {
128  if( action->GetScope() == AS_GLOBAL )
129  {
130  // Store the global action in case there are no context actions to run
131  global.emplace_back( action );
132  continue;
133  }
134 
135  TOOL_BASE* tool = m_toolMgr->FindTool( action->GetToolName() );
136 
137  if( tool )
138  {
139  // Choose the action that goes to the tool with highest priority
140  // (i.e. is on the top of active tools stack)
141  priority = m_toolMgr->GetPriority( tool->GetId() );
142 
143  if( priority >= 0 && priority > highestPriority )
144  {
145  highestPriority = priority;
146  context = action;
147  }
148  }
149  }
150 
151  if( context )
152  {
153  wxLogTrace( kicadTraceToolStack,
154  "ACTION_MANAGER::RunHotKey Running context action %s for hotkey %s",
155  context->GetName(),
156  KeyNameFromKeyCode( aHotKey ) );
157 
158  return m_toolMgr->RunAction( *context, true );
159  }
160  else if( !global.empty() )
161  {
162  for( auto act : global )
163  {
164  wxLogTrace( kicadTraceToolStack,
165  "ACTION_MANAGER::RunHotKey Running global action: %s for hotkey %s",
166  act->GetName(),
167  KeyNameFromKeyCode( aHotKey ) );
168 
169  if( m_toolMgr->RunAction( *act, true ) )
170  return true;
171  }
172  }
173 
174  wxLogTrace( kicadTraceToolStack,
175  "ACTION_MANAGER::RunHotKey No action found for key %s",
176  KeyNameFromKeyCode( aHotKey ) );
177 
178  return false;
179 }
180 
181 
182 const std::map<std::string, TOOL_ACTION*>& ACTION_MANAGER::GetActions()
183 {
184  return m_actionNameIndex;
185 }
186 
187 
188 int ACTION_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const
189 {
190  std::map<int, int>::const_iterator it = m_hotkeys.find( aAction.GetId() );
191 
192  if( it == m_hotkeys.end() )
193  return 0;
194 
195  return it->second;
196 }
197 
198 
199 void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate )
200 {
201  std::map<std::string, int> legacyHotKeyMap;
202  std::map<std::string, int> userHotKeyMap;
203 
204  m_actionHotKeys.clear();
205  m_hotkeys.clear();
206 
207  if( aFullUpdate && m_toolMgr->GetToolHolder() )
208  {
210  ReadHotKeyConfig( wxEmptyString, userHotKeyMap );
211  }
212 
213  for( const auto& ii : m_actionNameIndex )
214  {
215  TOOL_ACTION* action = ii.second;
216  int hotkey = 0;
217 
218  if( aFullUpdate )
219  hotkey = processHotKey( action, legacyHotKeyMap, userHotKeyMap );
220  else
221  hotkey = action->GetHotKey();
222 
223  if( hotkey > 0 )
224  m_actionHotKeys[hotkey].push_back( action );
225 
226  m_hotkeys[action->GetId()] = hotkey;
227  }
228 }
229 
230 
231 int ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction, std::map<std::string, int> aLegacyMap,
232  std::map<std::string, int> aHotKeyMap )
233 {
234  aAction->m_hotKey = aAction->m_defaultHotKey;
235 
236  if( !aAction->m_legacyName.empty() && aLegacyMap.count( aAction->m_legacyName ) )
237  aAction->SetHotKey( aLegacyMap[ aAction->m_legacyName ] );
238 
239  if( aHotKeyMap.count( aAction->m_name ) )
240  aAction->SetHotKey( aHotKeyMap[ aAction->m_name ] );
241 
242  return aAction->m_hotKey;
243 }
std::map< int, int > m_hotkeys
Quick action<->hot key lookup
int GetPriority(int aToolId) const
Returns priority of a given tool.
static int MakeActionId(const std::string &aActionName)
Generates an unique ID from for an action with given name.
TOOL_ID GetId() const
Function GetId() Returns the unique identifier of the tool.
Definition: tool_base.h:121
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:140
virtual wxString ConfigBaseName()
Definition: tools_holder.h:121
void UpdateHotKeys(bool aFullUpdate)
Function UpdateHotKeys() Optionally reads the hotkey config files and then rebuilds the internal hotk...
~ACTION_MANAGER()
Destructor.
TOOL_BASE * FindTool(int aId) const
Function FindTool() Searches for a tool with given ID.
static std::list< TOOL_ACTION * > & GetActionList()
Function GetActionList() Returns list of TOOL_ACTIONs.
std::string m_name
Name of the action (convention is "app.tool.actionName")
Definition: tool_action.h:160
const std::map< std::string, TOOL_ACTION * > & GetActions()
Get a list of currently-registered actions mapped by their name.
TOOL_ACTION * FindAction(const std::string &aActionName) const
Function FindAction() Finds an action with a given name (if there is one available).
bool RunHotKey(int aHotKey) const
Function RunHotKey() Runs an action associated with a hotkey (if there is one available).
void ReadHotKeyConfig(wxString fileName, std::map< std::string, int > &aHotKeys)
Function ReadotKeyConfig Reads a hotkey config file into a map.
TOOL_MANAGER.
Definition: tool_manager.h:51
const std::string m_legacyName
Definition: tool_action.h:165
#define NULL
int ReadLegacyHotkeyConfig(const wxString &aAppname, std::map< std::string, int > &aMap)
Function ReadLegacyHotkeyConfig Read configuration data and fill the current hotkey list with hotkeys...
int GetHotKey(const TOOL_ACTION &aAction) const
Function GetHotKey() Returns the hot key associated with a given action or 0 if there is none.
ACTION_MANAGER(TOOL_MANAGER *aToolManager)
Constructor.
wxLogTrace helper definitions.
void SetHotKey(int aKeycode)
Definition: tool_action.cpp:94
All active tools
Definition: tool_event.h:147
std::map< std::string, TOOL_ACTION * > m_actionNameIndex
Map for indexing actions by their names
HOTKEY_LIST m_actionHotKeys
TOOL_MANAGER * m_toolMgr
Tool manager needed to run actions
TOOLS_HOLDER * GetToolHolder() const
Definition: tool_manager.h:295
void RegisterAction(TOOL_ACTION *aAction)
Function RegisterAction() Adds a tool action to the manager and sets it up.
int GetId() const
Function GetId() Returns the unique id of the TOOL_ACTION object.
Definition: tool_action.h:100
int processHotKey(TOOL_ACTION *aAction, std::map< std::string, int > aLegacyMap, std::map< std::string, int > aHotKeyMap)
TOOL_BASE.
Definition: tool_base.h:67
TOOL_ACTION.
Definition: tool_action.h:46
const wxChar *const kicadTraceToolStack
Flag to enable tracing of the tool handling stack.
wxString KeyNameFromKeyCode(int aKeycode, bool *aIsFound)
Function KeyNameFromKeyCode return the key name from the key code Only some wxWidgets key values are ...
int GetHotKey() const
Function GetHotKey() Returns the hotkey keycode which initiates the action.
Definition: tool_action.h:90
const int m_defaultHotKey
Definition: tool_action.h:163
const std::string & GetName() const
Function GetName() Returns name of the action.
Definition: tool_action.h:78