QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 #include <QWidgetAction>
23 
24 QgsShortcutsManager::QgsShortcutsManager( QObject *parent, const QString &settingsRoot )
25  : QObject( parent )
26  , mSettingsPath( settingsRoot )
27 {
28 }
29 
30 void QgsShortcutsManager::registerAllChildren( QObject *object, bool recursive )
31 {
32  registerAllChildActions( object, recursive );
33  registerAllChildShortcuts( object, recursive );
34 }
35 
36 void QgsShortcutsManager::registerAllChildActions( QObject *object, bool recursive )
37 {
38  if ( recursive )
39  {
40  const QList< QAction * > actions = object->findChildren< QAction * >();
41  for ( QAction *a : actions )
42  {
43  registerAction( a, a->shortcut().toString( QKeySequence::NativeText ) );
44  }
45  }
46  else
47  {
48  const QList< QObject *> children = object->children();
49  for ( QObject *child : children )
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 ( qobject_cast< QWidgetAction * >( action ) )
86  return false;
87 
88  if ( mActions.contains( action ) )
89  return false; // already registered
90 
91 #ifdef QGISDEBUG
92  // if using a debug build, warn on duplicate or non-compliant actions
93  if ( action->text().isEmpty() )
94  {
95  QgsLogger::warning( QStringLiteral( "Action has no text set: %1" ).arg( action->objectName() ) );
96  return false;
97  }
98  else if ( actionByName( action->text() ) || shortcutByName( action->text() ) )
99  QgsLogger::warning( QStringLiteral( "Duplicate shortcut registered: %1" ).arg( action->text() ) );
100 #endif
101 
102  mActions.insert( action, defaultSequence );
103  connect( action, &QObject::destroyed, this, &QgsShortcutsManager::actionDestroyed );
104 
105  QString actionText = action->text();
106  actionText.remove( '&' ); // remove the accelerator
107 
108  // load overridden value from settings
109  const QgsSettings settings;
110  const QString sequence = settings.value( mSettingsPath + actionText, defaultSequence ).toString();
111 
112  action->setShortcut( sequence );
113  if ( !action->toolTip().isEmpty() )
114  {
115  const QStringList parts = action->toolTip().split( '\n' );
116  QString formatted = QStringLiteral( "<b>%1</b>" ).arg( parts.at( 0 ) );
117  if ( parts.count() > 1 )
118  {
119  for ( int i = 1; i < parts.count(); ++i )
120  formatted += QStringLiteral( "<p>%1</p>" ).arg( parts.at( i ) );
121  }
122 
123  action->setToolTip( formatted );
124  updateActionToolTip( action, sequence );
125  }
126 
127  return true;
128 }
129 
130 bool QgsShortcutsManager::registerShortcut( QShortcut *shortcut, const QString &defaultSequence )
131 {
132 #ifdef QGISDEBUG
133  // if using a debug build, warn on duplicate or non-compliant actions
134  if ( shortcut->objectName().isEmpty() )
135  QgsLogger::warning( QStringLiteral( "Shortcut has no object name set: %1" ).arg( shortcut->key().toString() ) );
136  else if ( actionByName( shortcut->objectName() ) || shortcutByName( shortcut->objectName() ) )
137  QgsLogger::warning( QStringLiteral( "Duplicate shortcut registered: %1" ).arg( shortcut->objectName() ) );
138 #endif
139 
140  mShortcuts.insert( shortcut, defaultSequence );
141  connect( shortcut, &QObject::destroyed, this, &QgsShortcutsManager::shortcutDestroyed );
142 
143  const QString shortcutName = shortcut->objectName();
144 
145  // load overridden value from settings
146  const QgsSettings settings;
147  const QString keySequence = settings.value( mSettingsPath + shortcutName, defaultSequence ).toString();
148 
149  shortcut->setKey( keySequence );
150 
151  return true;
152 }
153 
155 {
156  if ( !mActions.contains( action ) )
157  return false;
158 
159  mActions.remove( action );
160  return true;
161 }
162 
163 bool QgsShortcutsManager::unregisterShortcut( QShortcut *shortcut )
164 {
165  if ( !mShortcuts.contains( shortcut ) )
166  return false;
167 
168  mShortcuts.remove( shortcut );
169  return true;
170 }
171 
172 QList<QAction *> QgsShortcutsManager::listActions() const
173 {
174  return mActions.keys();
175 }
176 
177 QList<QShortcut *> QgsShortcutsManager::listShortcuts() const
178 {
179  return mShortcuts.keys();
180 }
181 
182 QList<QObject *> QgsShortcutsManager::listAll() const
183 {
184  QList< QObject * > list;
185  ActionsHash::const_iterator actionIt = mActions.constBegin();
186  for ( ; actionIt != mActions.constEnd(); ++actionIt )
187  {
188  list << actionIt.key();
189  }
190  ShortcutsHash::const_iterator shortcutIt = mShortcuts.constBegin();
191  for ( ; shortcutIt != mShortcuts.constEnd(); ++shortcutIt )
192  {
193  list << shortcutIt.key();
194  }
195  return list;
196 }
197 
198 QString QgsShortcutsManager::objectDefaultKeySequence( QObject *object ) const
199 {
200  if ( QAction *action = qobject_cast< QAction * >( object ) )
201  return defaultKeySequence( action );
202  else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( object ) )
203  return defaultKeySequence( shortcut );
204  else
205  return QString();
206 }
207 
208 QString QgsShortcutsManager::defaultKeySequence( QAction *action ) const
209 {
210  return mActions.value( action, QString() );
211 }
212 
213 QString QgsShortcutsManager::defaultKeySequence( QShortcut *shortcut ) const
214 {
215  return mShortcuts.value( shortcut, QString() );
216 }
217 
218 bool QgsShortcutsManager::setKeySequence( const QString &name, const QString &sequence )
219 {
220  if ( QAction *action = actionByName( name ) )
221  return setKeySequence( action, sequence );
222  else if ( QShortcut *shortcut = shortcutByName( name ) )
223  return setKeySequence( shortcut, sequence );
224  else
225  return false;
226 }
227 
228 bool QgsShortcutsManager::setObjectKeySequence( QObject *object, const QString &sequence )
229 {
230  if ( QAction *action = qobject_cast< QAction * >( object ) )
231  return setKeySequence( action, sequence );
232  else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( object ) )
233  return setKeySequence( shortcut, sequence );
234  else
235  return false;
236 }
237 
238 bool QgsShortcutsManager::setKeySequence( QAction *action, const QString &sequence )
239 {
240  action->setShortcut( sequence );
241  this->updateActionToolTip( action, sequence );
242 
243  QString actionText = action->text();
244  actionText.remove( '&' ); // remove the accelerator
245 
246  // save to settings
247  QgsSettings settings;
248  settings.setValue( mSettingsPath + actionText, sequence );
249  return true;
250 }
251 
252 bool QgsShortcutsManager::setKeySequence( QShortcut *shortcut, const QString &sequence )
253 {
254  shortcut->setKey( sequence );
255 
256  const QString shortcutText = shortcut->objectName();
257 
258  // save to settings
259  QgsSettings settings;
260  settings.setValue( mSettingsPath + shortcutText, sequence );
261  return true;
262 }
263 
264 QObject *QgsShortcutsManager::objectForSequence( const QKeySequence &sequence ) const
265 {
266  if ( QAction *action = actionForSequence( sequence ) )
267  return action;
268  else if ( QShortcut *shortcut = shortcutForSequence( sequence ) )
269  return shortcut;
270  else
271  return nullptr;
272 }
273 
274 QAction *QgsShortcutsManager::actionForSequence( const QKeySequence &sequence ) const
275 {
276  if ( sequence.isEmpty() )
277  return nullptr;
278 
279  for ( ActionsHash::const_iterator it = mActions.constBegin(); it != mActions.constEnd(); ++it )
280  {
281  if ( it.key()->shortcut() == sequence )
282  return it.key();
283  }
284 
285  return nullptr;
286 }
287 
288 QShortcut *QgsShortcutsManager::shortcutForSequence( const QKeySequence &sequence ) const
289 {
290  if ( sequence.isEmpty() )
291  return nullptr;
292 
293  for ( ShortcutsHash::const_iterator it = mShortcuts.constBegin(); it != mShortcuts.constEnd(); ++it )
294  {
295  if ( it.key()->key() == sequence )
296  return it.key();
297  }
298 
299  return nullptr;
300 }
301 
302 QAction *QgsShortcutsManager::actionByName( const QString &name ) const
303 {
304  for ( ActionsHash::const_iterator it = mActions.constBegin(); it != mActions.constEnd(); ++it )
305  {
306  if ( it.key()->text() == name )
307  return it.key();
308  }
309 
310  return nullptr;
311 }
312 
313 QShortcut *QgsShortcutsManager::shortcutByName( const QString &name ) const
314 {
315  for ( ShortcutsHash::const_iterator it = mShortcuts.constBegin(); it != mShortcuts.constEnd(); ++it )
316  {
317  if ( it.key()->objectName() == name )
318  return it.key();
319  }
320 
321  return nullptr;
322 }
323 
324 void QgsShortcutsManager::actionDestroyed()
325 {
326  mActions.remove( qobject_cast<QAction *>( sender() ) );
327 }
328 
329 void QgsShortcutsManager::shortcutDestroyed()
330 {
331  mShortcuts.remove( qobject_cast<QShortcut *>( sender() ) );
332 }
333 
334 void QgsShortcutsManager::updateActionToolTip( QAction *action, const QString &sequence )
335 {
336  QString current = action->toolTip();
337  // Remove the old shortcut.
338  const QRegularExpression rx( QStringLiteral( "\\(.*\\)" ) );
339  current.replace( rx, QString() );
340 
341  if ( !sequence.isEmpty() )
342  {
343  action->setToolTip( current + " (" + sequence + ")" );
344  }
345  else
346  {
347  action->setToolTip( current );
348  }
349 }
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:122
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
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,.