QGIS API Documentation 3.27.0-Master (f261cc1f8b)
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
24QgsShortcutsManager::QgsShortcutsManager( QObject *parent, const QString &settingsRoot )
25 : QObject( parent )
26 , mSettingsPath( settingsRoot )
27{
28}
29
30void QgsShortcutsManager::registerAllChildren( QObject *object, bool recursive )
31{
32 registerAllChildActions( object, recursive );
33 registerAllChildShortcuts( object, recursive );
34}
35
36void 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
59void 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
83bool 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
130bool 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
164{
165 if ( !mShortcuts.contains( shortcut ) )
166 return false;
167
168 mShortcuts.remove( shortcut );
169 return true;
170}
171
172QList<QAction *> QgsShortcutsManager::listActions() const
173{
174 return mActions.keys();
175}
176
177QList<QShortcut *> QgsShortcutsManager::listShortcuts() const
178{
179 return mShortcuts.keys();
180}
181
182QList<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
198QString 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
208QString QgsShortcutsManager::defaultKeySequence( QAction *action ) const
209{
210 return mActions.value( action, QString() );
211}
212
213QString QgsShortcutsManager::defaultKeySequence( QShortcut *shortcut ) const
214{
215 return mShortcuts.value( shortcut, QString() );
216}
217
218bool 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
228bool 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
238bool 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
252bool 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
264QObject *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
274QAction *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
288QShortcut *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
302QAction *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
313QShortcut *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
324void QgsShortcutsManager::actionDestroyed()
325{
326 mActions.remove( qobject_cast<QAction *>( sender() ) );
327}
328
329void QgsShortcutsManager::shortcutDestroyed()
330{
331 mShortcuts.remove( qobject_cast<QShortcut *>( sender() ) );
332}
333
334void 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,.