QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsconfigureshortcutsdialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsconfigureshortcutsdialog.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
17
18#include "qgsapplication.h"
19#include "qgsgui.h"
20#include "qgslogger.h"
21#include "qgsprojectversion.h"
22#include "qgssettings.h"
23#include "qgsshortcutsmanager.h"
24
25#include <QAction>
26#include <QDomDocument>
27#include <QFileDialog>
28#include <QKeyEvent>
29#include <QKeySequence>
30#include <QMenu>
31#include <QMessageBox>
32#include <QPdfWriter>
33#include <QShortcut>
34#include <QTextCharFormat>
35#include <QTextCursor>
36#include <QTextDocument>
37#include <QTextStream>
38#include <QTextTable>
39#include <QTextTableCellFormat>
40#include <QTextTableFormat>
41
42#include "moc_qgsconfigureshortcutsdialog.cpp"
43
45 : QDialog( parent )
46 , mManager( manager )
47{
48 setupUi( this );
50
51 mSaveMenu = new QMenu( this );
52 mSaveUserShortcuts = new QAction( tr( "Save User Shortcuts…" ), this );
53 mSaveMenu->addAction( mSaveUserShortcuts );
54 connect( mSaveUserShortcuts, &QAction::triggered, this, [this] { saveShortcuts( false ); } );
55
56 mSaveAllShortcuts = new QAction( tr( "Save All Shortcuts…" ), this );
57 mSaveMenu->addAction( mSaveAllShortcuts );
58 connect( mSaveAllShortcuts, &QAction::triggered, this, [this] { saveShortcuts(); } );
59
60 mSaveAsPdf = new QAction( tr( "Save as PDF…" ), this );
61 mSaveMenu->addAction( mSaveAsPdf );
62 connect( mSaveAsPdf, &QAction::triggered, this, &QgsConfigureShortcutsDialog::saveShortcutsPdf );
63
64 btnSaveShortcuts->setMenu( mSaveMenu );
65
66 connect( mLeFilter, &QgsFilterLineEdit::textChanged, this, &QgsConfigureShortcutsDialog::mLeFilter_textChanged );
67
68 if ( !mManager )
69 mManager = QgsGui::shortcutsManager();
70
71 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsConfigureShortcutsDialog::showHelp ); // Vérifier nommage des boutons
72 connect( btnChangeShortcut, &QAbstractButton::clicked, this, &QgsConfigureShortcutsDialog::changeShortcut );
73 connect( btnResetShortcut, &QAbstractButton::clicked, this, &QgsConfigureShortcutsDialog::resetShortcut );
74 connect( btnSetNoShortcut, &QAbstractButton::clicked, this, &QgsConfigureShortcutsDialog::setNoShortcut );
75 connect( btnLoadShortcuts, &QAbstractButton::clicked, this, &QgsConfigureShortcutsDialog::loadShortcuts );
76
77 connect( treeActions, &QTreeWidget::currentItemChanged, this, &QgsConfigureShortcutsDialog::actionChanged );
78
79 populateActions();
80}
81
82void QgsConfigureShortcutsDialog::populateActions()
83{
84 const QList<QObject *> objects = mManager->listAll();
85
86 QList<QTreeWidgetItem *> items;
87 items.reserve( objects.count() );
88 const auto constObjects = objects;
89 for ( QObject *obj : constObjects )
90 {
91 QString actionText;
92 QString sequence;
93 QIcon icon;
94 const QString settingKey = mManager->objectSettingKey( obj );
95
96 if ( QAction *action = qobject_cast<QAction *>( obj ) )
97 {
98 actionText = action->text();
99 actionText.remove( '&' ); // remove the accelerator
100 sequence = action->shortcut().toString( QKeySequence::NativeText );
101 icon = action->icon();
102 }
103 else if ( QShortcut *shortcut = qobject_cast<QShortcut *>( obj ) )
104 {
105 actionText = shortcut->whatsThis();
106 sequence = shortcut->key().toString( QKeySequence::NativeText );
107 icon = shortcut->property( "Icon" ).value<QIcon>();
108 }
109 else
110 {
111 continue;
112 }
113
114 if ( actionText.isEmpty() )
115 {
116 continue;
117 }
118
119 QStringList lst;
120 lst << actionText << sequence;
121 QTreeWidgetItem *item = new QTreeWidgetItem( lst );
122 item->setIcon( 0, icon );
123 item->setData( 0, Qt::UserRole, QVariant::fromValue( obj ) );
124 item->setToolTip( 0, settingKey );
125 items.append( item );
126 }
127
128 treeActions->addTopLevelItems( items );
129
130 // make sure everything's visible and sorted
131 treeActions->resizeColumnToContents( 0 );
132 treeActions->sortItems( 0, Qt::AscendingOrder );
133
134 actionChanged( treeActions->currentItem(), nullptr );
135}
136
137void QgsConfigureShortcutsDialog::saveShortcuts( bool saveAll )
138{
139 QString fileName = QFileDialog::getSaveFileName( this, tr( "Save Shortcuts" ), QDir::homePath(), tr( "XML file" ) + " (*.xml);;" + tr( "All files" ) + " (*)" );
140 // return dialog focus on Mac
141 activateWindow();
142 raise();
143
144 if ( fileName.isEmpty() )
145 return;
146
147 // ensure the user never omitted the extension from the file name
148 if ( !fileName.endsWith( QLatin1String( ".xml" ), Qt::CaseInsensitive ) )
149 {
150 fileName += QLatin1String( ".xml" );
151 }
152
153 QFile file( fileName );
154 if ( !file.open( QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate ) )
155 {
156 QMessageBox::warning( this, tr( "Saving Shortcuts" ), tr( "Cannot write file %1:\n%2." ).arg( fileName, file.errorString() ) );
157 return;
158 }
159
160 QgsSettings settings;
161
162 QDomDocument doc( QStringLiteral( "shortcuts" ) );
163 QDomElement root = doc.createElement( QStringLiteral( "qgsshortcuts" ) );
164 root.setAttribute( QStringLiteral( "version" ), QStringLiteral( "1.1" ) );
165 root.setAttribute( QStringLiteral( "locale" ), settings.value( QgsApplication::settingsLocaleUserLocale->key(), "en_US" ).toString() );
166 doc.appendChild( root );
167
168 const QList<QObject *> objects = mManager->listAll();
169 for ( QObject *obj : objects )
170 {
171 QString actionText;
172 QString actionShortcut;
173 QString actionSettingKey;
174 QKeySequence sequence;
175
176 if ( QAction *action = qobject_cast<QAction *>( obj ) )
177 {
178 actionText = action->text().remove( '&' );
179 actionShortcut = action->shortcut().toString( QKeySequence::NativeText );
180 sequence = mManager->defaultKeySequence( action );
181 }
182 else if ( QShortcut *shortcut = qobject_cast<QShortcut *>( obj ) )
183 {
184 actionText = shortcut->whatsThis();
185 actionShortcut = shortcut->key().toString( QKeySequence::NativeText );
186 sequence = mManager->defaultKeySequence( shortcut );
187 }
188 else
189 {
190 continue;
191 }
192
193 actionSettingKey = mManager->objectSettingKey( obj );
194
195 if ( actionSettingKey.isEmpty() )
196 {
197 continue;
198 }
199
200 // skip unchanged shortcuts if only user-definied were requested
201 if ( !saveAll && sequence == QKeySequence( actionShortcut ) )
202 {
203 continue;
204 }
205
206 QDomElement el = doc.createElement( QStringLiteral( "action" ) );
207 el.setAttribute( QStringLiteral( "name" ), actionText );
208 el.setAttribute( QStringLiteral( "shortcut" ), actionShortcut );
209 el.setAttribute( QStringLiteral( "setting" ), actionSettingKey );
210 root.appendChild( el );
211 }
212
213 QTextStream out( &file );
214 doc.save( out, 4 );
215}
216
217void QgsConfigureShortcutsDialog::loadShortcuts()
218{
219 const QString fileName = QFileDialog::getOpenFileName( this, tr( "Load Shortcuts" ), QDir::homePath(), tr( "XML file" ) + " (*.xml);;" + tr( "All files" ) + " (*)" );
220
221 if ( fileName.isEmpty() )
222 {
223 return;
224 }
225
226 QFile file( fileName );
227 if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
228 {
229 QMessageBox::warning( this, tr( "Loading Shortcuts" ), tr( "Cannot read file %1:\n%2." ).arg( fileName, file.errorString() ) );
230 return;
231 }
232
233 QDomDocument doc;
234 QString errorStr;
235 int errorLine;
236 int errorColumn;
237
238 if ( !doc.setContent( &file, true, &errorStr, &errorLine, &errorColumn ) )
239 {
240 QMessageBox::information( this, tr( "Loading Shortcuts" ), tr( "Parse error at line %1, column %2:\n%3" ).arg( errorLine ).arg( errorColumn ).arg( errorStr ) );
241 return;
242 }
243
244 const QDomElement root = doc.documentElement();
245 if ( root.tagName() != QLatin1String( "qgsshortcuts" ) )
246 {
247 QMessageBox::information( this, tr( "Loading Shortcuts" ), tr( "The file is not an shortcuts exchange file." ) );
248 return;
249 }
250
251 QString currentLocale;
252
253 const bool localeOverrideFlag = QgsApplication::settingsLocaleOverrideFlag->value();
254 if ( localeOverrideFlag )
255 {
257 }
258 else // use QGIS locale
259 {
260 currentLocale = QLocale().name();
261 }
262
263 const QString versionStr = root.attribute( QStringLiteral( "version" ) );
264 const QgsProjectVersion version( versionStr );
265
266 if ( root.attribute( QStringLiteral( "locale" ) ) != currentLocale )
267 {
268 if ( version < QgsProjectVersion( QStringLiteral( "1.1" ) ) )
269 {
270 QMessageBox::information( this, tr( "Loading Shortcuts" ), tr( "The file contains shortcuts created with different locale, so you can't use it." ) );
271 return;
272 }
273 else // From version 1.1, if objectName is not empty, it is used as key.
274 {
275 QMessageBox::information( this, tr( "Loading Shortcuts" ), tr( "The file contains shortcuts created with different locale, so some shortcuts may not work." ) );
276 }
277 }
278
279 QString actionName;
280 QString actionShortcut;
281 QString actionSettingKey;
282
283 QDomElement child = root.firstChildElement();
284 ActionOnExisting actionOnExisting = ActionOnExisting::Ask;
285 while ( !child.isNull() )
286 {
287 actionShortcut = child.attribute( QStringLiteral( "shortcut" ) );
288 QKeySequence actionShortcutSequence( actionShortcut );
289 QString previousText;
290
291 if ( version < QgsProjectVersion( QStringLiteral( "1.1" ) ) )
292 {
293 actionName = child.attribute( QStringLiteral( "name" ) );
294 QShortcut *previousShortcut = mManager->shortcutForSequence( actionShortcutSequence );
295 QAction *previousAction = mManager->actionForSequence( actionShortcutSequence );
296 if ( previousShortcut && previousShortcut->objectName() != actionName )
297 {
298 previousText = previousShortcut->whatsThis();
299 }
300 else if ( previousAction && previousAction->objectName() != actionName )
301 {
302 previousText = previousAction->text().remove( '&' );
303 }
304 if ( !previousText.isEmpty() )
305 {
306 QString text;
307 if ( QAction *action = mManager->actionByName( actionName ) )
308 {
309 text = action->text().remove( '&' );
310 }
311 else if ( QShortcut *shortcut = mManager->shortcutByName( actionName ) )
312 {
313 text = shortcut->whatsThis();
314 }
315
316 if ( actionOnExisting == ActionOnExisting::Ask )
317 {
318 const int res = QMessageBox::question( this, tr( "Load Shortcut" ), tr( "Shortcut %1 is already assigned to action %2. Reassign to %3?" ).arg( actionShortcut, previousText, text ), QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No | QMessageBox::NoToAll );
319 if ( res == QMessageBox::No || res == QMessageBox::NoToAll )
320 {
321 if ( res == QMessageBox::NoToAll )
322 {
323 actionOnExisting = ActionOnExisting::SkipAll;
324 }
325 child = child.nextSiblingElement();
326 continue;
327 }
328 if ( res == QMessageBox::YesToAll )
329 {
330 actionOnExisting = ActionOnExisting::ReassignAll;
331 }
332 }
333 else if ( actionOnExisting == ActionOnExisting::SkipAll )
334 {
335 child = child.nextSiblingElement();
336 continue;
337 }
338 mManager->setObjectKeySequence( previousAction ? qobject_cast<QObject *>( previousAction ) : qobject_cast<QObject *>( previousShortcut ), QString() );
339 }
340 mManager->setKeySequence( actionName, actionShortcut );
341 }
342 else
343 {
344 actionSettingKey = child.attribute( QStringLiteral( "setting" ) );
345 QObject *obj = mManager->objectForSettingKey( actionSettingKey );
346 if ( obj )
347 {
348 QObject *previousObj = mManager->objectForSequence( actionShortcutSequence );
349 if ( previousObj && previousObj != obj )
350 {
351 if ( QAction *previousAction = qobject_cast<QAction *>( previousObj ) )
352 {
353 previousText = previousAction->text().remove( '&' );
354 }
355 else if ( QShortcut *previousShortcut = qobject_cast<QShortcut *>( previousObj ) )
356 {
357 previousText = previousShortcut->whatsThis();
358 }
359 }
360
361 if ( !previousText.isEmpty() )
362 {
363 QString text;
364 if ( QAction *action = qobject_cast<QAction *>( obj ) )
365 {
366 text = action->text().remove( '&' );
367 }
368 else if ( QShortcut *shortcut = qobject_cast<QShortcut *>( obj ) )
369 {
370 text = shortcut->whatsThis();
371 }
372
373 if ( actionOnExisting == ActionOnExisting::Ask )
374 {
375 const int res = QMessageBox::question( this, tr( "Load Shortcut" ), tr( "Shortcut %1 is already assigned to action %2. Reassign to %3?" ).arg( actionShortcut, previousText, text ), QMessageBox::YesToAll | QMessageBox::Yes | QMessageBox::No | QMessageBox::NoToAll );
376 if ( res == QMessageBox::No || res == QMessageBox::NoToAll )
377 {
378 if ( res == QMessageBox::NoToAll )
379 {
380 actionOnExisting = ActionOnExisting::SkipAll;
381 }
382 child = child.nextSiblingElement();
383 continue;
384 }
385 if ( res == QMessageBox::YesToAll )
386 {
387 actionOnExisting = ActionOnExisting::ReassignAll;
388 }
389 }
390 else if ( actionOnExisting == ActionOnExisting::SkipAll )
391 {
392 child = child.nextSiblingElement();
393 continue;
394 }
395 mManager->setObjectKeySequence( previousObj, QString() );
396 }
397 mManager->setObjectKeySequence( obj, actionShortcut );
398 }
399 }
400
401 child = child.nextSiblingElement();
402 }
403
404 treeActions->clear();
405 populateActions();
406}
407
408void QgsConfigureShortcutsDialog::changeShortcut()
409{
410 setFocus(); // make sure we have focus
411 setGettingShortcut( true );
412}
413
414void QgsConfigureShortcutsDialog::resetShortcut()
415{
416 QObject *object = currentObject();
417 const QString sequence = mManager->objectDefaultKeySequence( object );
418 setCurrentActionShortcut( sequence );
419}
420
421void QgsConfigureShortcutsDialog::setNoShortcut()
422{
423 setCurrentActionShortcut( QKeySequence() );
424}
425
426QAction *QgsConfigureShortcutsDialog::currentAction()
427{
428 return qobject_cast<QAction *>( currentObject() );
429}
430
431QShortcut *QgsConfigureShortcutsDialog::currentShortcut()
432{
433 return qobject_cast<QShortcut *>( currentObject() );
434}
435
436void QgsConfigureShortcutsDialog::actionChanged( QTreeWidgetItem *current, QTreeWidgetItem *previous )
437{
438 Q_UNUSED( current )
439 Q_UNUSED( previous )
440 // cancel previous shortcut setting (if any)
441 setGettingShortcut( false );
442
443 QString shortcut;
444 QKeySequence sequence;
445 if ( QAction *action = currentAction() )
446 {
447 // show which one is the default action
448 shortcut = mManager->defaultKeySequence( action );
449 sequence = action->shortcut();
450 }
451 else if ( QShortcut *object = currentShortcut() )
452 {
453 // show which one is the default action
454 shortcut = mManager->defaultKeySequence( object );
455 sequence = object->key();
456 }
457 else
458 {
459 return;
460 }
461
462 if ( shortcut.isEmpty() )
463 shortcut = tr( "None" );
464 btnResetShortcut->setText( tr( "Set default (%1)" ).arg( shortcut ) );
465
466 // if there's no shortcut, disable set none
467 btnSetNoShortcut->setEnabled( !sequence.isEmpty() );
468 // if the shortcut is default, disable set default
469 btnResetShortcut->setEnabled( sequence != QKeySequence( shortcut ) );
470}
471
473{
474 if ( !mGettingShortcut )
475 {
476 QDialog::keyPressEvent( event );
477 return;
478 }
479
480 const int key = event->key();
481 switch ( key )
482 {
483 // modifiers
484 case Qt::Key_Meta:
485 mModifiers |= Qt::META;
486 updateShortcutText();
487 break;
488 case Qt::Key_Alt:
489 mModifiers |= Qt::ALT;
490 updateShortcutText();
491 break;
492 case Qt::Key_Control:
493 mModifiers |= Qt::CTRL;
494 updateShortcutText();
495 break;
496 case Qt::Key_Shift:
497 mModifiers |= Qt::SHIFT;
498 updateShortcutText();
499 break;
500
501 // escape aborts the acquisition of shortcut
502 case Qt::Key_Escape:
503 setGettingShortcut( false );
504 break;
505
506 default:
507 mKey = key;
508 updateShortcutText();
509 }
510}
511
513{
514 if ( !mGettingShortcut )
515 {
516 QDialog::keyReleaseEvent( event );
517 return;
518 }
519
520 const int key = event->key();
521 switch ( key )
522 {
523 // modifiers
524 case Qt::Key_Meta:
525 mModifiers &= ~Qt::META;
526 updateShortcutText();
527 break;
528 case Qt::Key_Alt:
529 mModifiers &= ~Qt::ALT;
530 updateShortcutText();
531 break;
532 case Qt::Key_Control:
533 mModifiers &= ~Qt::CTRL;
534 updateShortcutText();
535 break;
536 case Qt::Key_Shift:
537 mModifiers &= ~Qt::SHIFT;
538 updateShortcutText();
539 break;
540
541 case Qt::Key_Escape:
542 break;
543
544 default:
545 {
546 // an ordinary key - set it with modifiers as a shortcut
547 setCurrentActionShortcut( QKeySequence( mModifiers + mKey ) );
548 setGettingShortcut( false );
549 }
550 }
551}
552
553QObject *QgsConfigureShortcutsDialog::currentObject()
554{
555 if ( !treeActions->currentItem() )
556 return nullptr;
557
558 QObject *object = treeActions->currentItem()->data( 0, Qt::UserRole ).value<QObject *>();
559 return object;
560}
561
562void QgsConfigureShortcutsDialog::updateShortcutText()
563{
564 // update text of the button so that user can see what has typed already
565 const QKeySequence s( mModifiers + mKey );
566 btnChangeShortcut->setText( tr( "Input: " ) + s.toString( QKeySequence::NativeText ) );
567}
568
569void QgsConfigureShortcutsDialog::setGettingShortcut( bool getting )
570{
571 mModifiers = 0;
572 mKey = 0;
573 mGettingShortcut = getting;
574 if ( !getting )
575 {
576 btnChangeShortcut->setChecked( false );
577 btnChangeShortcut->setText( tr( "Change" ) );
578 }
579 else
580 {
581 updateShortcutText();
582 }
583}
584
585void QgsConfigureShortcutsDialog::setCurrentActionShortcut( const QKeySequence &s )
586{
587 QObject *object = currentObject();
588 if ( !object )
589 return;
590
591 // first check whether this action is not taken already
592 QObject *otherObject = mManager->objectForSequence( s );
593 if ( otherObject == object )
594 return;
595
596 if ( otherObject )
597 {
598 QString otherText;
599 if ( QAction *otherAction = qobject_cast<QAction *>( otherObject ) )
600 {
601 otherText = otherAction->text();
602 otherText.remove( '&' ); // remove the accelerator
603 }
604 else if ( QShortcut *otherShortcut = qobject_cast<QShortcut *>( otherObject ) )
605 {
606 otherText = otherShortcut->whatsThis();
607 }
608
609 const int res = QMessageBox::question( this, tr( "Change Shortcut" ), tr( "This shortcut is already assigned to action %1. Reassign?" ).arg( otherText ), QMessageBox::Yes | QMessageBox::No );
610
611 if ( res != QMessageBox::Yes )
612 return;
613
614 // reset action of the conflicting other action!
615 mManager->setObjectKeySequence( otherObject, QString() );
616 QList<QTreeWidgetItem *> items = treeActions->findItems( otherText, Qt::MatchExactly );
617 if ( !items.isEmpty() ) // there should be exactly one
618 items[0]->setText( 1, QString() );
619 }
620
621 // update manager
622 mManager->setObjectKeySequence( object, s.toString( QKeySequence::NativeText ) );
623
624 // update gui
625 treeActions->currentItem()->setText( 1, s.toString( QKeySequence::NativeText ) );
626
627 actionChanged( treeActions->currentItem(), nullptr );
628}
629
630void QgsConfigureShortcutsDialog::mLeFilter_textChanged( const QString &text )
631{
632 for ( int i = 0; i < treeActions->topLevelItemCount(); i++ )
633 {
634 QTreeWidgetItem *item = treeActions->topLevelItem( i );
635 if ( !item->text( 0 ).contains( text, Qt::CaseInsensitive ) && !item->text( 1 ).contains( text, Qt::CaseInsensitive ) )
636 {
637 item->setHidden( true );
638 }
639 else
640 {
641 item->setHidden( false );
642 }
643 }
644}
645
646void QgsConfigureShortcutsDialog::showHelp()
647{
648 QgsHelp::openHelp( QStringLiteral( "introduction/qgis_configuration.html#shortcuts" ) );
649}
650
651void QgsConfigureShortcutsDialog::saveShortcutsPdf()
652{
653 QString fileName = QFileDialog::getSaveFileName( this, tr( "Save Shortcuts" ), QDir::homePath(), tr( "PDF file" ) + " (*.pdf);;" + tr( "All files" ) + " (*)" );
654 // return dialog focus on Mac
655 activateWindow();
656 raise();
657
658 if ( fileName.isEmpty() )
659 return;
660
661 if ( !fileName.endsWith( QLatin1String( ".pdf" ), Qt::CaseInsensitive ) )
662 {
663 fileName += QLatin1String( ".pdf" );
664 }
665
666 QTextDocument *document = new QTextDocument;
667 QTextCursor cursor( document );
668
669 QTextTableFormat tableFormat;
670 tableFormat.setBorder( 0 );
671 tableFormat.setCellSpacing( 0 );
672 tableFormat.setCellPadding( 4 );
673 tableFormat.setHeaderRowCount( 1 );
674
675 QVector<QTextLength> constraints;
676 constraints << QTextLength( QTextLength::PercentageLength, 5 );
677 constraints << QTextLength( QTextLength::PercentageLength, 80 );
678 constraints << QTextLength( QTextLength::PercentageLength, 15 );
679 tableFormat.setColumnWidthConstraints( constraints );
680
681 QTextTableCellFormat headerFormat;
682 headerFormat.setFontWeight( QFont::Bold );
683 headerFormat.setBottomPadding( 4 );
684
685 QTextCharFormat rowFormat;
686 rowFormat.setVerticalAlignment( QTextCharFormat::AlignMiddle );
687
688 QTextCharFormat altRowFormat;
689 altRowFormat.setBackground( QBrush( QColor( 238, 238, 236 ) ) );
690 altRowFormat.setVerticalAlignment( QTextCharFormat::AlignMiddle );
691
692 int row = 0;
693 QTextTable *table = cursor.insertTable( 1, 3, tableFormat );
694 table->mergeCells( 0, 0, 1, 2 );
695 QTextCursor c = table->cellAt( row, 0 ).firstCursorPosition();
696 c.setCharFormat( headerFormat );
697 c.insertText( tr( "Action" ) );
698 c = table->cellAt( row, 2 ).firstCursorPosition();
699 c.setCharFormat( headerFormat );
700 c.insertText( tr( "Shortcut" ) );
701
702 const QList<QObject *> objects = mManager->listAll();
703 for ( QObject *obj : objects )
704 {
705 QString actionText;
706 QString sequence;
707 QIcon icon;
708
709 if ( QAction *action = qobject_cast<QAction *>( obj ) )
710 {
711 actionText = action->text().remove( '&' );
712 sequence = action->shortcut().toString( QKeySequence::NativeText );
713 icon = action->icon();
714 }
715 else if ( QShortcut *shortcut = qobject_cast<QShortcut *>( obj ) )
716 {
717 actionText = shortcut->whatsThis();
718 sequence = shortcut->key().toString( QKeySequence::NativeText );
719 icon = shortcut->property( "Icon" ).value<QIcon>();
720 }
721 else
722 {
723 continue;
724 }
725
726 // skip actions without shortcut and name
727 if ( actionText.isEmpty() || sequence.isEmpty() )
728 {
729 continue;
730 }
731
732 row += 1;
733 table->appendRows( 1 );
734
735 if ( row % 2 )
736 {
737 table->cellAt( row, 0 ).setFormat( altRowFormat );
738 table->cellAt( row, 1 ).setFormat( altRowFormat );
739 table->cellAt( row, 2 ).setFormat( altRowFormat );
740 }
741 else
742 {
743 table->cellAt( row, 0 ).setFormat( rowFormat );
744 table->cellAt( row, 1 ).setFormat( rowFormat );
745 table->cellAt( row, 2 ).setFormat( rowFormat );
746 }
747
748 if ( !icon.isNull() )
749 {
750 c = table->cellAt( row, 0 ).firstCursorPosition();
751 c.insertImage( icon.pixmap( QSize( 24, 24 ) ).toImage() );
752 }
753 table->cellAt( row, 1 ).firstCursorPosition().insertText( actionText );
754 table->cellAt( row, 2 ).firstCursorPosition().insertText( sequence );
755 }
756
757 QPdfWriter pdfWriter( fileName );
758 pdfWriter.setPageLayout( QPageLayout( QPageSize( QPageSize::A4 ), QPageLayout::Portrait, QMarginsF( 20, 10, 10, 10 ) ) );
759 document->setPageSize( QSizeF( pdfWriter.pageLayout().fullRect( QPageLayout::Point ).size() ) );
760 document->print( &pdfWriter );
761}
static const QgsSettingsEntryBool * settingsLocaleOverrideFlag
Settings entry locale override flag.
static const QgsSettingsEntryString * settingsLocaleUserLocale
Settings entry locale user locale.
QgsConfigureShortcutsDialog(QWidget *parent=nullptr, QgsShortcutsManager *manager=nullptr)
Constructor for QgsConfigureShortcutsDialog.
void keyReleaseEvent(QKeyEvent *event) override
void keyPressEvent(QKeyEvent *event) override
static QgsShortcutsManager * shortcutsManager()
Returns the global shortcuts manager, used for managing a QAction and QShortcut sequences.
Definition qgsgui.cpp:136
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...
Definition qgsgui.cpp:221
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:38
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.
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...
QList< QObject * > listAll() const
Returns a list of both actions and shortcuts in the manager.
QString objectSettingKey(QObject *object) const
Returns the full settings key matching the QShortcut or QAction Return an empty QString if the QObjec...
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