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  it = m_actionHotKeys.find( key | ( mod & ~MD_SHIFT ) );
111 
112  if( it == m_actionHotKeys.end() )
113  return false; // no appropriate action found for the hotkey
114  }
115 
116  const std::list<TOOL_ACTION*>& actions = it->second;
117 
118  // Choose the action that has the highest priority on the active tools stack
119  // If there is none, run the global action associated with the hot key
120  int highestPriority = -1, priority = -1;
121  const TOOL_ACTION* context = NULL; // pointer to context action of the highest priority tool
122  std::vector<const TOOL_ACTION*> global; // pointers to global actions
123  // if there is no context action
124 
125  for( const TOOL_ACTION* action : actions )
126  {
127  if( action->GetScope() == AS_GLOBAL )
128  {
129  // Store the global action in case there are no context actions to run
130  global.emplace_back( action );
131  continue;
132  }
133 
134  TOOL_BASE* tool = m_toolMgr->FindTool( action->GetToolName() );
135 
136  if( tool )
137  {
138  // Choose the action that goes to the tool with highest priority
139  // (i.e. is on the top of active tools stack)
140  priority = m_toolMgr->GetPriority( tool->GetId() );
141 
142  if( priority >= 0 && priority > highestPriority )
143  {
144  highestPriority = priority;
145  context = action;
146  }
147  }
148  }
149 
150  if( context )
151  {
152  wxLogTrace( kicadTraceToolStack,
153  "ACTION_MANAGER::RunHotKey Running action %s for hotkey %s", context->GetName(),
154  KeyNameFromKeyCode( aHotKey ) );
155 
156  return m_toolMgr->RunAction( *context, true );
157  }
158  else if( !global.empty() )
159  {
160  for( auto act : global )
161  {
162  wxLogTrace( kicadTraceToolStack,
163  "ACTION_MANAGER::RunHotKey Running action: %s for hotkey %s", act->GetName(),
164  KeyNameFromKeyCode( aHotKey ) );
165 
166  if( m_toolMgr->RunAction( *act, true ) )
167  return true;
168  }
169  }
170 
171  wxLogTrace( kicadTraceToolStack, "ACTION_MANAGER::RunHotKey No action found for key %s",
172  KeyNameFromKeyCode( aHotKey ) );
173 
174  return false;
175 }
176 
177 
178 const std::map<std::string, TOOL_ACTION*>& ACTION_MANAGER::GetActions()
179 {
180  return m_actionNameIndex;
181 }
182 
183 
184 int ACTION_MANAGER::GetHotKey( const TOOL_ACTION& aAction ) const
185 {
186  std::map<int, int>::const_iterator it = m_hotkeys.find( aAction.GetId() );
187 
188  if( it == m_hotkeys.end() )
189  return 0;
190 
191  return it->second;
192 }
193 
194 
195 void ACTION_MANAGER::UpdateHotKeys( bool aFullUpdate )
196 {
197  std::map<std::string, int> legacyHotKeyMap;
198  std::map<std::string, int> userHotKeyMap;
199 
200  m_actionHotKeys.clear();
201  m_hotkeys.clear();
202 
203  if( aFullUpdate )
204  {
206  ReadHotKeyConfig( wxEmptyString, userHotKeyMap );
207  }
208 
209  for( const auto& ii : m_actionNameIndex )
210  {
211  TOOL_ACTION* action = ii.second;
212  int hotkey = 0;
213 
214  if( aFullUpdate )
215  hotkey = processHotKey( action, legacyHotKeyMap, userHotKeyMap );
216  else
217  hotkey = action->GetHotKey();
218 
219  if( hotkey > 0 )
220  m_actionHotKeys[hotkey].push_back( action );
221 
222  m_hotkeys[action->GetId()] = hotkey;
223  }
224 }
225 
226 
227 int ACTION_MANAGER::processHotKey( TOOL_ACTION* aAction, std::map<std::string, int> aLegacyMap,
228  std::map<std::string, int> aHotKeyMap )
229 {
230  aAction->m_hotKey = aAction->m_defaultHotKey;
231 
232  if( !aAction->m_legacyName.empty() && aLegacyMap.count( aAction->m_legacyName ) )
233  aAction->SetHotKey( aLegacyMap[ aAction->m_legacyName ] );
234 
235  if( aHotKeyMap.count( aAction->m_name ) )
236  aAction->SetHotKey( aHotKeyMap[ aAction->m_name ] );
237 
238  return aAction->m_hotKey;
239 }
std::map< int, int > m_hotkeys
Quick action<->hot key lookup
EDA_BASE_FRAME * GetEditFrame() const
Definition: tool_manager.h:268
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
wxString ConfigBaseName()
bool RunAction(const std::string &aActionName, bool aNow=false, T aParam=NULL)
Function RunAction() Runs the specified action.
Definition: tool_manager.h:109
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:50
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
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