24 #include <QKeySequence>
25 #include <QMessageBox>
27 #include <QDomDocument>
28 #include <QFileDialog>
29 #include <QTextStream>
38 connect( mLeFilter, &QgsFilterLineEdit::textChanged,
this, &QgsConfigureShortcutsDialog::mLeFilter_textChanged );
43 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsConfigureShortcutsDialog::showHelp );
44 connect( btnChangeShortcut, &QAbstractButton::clicked,
this, &QgsConfigureShortcutsDialog::changeShortcut );
45 connect( btnResetShortcut, &QAbstractButton::clicked,
this, &QgsConfigureShortcutsDialog::resetShortcut );
46 connect( btnSetNoShortcut, &QAbstractButton::clicked,
this, &QgsConfigureShortcutsDialog::setNoShortcut );
47 connect( btnSaveShortcuts, &QAbstractButton::clicked,
this, &QgsConfigureShortcutsDialog::saveShortcuts );
48 connect( btnLoadShortcuts, &QAbstractButton::clicked,
this, &QgsConfigureShortcutsDialog::loadShortcuts );
50 connect( treeActions, &QTreeWidget::currentItemChanged,
51 this, &QgsConfigureShortcutsDialog::actionChanged );
56 void QgsConfigureShortcutsDialog::populateActions()
58 QList<QObject *> objects = mManager->
listAll();
60 QList<QTreeWidgetItem *> items;
61 items.reserve( objects.count() );
62 const auto constObjects = objects;
63 for ( QObject *obj : constObjects )
69 if ( QAction *action = qobject_cast< QAction * >( obj ) )
71 actionText = action->text();
72 actionText.remove(
'&' );
73 sequence = action->shortcut().toString( QKeySequence::NativeText );
74 icon = action->icon();
76 else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( obj ) )
78 actionText = shortcut->whatsThis();
79 sequence = shortcut->key().toString( QKeySequence::NativeText );
80 icon = shortcut->property(
"Icon" ).value<QIcon>();
87 if ( actionText.isEmpty() )
93 lst << actionText << sequence;
94 QTreeWidgetItem *item =
new QTreeWidgetItem( lst );
95 item->setIcon( 0, icon );
96 item->setData( 0, Qt::UserRole, QVariant::fromValue( obj ) );
100 treeActions->addTopLevelItems( items );
103 treeActions->resizeColumnToContents( 0 );
104 treeActions->sortItems( 0, Qt::AscendingOrder );
106 actionChanged( treeActions->currentItem(),
nullptr );
109 void QgsConfigureShortcutsDialog::saveShortcuts()
111 QString fileName = QFileDialog::getSaveFileName(
this, tr(
"Save Shortcuts" ), QDir::homePath(),
112 tr(
"XML file" ) +
" (*.xml);;" + tr(
"All files" ) +
" (*)" );
114 if ( fileName.isEmpty() )
118 if ( !fileName.endsWith( QLatin1String(
".xml" ), Qt::CaseInsensitive ) )
120 fileName += QLatin1String(
".xml" );
123 QFile file( fileName );
124 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
126 QMessageBox::warning(
this, tr(
"Saving Shortcuts" ),
127 tr(
"Cannot write file %1:\n%2." )
129 file.errorString() ) );
135 QDomDocument doc( QStringLiteral(
"shortcuts" ) );
136 QDomElement root = doc.createElement( QStringLiteral(
"qgsshortcuts" ) );
137 root.setAttribute( QStringLiteral(
"version" ), QStringLiteral(
"1.0" ) );
138 root.setAttribute( QStringLiteral(
"locale" ), settings.
value( QStringLiteral(
"locale/userLocale" ),
"en_US" ).toString() );
139 doc.appendChild( root );
145 QString actionShortcut;
147 for (
int i = 0; i < keys.count(); ++i )
149 actionText = keys[ i ];
150 actionShortcut = settings.
value( actionText,
"" ).toString();
152 QDomElement el = doc.createElement( QStringLiteral(
"act" ) );
153 el.setAttribute( QStringLiteral(
"name" ), actionText );
154 el.setAttribute( QStringLiteral(
"shortcut" ), actionShortcut );
155 root.appendChild( el );
158 QTextStream out( &file );
162 void QgsConfigureShortcutsDialog::loadShortcuts()
164 QString fileName = QFileDialog::getOpenFileName(
this, tr(
"Load Shortcuts" ), QDir::homePath(),
165 tr(
"XML file" ) +
" (*.xml);;" + tr(
"All files" ) +
" (*)" );
167 if ( fileName.isEmpty() )
172 QFile file( fileName );
173 if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
175 QMessageBox::warning(
this, tr(
"Loading Shortcuts" ),
176 tr(
"Cannot read file %1:\n%2." )
178 file.errorString() ) );
187 if ( !doc.setContent( &file,
true, &errorStr, &errorLine, &errorColumn ) )
189 QMessageBox::information(
this, tr(
"Loading Shortcuts" ),
190 tr(
"Parse error at line %1, column %2:\n%3" )
197 QDomElement root = doc.documentElement();
198 if ( root.tagName() != QLatin1String(
"qgsshortcuts" ) )
200 QMessageBox::information(
this, tr(
"Loading Shortcuts" ),
201 tr(
"The file is not an shortcuts exchange file." ) );
206 QString currentLocale;
208 bool localeOverrideFlag = settings.
value( QStringLiteral(
"locale/overrideFlag" ),
false ).toBool();
209 if ( localeOverrideFlag )
211 currentLocale = settings.
value( QStringLiteral(
"locale/userLocale" ),
"en_US" ).toString();
215 currentLocale = QLocale().name();
218 if ( root.attribute( QStringLiteral(
"locale" ) ) != currentLocale )
220 QMessageBox::information(
this, tr(
"Loading Shortcuts" ),
221 tr(
"The file contains shortcuts created with different locale, so you can't use it." ) );
226 QString actionShortcut;
228 QDomElement child = root.firstChildElement();
229 while ( !child.isNull() )
231 actionName = child.attribute( QStringLiteral(
"name" ) );
232 actionShortcut = child.attribute( QStringLiteral(
"shortcut" ) );
235 child = child.nextSiblingElement();
238 treeActions->clear();
242 void QgsConfigureShortcutsDialog::changeShortcut()
245 setGettingShortcut(
true );
248 void QgsConfigureShortcutsDialog::resetShortcut()
250 QObject *
object = currentObject();
252 setCurrentActionShortcut( sequence );
255 void QgsConfigureShortcutsDialog::setNoShortcut()
257 setCurrentActionShortcut( QKeySequence() );
260 QAction *QgsConfigureShortcutsDialog::currentAction()
262 return qobject_cast<QAction *>( currentObject() );
265 QShortcut *QgsConfigureShortcutsDialog::currentShortcut()
267 return qobject_cast<QShortcut *>( currentObject() );
270 void QgsConfigureShortcutsDialog::actionChanged( QTreeWidgetItem *current, QTreeWidgetItem *previous )
275 setGettingShortcut(
false );
278 QKeySequence sequence;
279 if ( QAction *action = currentAction() )
283 sequence = action->shortcut();
285 else if ( QShortcut *
object = currentShortcut() )
289 sequence =
object->key();
296 if ( shortcut.isEmpty() )
297 shortcut = tr(
"None" );
298 btnResetShortcut->setText( tr(
"Set default (%1)" ).arg( shortcut ) );
301 btnSetNoShortcut->setEnabled( !sequence.isEmpty() );
303 btnResetShortcut->setEnabled( sequence != QKeySequence( shortcut ) );
308 if ( !mGettingShortcut )
310 QDialog::keyPressEvent( event );
314 int key =
event->key();
319 mModifiers |= Qt::META;
320 updateShortcutText();
323 mModifiers |= Qt::ALT;
324 updateShortcutText();
326 case Qt::Key_Control:
327 mModifiers |= Qt::CTRL;
328 updateShortcutText();
331 mModifiers |= Qt::SHIFT;
332 updateShortcutText();
337 setGettingShortcut(
false );
342 updateShortcutText();
348 if ( !mGettingShortcut )
350 QDialog::keyReleaseEvent( event );
354 int key =
event->key();
359 mModifiers &= ~Qt::META;
360 updateShortcutText();
363 mModifiers &= ~Qt::ALT;
364 updateShortcutText();
366 case Qt::Key_Control:
367 mModifiers &= ~Qt::CTRL;
368 updateShortcutText();
371 mModifiers &= ~Qt::SHIFT;
372 updateShortcutText();
381 setCurrentActionShortcut( QKeySequence( mModifiers + mKey ) );
382 setGettingShortcut(
false );
387 QObject *QgsConfigureShortcutsDialog::currentObject()
389 if ( !treeActions->currentItem() )
392 QObject *
object = treeActions->currentItem()->data( 0, Qt::UserRole ).value<QObject *>();
396 void QgsConfigureShortcutsDialog::updateShortcutText()
399 QKeySequence s( mModifiers + mKey );
400 btnChangeShortcut->setText( tr(
"Input: " ) + s.toString( QKeySequence::NativeText ) );
403 void QgsConfigureShortcutsDialog::setGettingShortcut(
bool getting )
407 mGettingShortcut = getting;
410 btnChangeShortcut->setChecked(
false );
411 btnChangeShortcut->setText( tr(
"Change" ) );
415 updateShortcutText();
419 void QgsConfigureShortcutsDialog::setCurrentActionShortcut(
const QKeySequence &s )
421 QObject *
object = currentObject();
427 if ( otherObject ==
object )
433 if ( QAction *otherAction = qobject_cast< QAction * >( otherObject ) )
435 otherText = otherAction->text();
436 otherText.remove(
'&' );
438 else if ( QShortcut *otherShortcut = qobject_cast< QShortcut * >( otherObject ) )
440 otherText = otherShortcut->whatsThis();
443 int res = QMessageBox::question(
this, tr(
"Change Shortcut" ),
444 tr(
"This shortcut is already assigned to action %1. Reassign?" ).arg( otherText ),
445 QMessageBox::Yes | QMessageBox::No );
447 if ( res != QMessageBox::Yes )
452 QList<QTreeWidgetItem *> items = treeActions->findItems( otherText, Qt::MatchExactly );
453 if ( !items.isEmpty() )
454 items[0]->setText( 1, QString() );
461 treeActions->currentItem()->setText( 1, s.toString( QKeySequence::NativeText ) );
463 actionChanged( treeActions->currentItem(),
nullptr );
466 void QgsConfigureShortcutsDialog::mLeFilter_textChanged(
const QString &text )
468 for (
int i = 0; i < treeActions->topLevelItemCount(); i++ )
470 QTreeWidgetItem *item = treeActions->topLevelItem( i );
471 if ( !item->text( 0 ).contains( text, Qt::CaseInsensitive ) && !item->text( 1 ).contains( text, Qt::CaseInsensitive ) )
473 item->setHidden(
true );
477 item->setHidden(
false );
482 void QgsConfigureShortcutsDialog::showHelp()
484 QgsHelp::openHelp( QStringLiteral(
"introduction/qgis_configuration.html#keyboard-shortcuts" ) );