QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsshortcutsmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsshortcutsmanager.cpp
3  ---------------------
4  begin : May 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsshortcutsmanager.h"
17 #include "qgslogger.h"
18 #include "qgssettings.h"
19 
20 #include <QShortcut>
21 #include <QRegularExpression>
22 
23 QgsShortcutsManager::QgsShortcutsManager( QObject *parent, const QString &settingsRoot )
24  : QObject( parent )
25  , mSettingsPath( settingsRoot )
26 {
27 }
28 
29 void QgsShortcutsManager::registerAllChildren( QObject *object, bool recursive )
30 {
31  registerAllChildActions( object, recursive );
32  registerAllChildShortcuts( object, recursive );
33 }
34 
35 void QgsShortcutsManager::registerAllChildActions( QObject *object, bool recursive )
36 {
37  if ( recursive )
38  {
39  const QList< QAction * > actions = object->findChildren< QAction * >();
40  const auto constActions = actions;
41  for ( QAction *a : constActions )
42  {
43  registerAction( a, a->shortcut().toString( QKeySequence::NativeText ) );
44  }
45  }
46  else
47  {
48  const auto constChildren = object->children();
49  for ( QObject *child : constChildren )
50  {
51  if ( QAction *a = qobject_cast<QAction *>( child ) )
52  {
53  registerAction( a, a->shortcut().toString( QKeySequence::NativeText ) );
54  }
55  }
56  }
57 }
58 
59 void QgsShortcutsManager::registerAllChildShortcuts( QObject *object, bool recursive )
60 {
61  if ( recursive )
62  {
63  const QList< QShortcut * > shortcuts = object->findChildren< QShortcut * >();
64  const auto constShortcuts = shortcuts;
65  for ( QShortcut *s : constShortcuts )
66  {
67  registerShortcut( s, s->key().toString( QKeySequence::NativeText ) );
68  }
69  }
70  else
71  {
72  const auto constChildren = object->children();
73  for ( QObject *child : constChildren )
74  {
75  if ( QShortcut *s = qobject_cast<QShortcut *>( child ) )
76  {
77  registerShortcut( s, s->key().toString( QKeySequence::NativeText ) );
78  }
79  }
80  }
81 }
82 
83 bool QgsShortcutsManager::registerAction( QAction *action, const QString &defaultSequence )
84 {
85  if ( mActions.contains( action ) )
86  return false; // already registered
87 
88 #ifdef QGISDEBUG
89  // if using a debug build, warn on duplicate actions
90  if ( actionByName( action->text() ) || shortcutByName( action->text() ) )
91  QgsLogger::warning( QStringLiteral( "Duplicate shortcut registered: %1" ).arg( action->text() ) );
92 #endif
93 
94  mActions.insert( action, defaultSequence );
95  connect( action, &QObject::destroyed, this, &QgsShortcutsManager::actionDestroyed );
96 
97  QString actionText = action->text();
98  actionText.remove( '&' ); // remove the accelerator
99 
100  // load overridden value from settings
101  const QgsSettings settings;
102  const QString sequence = settings.value( mSettingsPath + actionText, defaultSequence ).toString();
103 
104  action->setShortcut( sequence );
105  if ( !action->toolTip().isEmpty() )
106  {
107  const QStringList parts = action->toolTip().split( '\n' );
108  QString formatted = QStringLiteral( "<b>%1</b>" ).arg( parts.at( 0 ) );
109  if ( parts.count() > 1 )
110  {
111  for ( int i = 1; i < parts.count(); ++i )
112  formatted += QStringLiteral( "<p>%1</p>" ).arg( parts.at( i ) );
113  }
114 
115  action->setToolTip( formatted );
116  updateActionToolTip( action, sequence );
117  }
118 
119  return true;
120 }
121 
122 bool QgsShortcutsManager::registerShortcut( QShortcut *shortcut, const QString &defaultSequence )
123 {
124 #ifdef QGISDEBUG
125  // if using a debug build, warn on duplicate actions
126  if ( actionByName( shortcut->objectName() ) || shortcutByName( shortcut->objectName() ) )
127  QgsLogger::warning( QStringLiteral( "Duplicate shortcut registered: %1" ).arg( shortcut->objectName() ) );
128 #endif
129 
130  mShortcuts.insert( shortcut, defaultSequence );
131  connect( shortcut, &QObject::destroyed, this, &QgsShortcutsManager::shortcutDestroyed );
132 
133  const QString shortcutName = shortcut->objectName();
134 
135  // load overridden value from settings
136  const QgsSettings settings;
137  const QString keySequence = settings.value( mSettingsPath + shortcutName, defaultSequence ).toString();
138 
139  shortcut->setKey( keySequence );
140 
141  return true;
142 }
143 
145 {
146  if ( !mActions.contains( action ) )
147  return false;
148 
149  mActions.remove( action );
150  return true;
151 }
152 
153 bool QgsShortcutsManager::unregisterShortcut( QShortcut *shortcut )
154 {
155  if ( !mShortcuts.contains( shortcut ) )
156  return false;
157 
158  mShortcuts.remove( shortcut );
159  return true;
160 }
161 
162 QList<QAction *> QgsShortcutsManager::listActions() const
163 {
164  return mActions.keys();
165 }
166 
167 QList<QShortcut *> QgsShortcutsManager::listShortcuts() const
168 {
169  return mShortcuts.keys();
170 }
171 
172 QList<QObject *> QgsShortcutsManager::listAll() const
173 {
174  QList< QObject * > list;
175  ActionsHash::const_iterator actionIt = mActions.constBegin();
176  for ( ; actionIt != mActions.constEnd(); ++actionIt )
177  {
178  list << actionIt.key();
179  }
180  ShortcutsHash::const_iterator shortcutIt = mShortcuts.constBegin();
181  for ( ; shortcutIt != mShortcuts.constEnd(); ++shortcutIt )
182  {
183  list << shortcutIt.key();
184  }
185  return list;
186 }
187 
188 QString QgsShortcutsManager::objectDefaultKeySequence( QObject *object ) const
189 {
190  if ( QAction *action = qobject_cast< QAction * >( object ) )
191  return defaultKeySequence( action );
192  else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( object ) )
193  return defaultKeySequence( shortcut );
194  else
195  return QString();
196 }
197 
198 QString QgsShortcutsManager::defaultKeySequence( QAction *action ) const
199 {
200  return mActions.value( action, QString() );
201 }
202 
203 QString QgsShortcutsManager::defaultKeySequence( QShortcut *shortcut ) const
204 {
205  return mShortcuts.value( shortcut, QString() );
206 }
207 
208 bool QgsShortcutsManager::setKeySequence( const QString &name, const QString &sequence )
209 {
210  if ( QAction *action = actionByName( name ) )
211  return setKeySequence( action, sequence );
212  else if ( QShortcut *shortcut = shortcutByName( name ) )
213  return setKeySequence( shortcut, sequence );
214  else
215  return false;
216 }
217 
218 bool QgsShortcutsManager::setObjectKeySequence( QObject *object, const QString &sequence )
219 {
220  if ( QAction *action = qobject_cast< QAction * >( object ) )
221  return setKeySequence( action, sequence );
222  else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( object ) )
223  return setKeySequence( shortcut, sequence );
224  else
225  return false;
226 }
227 
228 bool QgsShortcutsManager::setKeySequence( QAction *action, const QString &sequence )
229 {
230  action->setShortcut( sequence );
231  this->updateActionToolTip( action, sequence );
232 
233  QString actionText = action->text();
234  actionText.remove( '&' ); // remove the accelerator
235 
236  // save to settings
237  QgsSettings settings;
238  settings.setValue( mSettingsPath + actionText, sequence );
239  return true;
240 }
241 
242 bool QgsShortcutsManager::setKeySequence( QShortcut *shortcut, const QString &sequence )
243 {
244  shortcut->setKey( sequence );
245 
246  const QString shortcutText = shortcut->objectName();
247 
248  // save to settings
249  QgsSettings settings;
250  settings.setValue( mSettingsPath + shortcutText, sequence );
251  return true;
252 }
253 
254 QObject *QgsShortcutsManager::objectForSequence( const QKeySequence &sequence ) const
255 {
256  if ( QAction *action = actionForSequence( sequence ) )
257  return action;
258  else if ( QShortcut *shortcut = shortcutForSequence( sequence ) )
259  return shortcut;
260  else
261  return nullptr;
262 }
263 
264 QAction *QgsShortcutsManager::actionForSequence( const QKeySequence &sequence ) const
265 {
266  if ( sequence.isEmpty() )
267  return nullptr;
268 
269  for ( ActionsHash::const_iterator it = mActions.constBegin(); it != mActions.constEnd(); ++it )
270  {
271  if ( it.key()->shortcut() == sequence )
272  return it.key();
273  }
274 
275  return nullptr;
276 }
277 
278 QShortcut *QgsShortcutsManager::shortcutForSequence( const QKeySequence &sequence ) const
279 {
280  if ( sequence.isEmpty() )
281  return nullptr;
282 
283  for ( ShortcutsHash::const_iterator it = mShortcuts.constBegin(); it != mShortcuts.constEnd(); ++it )
284  {
285  if ( it.key()->key() == sequence )
286  return it.key();
287  }
288 
289  return nullptr;
290 }
291 
292 QAction *QgsShortcutsManager::actionByName( const QString &name ) const
293 {
294  for ( ActionsHash::const_iterator it = mActions.constBegin(); it != mActions.constEnd(); ++it )
295  {
296  if ( it.key()->text() == name )
297  return it.key();
298  }
299 
300  return nullptr;
301 }
302 
303 QShortcut *QgsShortcutsManager::shortcutByName( const QString &name ) const
304 {
305  for ( ShortcutsHash::const_iterator it = mShortcuts.constBegin(); it != mShortcuts.constEnd(); ++it )
306  {
307  if ( it.key()->objectName() == name )
308  return it.key();
309  }
310 
311  return nullptr;
312 }
313 
314 void QgsShortcutsManager::actionDestroyed()
315 {
316  mActions.remove( qobject_cast<QAction *>( sender() ) );
317 }
318 
319 void QgsShortcutsManager::shortcutDestroyed()
320 {
321  mShortcuts.remove( qobject_cast<QShortcut *>( sender() ) );
322 }
323 
324 void QgsShortcutsManager::updateActionToolTip( QAction *action, const QString &sequence )
325 {
326  QString current = action->toolTip();
327  // Remove the old shortcut.
328  const QRegularExpression rx( QStringLiteral( "\\(.*\\)" ) );
329  current.replace( rx, QString() );
330 
331  if ( !sequence.isEmpty() )
332  {
333  action->setToolTip( current + " (" + sequence + ")" );
334  }
335  else
336  {
337  action->setToolTip( current );
338  }
339 }
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
bool setKeySequence(const QString &name, const QString &sequence)
Modifies an action or shortcut's key sequence.
QList< QObject * > listAll() const
Returns a list of both actions and shortcuts in the manager.
QgsShortcutsManager(QObject *parent=nullptr, const QString &settingsRoot="/shortcuts/")
Constructor for QgsShortcutsManager.
QString objectDefaultKeySequence(QObject *object) const
Returns the default sequence for an object (either a QAction or QShortcut).
QList< QShortcut * > listShortcuts() const
Returns a list of shortcuts in the manager.
bool unregisterShortcut(QShortcut *shortcut)
Removes a shortcut from the manager.
bool registerShortcut(QShortcut *shortcut, const QString &defaultSequence=QString())
Registers a QShortcut with the manager so the shortcut can be configured in GUI.
QString defaultKeySequence(QAction *action) const
Returns the default sequence for an action.
bool setObjectKeySequence(QObject *object, const QString &sequence)
Modifies an object's (either a QAction or a QShortcut) key sequence.
bool registerAction(QAction *action, const QString &defaultShortcut=QString())
Registers an action with the manager so the shortcut can be configured in GUI.
void registerAllChildren(QObject *object, bool recursive=false)
Automatically registers all QActions and QShortcuts which are children of the passed object.
QShortcut * shortcutByName(const QString &name) const
Returns a shortcut by its name, or nullptr if nothing found.
void registerAllChildShortcuts(QObject *object, bool recursive=false)
Automatically registers all QShortcuts which are children of the passed object.
QAction * actionByName(const QString &name) const
Returns an action by its name, or nullptr if nothing found.
QShortcut * shortcutForSequence(const QKeySequence &sequence) const
Returns the shortcut which is associated for a key sequence, or nullptr if no shortcut is associated.
QList< QAction * > listActions() const
Returns a list of all actions in the manager.
QAction * actionForSequence(const QKeySequence &sequence) const
Returns the action which is associated for a shortcut sequence, or nullptr if no action is associated...
void registerAllChildActions(QObject *object, bool recursive=false)
Automatically registers all QActions which are children of the passed object.
bool unregisterAction(QAction *action)
Removes an action from the manager.
QObject * objectForSequence(const QKeySequence &sequence) const
Returns the object (QAction or QShortcut) matching the specified key sequence,.