26#include <QKeySequence> 
   29#include <QDomDocument> 
   35#include <QTextDocument> 
   38#include <QTextTableFormat> 
   39#include <QTextTableCellFormat> 
   40#include <QTextCharFormat> 
   49  mSaveMenu = 
new QMenu( 
this );
 
   50  mSaveUserShortcuts = 
new QAction( tr( 
"Save User Shortcuts…" ), 
this );
 
   51  mSaveMenu->addAction( mSaveUserShortcuts );
 
   52  connect( mSaveUserShortcuts, &QAction::triggered, 
this, [
this] { saveShortcuts( 
false ); } );
 
   54  mSaveAllShortcuts = 
new QAction( tr( 
"Save All Shortcuts…" ), 
this );
 
   55  mSaveMenu->addAction( mSaveAllShortcuts );
 
   56  connect( mSaveAllShortcuts, &QAction::triggered, 
this, [
this] { saveShortcuts(); } );
 
   58  mSaveAsPdf = 
new QAction( tr( 
"Save as PDF…" ), 
this );
 
   59  mSaveMenu->addAction( mSaveAsPdf );
 
   60  connect( mSaveAsPdf, &QAction::triggered, 
this, &QgsConfigureShortcutsDialog::saveShortcutsPdf );
 
   62  btnSaveShortcuts->setMenu( mSaveMenu );
 
   64  connect( mLeFilter, &QgsFilterLineEdit::textChanged, 
this, &QgsConfigureShortcutsDialog::mLeFilter_textChanged );
 
   69  connect( buttonBox, &QDialogButtonBox::helpRequested, 
this, &QgsConfigureShortcutsDialog::showHelp ); 
 
   70  connect( btnChangeShortcut, &QAbstractButton::clicked, 
this, &QgsConfigureShortcutsDialog::changeShortcut );
 
   71  connect( btnResetShortcut, &QAbstractButton::clicked, 
this, &QgsConfigureShortcutsDialog::resetShortcut );
 
   72  connect( btnSetNoShortcut, &QAbstractButton::clicked, 
this, &QgsConfigureShortcutsDialog::setNoShortcut );
 
   73  connect( btnLoadShortcuts, &QAbstractButton::clicked, 
this, &QgsConfigureShortcutsDialog::loadShortcuts );
 
   75  connect( treeActions, &QTreeWidget::currentItemChanged,
 
   76           this, &QgsConfigureShortcutsDialog::actionChanged );
 
 
   81void QgsConfigureShortcutsDialog::populateActions()
 
   83  const QList<QObject *> objects = mManager->
listAll();
 
   85  QList<QTreeWidgetItem *> items;
 
   86  items.reserve( objects.count() );
 
   87  const auto constObjects = objects;
 
   88  for ( QObject *obj : constObjects )
 
   95    if ( QAction *action = qobject_cast< QAction * >( obj ) )
 
   97      actionText = action->text();
 
   98      actionText.remove( 
'&' ); 
 
   99      sequence = action->shortcut().toString( QKeySequence::NativeText );
 
  100      icon = action->icon();
 
  102    else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( obj ) )
 
  104      actionText = shortcut->whatsThis();
 
  105      sequence = shortcut->key().toString( QKeySequence::NativeText );
 
  106      icon = shortcut->property( 
"Icon" ).value<QIcon>();
 
  113    if ( actionText.isEmpty() )
 
  119    lst << actionText << sequence;
 
  120    QTreeWidgetItem *item = 
new QTreeWidgetItem( lst );
 
  121    item->setIcon( 0, icon );
 
  122    item->setData( 0, Qt::UserRole, QVariant::fromValue( obj ) );
 
  123    item->setToolTip( 0, settingKey );
 
  124    items.append( item );
 
  127  treeActions->addTopLevelItems( items );
 
  130  treeActions->resizeColumnToContents( 0 );
 
  131  treeActions->sortItems( 0, Qt::AscendingOrder );
 
  133  actionChanged( treeActions->currentItem(), 
nullptr );
 
  136void QgsConfigureShortcutsDialog::saveShortcuts( 
bool saveAll )
 
  138  QString fileName = QFileDialog::getSaveFileName( 
this, tr( 
"Save Shortcuts" ), QDir::homePath(),
 
  139                     tr( 
"XML file" ) + 
" (*.xml);;" + tr( 
"All files" ) + 
" (*)" );
 
  144  if ( fileName.isEmpty() )
 
  148  if ( !fileName.endsWith( QLatin1String( 
".xml" ), Qt::CaseInsensitive ) )
 
  150    fileName += QLatin1String( 
".xml" );
 
  153  QFile file( fileName );
 
  154  if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
 
  156    QMessageBox::warning( 
this, tr( 
"Saving Shortcuts" ),
 
  157                          tr( 
"Cannot write file %1:\n%2." )
 
  159                                file.errorString() ) );
 
  165  QDomDocument doc( QStringLiteral( 
"shortcuts" ) );
 
  166  QDomElement root = doc.createElement( QStringLiteral( 
"qgsshortcuts" ) );
 
  167  root.setAttribute( QStringLiteral( 
"version" ), QStringLiteral( 
"1.1" ) );
 
  169  doc.appendChild( root );
 
  171  const QList<QObject *> objects = mManager->
listAll();
 
  172  for ( QObject *obj : objects )
 
  175    QString actionShortcut;
 
  176    QString actionSettingKey;
 
  177    QKeySequence sequence;
 
  179    if ( QAction *action = qobject_cast< QAction * >( obj ) )
 
  181      actionText = action->text().remove( 
'&' );
 
  182      actionShortcut = action->shortcut().toString( QKeySequence::NativeText );
 
  185    else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( obj ) )
 
  187      actionText = shortcut->whatsThis();
 
  188      actionShortcut = shortcut->key().toString( QKeySequence::NativeText );
 
  198    if ( actionSettingKey.isEmpty() )
 
  204    if ( !saveAll && sequence == QKeySequence( actionShortcut ) )
 
  209    QDomElement el = doc.createElement( QStringLiteral( 
"action" ) );
 
  210    el.setAttribute( QStringLiteral( 
"name" ), actionText );
 
  211    el.setAttribute( QStringLiteral( 
"shortcut" ), actionShortcut );
 
  212    el.setAttribute( QStringLiteral( 
"setting" ), actionSettingKey );
 
  213    root.appendChild( el );
 
  216  QTextStream out( &file );
 
  220void QgsConfigureShortcutsDialog::loadShortcuts()
 
  222  const QString fileName = QFileDialog::getOpenFileName( 
this, tr( 
"Load Shortcuts" ), QDir::homePath(),
 
  223                           tr( 
"XML file" ) + 
" (*.xml);;" + tr( 
"All files" ) + 
" (*)" );
 
  225  if ( fileName.isEmpty() )
 
  230  QFile file( fileName );
 
  231  if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
 
  233    QMessageBox::warning( 
this, tr( 
"Loading Shortcuts" ),
 
  234                          tr( 
"Cannot read file %1:\n%2." )
 
  236                                file.errorString() ) );
 
  245  if ( !doc.setContent( &file, 
true, &errorStr, &errorLine, &errorColumn ) )
 
  247    QMessageBox::information( 
this, tr( 
"Loading Shortcuts" ),
 
  248                              tr( 
"Parse error at line %1, column %2:\n%3" )
 
  255  const QDomElement root = doc.documentElement();
 
  256  if ( root.tagName() != QLatin1String( 
"qgsshortcuts" ) )
 
  258    QMessageBox::information( 
this, tr( 
"Loading Shortcuts" ),
 
  259                              tr( 
"The file is not an shortcuts exchange file." ) );
 
  263  QString currentLocale;
 
  266  if ( localeOverrideFlag )
 
  272    currentLocale = QLocale().name();
 
  275  const QString versionStr = root.attribute( QStringLiteral( 
"version" ) );
 
  278  if ( root.attribute( QStringLiteral( 
"locale" ) ) != currentLocale )
 
  282      QMessageBox::information( 
this, tr( 
"Loading Shortcuts" ),
 
  283                                tr( 
"The file contains shortcuts created with different locale, so you can't use it." ) );
 
  288      QMessageBox::information( 
this, tr( 
"Loading Shortcuts" ),
 
  289                                tr( 
"The file contains shortcuts created with different locale, so some shortcuts may not work." ) );
 
  294  QString actionShortcut;
 
  295  QString actionSettingKey;
 
  297  QDomElement child = root.firstChildElement();
 
  298  while ( !child.isNull() )
 
  300    actionShortcut = child.attribute( QStringLiteral( 
"shortcut" ) );
 
  303      actionName = child.attribute( QStringLiteral( 
"name" ) );
 
  308      actionSettingKey = child.attribute( QStringLiteral( 
"setting" ) );
 
  315    child = child.nextSiblingElement();
 
  318  treeActions->clear();
 
  322void QgsConfigureShortcutsDialog::changeShortcut()
 
  325  setGettingShortcut( 
true );
 
  328void QgsConfigureShortcutsDialog::resetShortcut()
 
  330  QObject *
object = currentObject();
 
  332  setCurrentActionShortcut( sequence );
 
  335void QgsConfigureShortcutsDialog::setNoShortcut()
 
  337  setCurrentActionShortcut( QKeySequence() );
 
  340QAction *QgsConfigureShortcutsDialog::currentAction()
 
  342  return qobject_cast<QAction *>( currentObject() );
 
  345QShortcut *QgsConfigureShortcutsDialog::currentShortcut()
 
  347  return qobject_cast<QShortcut *>( currentObject() );
 
  350void QgsConfigureShortcutsDialog::actionChanged( QTreeWidgetItem *current, QTreeWidgetItem *previous )
 
  355  setGettingShortcut( 
false );
 
  358  QKeySequence sequence;
 
  359  if ( QAction *action = currentAction() )
 
  363    sequence = action->shortcut();
 
  365  else if ( QShortcut *
object = currentShortcut() )
 
  369    sequence = 
object->key();
 
  376  if ( shortcut.isEmpty() )
 
  377    shortcut = tr( 
"None" );
 
  378  btnResetShortcut->setText( tr( 
"Set default (%1)" ).arg( shortcut ) );
 
  381  btnSetNoShortcut->setEnabled( !sequence.isEmpty() );
 
  383  btnResetShortcut->setEnabled( sequence != QKeySequence( shortcut ) );
 
  388  if ( !mGettingShortcut )
 
  390    QDialog::keyPressEvent( event );
 
  394  const int key = 
event->key();
 
  399      mModifiers |= Qt::META;
 
  400      updateShortcutText();
 
  403      mModifiers |= Qt::ALT;
 
  404      updateShortcutText();
 
  406    case Qt::Key_Control:
 
  407      mModifiers |= Qt::CTRL;
 
  408      updateShortcutText();
 
  411      mModifiers |= Qt::SHIFT;
 
  412      updateShortcutText();
 
  417      setGettingShortcut( 
false );
 
  422      updateShortcutText();
 
 
  428  if ( !mGettingShortcut )
 
  430    QDialog::keyReleaseEvent( event );
 
  434  const int key = 
event->key();
 
  439      mModifiers &= ~Qt::META;
 
  440      updateShortcutText();
 
  443      mModifiers &= ~Qt::ALT;
 
  444      updateShortcutText();
 
  446    case Qt::Key_Control:
 
  447      mModifiers &= ~Qt::CTRL;
 
  448      updateShortcutText();
 
  451      mModifiers &= ~Qt::SHIFT;
 
  452      updateShortcutText();
 
  461      setCurrentActionShortcut( QKeySequence( mModifiers + mKey ) );
 
  462      setGettingShortcut( 
false );
 
 
  467QObject *QgsConfigureShortcutsDialog::currentObject()
 
  469  if ( !treeActions->currentItem() )
 
  472  QObject *
object = treeActions->currentItem()->data( 0, Qt::UserRole ).value<QObject *>();
 
  476void QgsConfigureShortcutsDialog::updateShortcutText()
 
  479  const QKeySequence s( mModifiers + mKey );
 
  480  btnChangeShortcut->setText( tr( 
"Input: " ) + s.toString( QKeySequence::NativeText ) );
 
  483void QgsConfigureShortcutsDialog::setGettingShortcut( 
bool getting )
 
  487  mGettingShortcut = getting;
 
  490    btnChangeShortcut->setChecked( 
false );
 
  491    btnChangeShortcut->setText( tr( 
"Change" ) );
 
  495    updateShortcutText();
 
  499void QgsConfigureShortcutsDialog::setCurrentActionShortcut( 
const QKeySequence &s )
 
  501  QObject *
object = currentObject();
 
  507  if ( otherObject == 
object )
 
  513    if ( QAction *otherAction = qobject_cast< QAction * >( otherObject ) )
 
  515      otherText = otherAction->text();
 
  516      otherText.remove( 
'&' ); 
 
  518    else if ( QShortcut *otherShortcut = qobject_cast< QShortcut * >( otherObject ) )
 
  520      otherText = otherShortcut->whatsThis();
 
  523    const int res = QMessageBox::question( 
this, tr( 
"Change Shortcut" ),
 
  524                                           tr( 
"This shortcut is already assigned to action %1. Reassign?" ).arg( otherText ),
 
  525                                           QMessageBox::Yes | QMessageBox::No );
 
  527    if ( res != QMessageBox::Yes )
 
  532    QList<QTreeWidgetItem *> items = treeActions->findItems( otherText, Qt::MatchExactly );
 
  533    if ( !items.isEmpty() ) 
 
  534      items[0]->setText( 1, QString() );
 
  541  treeActions->currentItem()->setText( 1, s.toString( QKeySequence::NativeText ) );
 
  543  actionChanged( treeActions->currentItem(), 
nullptr );
 
  546void QgsConfigureShortcutsDialog::mLeFilter_textChanged( 
const QString &text )
 
  548  for ( 
int i = 0; i < treeActions->topLevelItemCount(); i++ )
 
  550    QTreeWidgetItem *item = treeActions->topLevelItem( i );
 
  551    if ( !item->text( 0 ).contains( text, Qt::CaseInsensitive ) && !item->text( 1 ).contains( text, Qt::CaseInsensitive ) )
 
  553      item->setHidden( 
true );
 
  557      item->setHidden( 
false );
 
  562void QgsConfigureShortcutsDialog::showHelp()
 
  564  QgsHelp::openHelp( QStringLiteral( 
"introduction/qgis_configuration.html#shortcuts" ) );
 
  567void QgsConfigureShortcutsDialog::saveShortcutsPdf()
 
  569  QString fileName = QFileDialog::getSaveFileName( 
this, tr( 
"Save Shortcuts" ), QDir::homePath(),
 
  570                     tr( 
"PDF file" ) + 
" (*.pdf);;" + tr( 
"All files" ) + 
" (*)" );
 
  575  if ( fileName.isEmpty() )
 
  578  if ( !fileName.endsWith( QLatin1String( 
".pdf" ), Qt::CaseInsensitive ) )
 
  580    fileName += QLatin1String( 
".pdf" );
 
  583  QTextDocument *document = 
new QTextDocument;
 
  584  QTextCursor cursor( document );
 
  586  QTextTableFormat tableFormat;
 
  587  tableFormat.setBorder( 0 );
 
  588  tableFormat.setCellSpacing( 0 );
 
  589  tableFormat.setCellPadding( 4 );
 
  590  tableFormat.setHeaderRowCount( 1 );
 
  592  QVector<QTextLength> constraints;
 
  593  constraints << QTextLength( QTextLength::PercentageLength, 5 );
 
  594  constraints << QTextLength( QTextLength::PercentageLength, 80 );
 
  595  constraints << QTextLength( QTextLength::PercentageLength, 15 );
 
  596  tableFormat.setColumnWidthConstraints( constraints );
 
  598  QTextTableCellFormat headerFormat;
 
  599  headerFormat.setFontWeight( QFont::Bold );
 
  600  headerFormat.setBottomPadding( 4 );
 
  602  QTextCharFormat rowFormat;
 
  603  rowFormat.setVerticalAlignment( QTextCharFormat::AlignMiddle );
 
  605  QTextCharFormat altRowFormat;
 
  606  altRowFormat.setBackground( QBrush( QColor( 238, 238, 236 ) ) );
 
  607  altRowFormat.setVerticalAlignment( QTextCharFormat::AlignMiddle );
 
  610  QTextTable *table = cursor.insertTable( 1, 3, tableFormat );
 
  611  table->mergeCells( 0, 0, 1, 2 );
 
  612  QTextCursor 
c = table->cellAt( row, 0 ).firstCursorPosition();
 
  613  c.setCharFormat( headerFormat );
 
  614  c.insertText( tr( 
"Action" ) );
 
  615  c = table->cellAt( row, 2 ).firstCursorPosition();
 
  616  c.setCharFormat( headerFormat );
 
  617  c.insertText( tr( 
"Shortcut" ) );
 
  619  const QList<QObject *> objects = mManager->
listAll();
 
  620  for ( QObject *obj : objects )
 
  626    if ( QAction *action = qobject_cast< QAction * >( obj ) )
 
  628      actionText = action->text().remove( 
'&' );
 
  629      sequence = action->shortcut().toString( QKeySequence::NativeText );
 
  630      icon = action->icon();
 
  632    else if ( QShortcut *shortcut = qobject_cast< QShortcut * >( obj ) )
 
  634      actionText = shortcut->whatsThis();
 
  635      sequence = shortcut->key().toString( QKeySequence::NativeText );
 
  636      icon = shortcut->property( 
"Icon" ).value<QIcon>();
 
  644    if ( actionText.isEmpty() || sequence.isEmpty() )
 
  650    table->appendRows( 1 );
 
  654      table->cellAt( row, 0 ).setFormat( altRowFormat );
 
  655      table->cellAt( row, 1 ).setFormat( altRowFormat );
 
  656      table->cellAt( row, 2 ).setFormat( altRowFormat );
 
  660      table->cellAt( row, 0 ).setFormat( rowFormat );
 
  661      table->cellAt( row, 1 ).setFormat( rowFormat );
 
  662      table->cellAt( row, 2 ).setFormat( rowFormat );
 
  665    if ( !icon.isNull() )
 
  667      c = table->cellAt( row, 0 ).firstCursorPosition();
 
  668      c.insertImage( icon.pixmap( QSize( 24, 24 ) ).toImage() );
 
  670    table->cellAt( row, 1 ).firstCursorPosition().insertText( actionText );
 
  671    table->cellAt( row, 2 ).firstCursorPosition().insertText( sequence );
 
  674  QPdfWriter pdfWriter( fileName );
 
  675  pdfWriter.setPageLayout( QPageLayout( QPageSize( QPageSize::A4 ), QPageLayout::Portrait, QMarginsF( 20, 10, 10, 10 ) ) );
 
  676  document->setPageSize( QSizeF( pdfWriter.pageLayout().fullRect( QPageLayout::Point ).size() ) );
 
  677  document->print( &pdfWriter );
 
static const QgsSettingsEntryBool * settingsLocaleOverrideFlag
Settings entry locale override flag.
 
static const QgsSettingsEntryString * settingsLocaleUserLocale
Settings entry locale user locale.
 
static QgsShortcutsManager * shortcutsManager()
Returns the global shortcuts manager, used for managing a QAction and QShortcut sequences.
 
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
 
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
 
A class to describe the version of a project.
 
T valueWithDefaultOverride(const T &defaultValueOverride, const QString &dynamicKeyPart=QString()) const
Returns the settings value with a defaultValueOverride and with an optional dynamicKeyPart.
 
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
 
QString key(const QString &dynamicKeyPart=QString()) const
Returns settings entry key.
 
This class is a composition of two QSettings instances:
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
 
Shortcuts manager is a class that contains a list of QActions and QShortcuts that have been registere...
 
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.
 
QObject * objectForSettingKey(const QString &name) const
Returns the QShortcut or QAction matching the the full setting key Return nullptr if the key was not ...
 
QString objectDefaultKeySequence(QObject *object) const
Returns the default sequence for an object (either a QAction or QShortcut).
 
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.
 
QString objectSettingKey(QObject *object) const
Returns the full settings key matching the QShortcut or QAction Return an empty QString if the QObjec...
 
QObject * objectForSequence(const QKeySequence &sequence) const
Returns the object (QAction or QShortcut) matching the specified key sequence,.
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c