Add new API to control whether shortcuts are shown in context menus

Shortcuts are universally not shown on macOS or mobile platforms, making
applications look very obviously out of place.

Windows and GNOME desktop environments almost never use them.

Only KDE appears to do so commonly; default accordingly.

Task-number: QTBUG-49435
Change-Id: Ieac4cee57b15a02be5258f3d07749af6316af62b
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@qt.io>
This commit is contained in:
Jake Petroules 2017-03-10 16:55:04 -08:00
parent b6e3fd8ced
commit c2c3452ba5
14 changed files with 84 additions and 5 deletions

View File

@ -508,6 +508,7 @@ public:
AA_CompressHighFrequencyEvents = 25,
AA_DontCheckOpenGLContextThreadAffinity = 26,
AA_DisableShaderDiskCache = 27,
AA_DontShowShortcutsInContextMenus = 28,
// Add new attributes before this line
AA_AttributeCount

View File

@ -114,6 +114,11 @@
\macos menubar \e{may not} pick up a change in this attribute. Changes
in the QAction::iconVisibleInMenu property will always be picked up.
\value AA_DontShowShortcutsInContextMenus Actions with the Shortcut property
won't be shown in any shortcut menus unless specifically set by the
QAction::shortcutVisibleInContextMenu property. This value has
been added in Qt 5.10.
\value AA_NativeWindows Ensures that widgets have native windows.
\value AA_DontCreateNativeWidgetSiblings Ensures that siblings of native

View File

@ -392,6 +392,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const
return false;
case ShowIsMaximized:
return false;
case ShowShortcutsInContextMenus:
return QPlatformTheme::defaultThemeHint(QPlatformTheme::ShowShortcutsInContextMenus);
case PasswordMaskDelay:
return QPlatformTheme::defaultThemeHint(QPlatformTheme::PasswordMaskDelay);
case PasswordMaskCharacter:

View File

@ -161,6 +161,7 @@ public:
ItemViewActivateItemOnSingleClick,
UiEffects,
WheelScrollLines,
ShowShortcutsInContextMenus,
};
virtual QVariant styleHint(StyleHint hint) const;

View File

@ -161,6 +161,8 @@ QT_BEGIN_NAMESPACE
The default value is double the MouseDoubleClickDistance, or 10 logical pixels
if that is not specified.
\value ShowShortcutsInContextMenus (bool) Whether to display shortcut key sequences in context menus.
\sa themeHint(), QStyle::pixelMetric()
*/
@ -516,6 +518,8 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
return QVariant(QStringList());
case QPlatformTheme::StyleNames:
return QVariant(QStringList());
case QPlatformTheme::ShowShortcutsInContextMenus:
return QVariant(false);
case TextCursorWidth:
return QVariant(1);
case DropShadow:

View File

@ -115,7 +115,8 @@ public:
MousePressAndHoldInterval,
MouseDoubleClickDistance,
WheelScrollLines,
TouchDoubleTapDistance
TouchDoubleTapDistance,
ShowShortcutsInContextMenus
};
enum DialogType {

View File

@ -364,6 +364,17 @@ bool QStyleHints::showIsMaximized() const
return hint(QPlatformIntegration::ShowIsMaximized).toBool();
}
/*!
\property QStyleHints::showShortcutsInContextMenus
\since 5.10
\brief \c true if the platform normally shows shortcut key sequences in
context menus, otherwise \c false.
*/
bool QStyleHints::showShortcutsInContextMenus() const
{
return themeableHint(QPlatformTheme::ShowShortcutsInContextMenus, QPlatformIntegration::ShowShortcutsInContextMenus).toBool();
}
/*!
\property QStyleHints::passwordMaskDelay
\brief the time, in milliseconds, a typed letter is displayed unshrouded

View File

@ -90,6 +90,7 @@ public:
int cursorFlashTime() const;
bool showIsFullScreen() const;
bool showIsMaximized() const;
bool showShortcutsInContextMenus() const;
int passwordMaskDelay() const;
QChar passwordMaskCharacter() const;
qreal fontSmoothingGamma() const;

View File

@ -45,6 +45,7 @@
#include "qapplication.h"
#include "qevent.h"
#include "qlist.h"
#include "qstylehints.h"
#include <private/qshortcutmap_p.h>
#include <private/qapplication_p.h>
#include <private/qmenu_p.h>
@ -75,6 +76,7 @@ static QString qt_strippedText(QString s)
QActionPrivate::QActionPrivate() : group(0), enabled(1), forceDisabled(0),
visible(1), forceInvisible(0), checkable(0), checked(0), separator(0), fontSet(false),
iconVisibleInMenu(-1),
shortcutVisibleInContextMenu(-1),
menuRole(QAction::TextHeuristicRole),
priority(QAction::NormalPriority)
{
@ -1292,6 +1294,46 @@ bool QAction::isIconVisibleInMenu() const
return d->iconVisibleInMenu;
}
/*!
\property QAction::shortcutVisibleInContextMenu
\brief Whether or not an action should show a shortcut in a context menu
\since 5.10
In some applications, it may make sense to have actions with shortcuts in
context menus. If true, the shortcut (if valid) is shown when the action is
shown via a context menu, when it is false, it is not shown.
The default is to follow whether the Qt::AA_DontShowShortcutsInContextMenus attribute
is set for the application, falling back to the widget style hint.
Explicitly setting this property overrides the presence (or abscence) of the attribute.
\sa QAction::shortcut, QCoreApplication::setAttribute()
*/
void QAction::setShortcutVisibleInContextMenu(bool visible)
{
Q_D(QAction);
if (d->shortcutVisibleInContextMenu == -1 || visible != bool(d->shortcutVisibleInContextMenu)) {
int oldValue = d->shortcutVisibleInContextMenu;
d->shortcutVisibleInContextMenu = visible;
// Only send data changed if we really need to.
if (oldValue != -1
|| visible == !QApplication::instance()->testAttribute(Qt::AA_DontShowShortcutsInContextMenus)) {
d->sendDataChanged();
}
}
}
bool QAction::isShortcutVisibleInContextMenu() const
{
Q_D(const QAction);
if (d->shortcutVisibleInContextMenu == -1) {
if (QApplication::instance()->testAttribute(Qt::AA_DontShowIconsInMenus))
return false;
return qApp->styleHints()->showShortcutsInContextMenus();
}
return d->shortcutVisibleInContextMenu;
}
#ifndef QT_NO_DEBUG_STREAM
Q_WIDGETS_EXPORT QDebug operator<<(QDebug d, const QAction *action)
{

View File

@ -80,6 +80,7 @@ class Q_WIDGETS_EXPORT QAction : public QObject
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed)
Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed)
Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed)
Q_PROPERTY(bool shortcutVisibleInContextMenu READ isShortcutVisibleInContextMenu WRITE setShortcutVisibleInContextMenu NOTIFY changed)
Q_PROPERTY(Priority priority READ priority WRITE setPriority)
public:
@ -168,6 +169,8 @@ public:
void setIconVisibleInMenu(bool visible);
bool isIconVisibleInMenu() const;
void setShortcutVisibleInContextMenu(bool show);
bool isShortcutVisibleInContextMenu() const;
QWidget *parentWidget() const;

View File

@ -106,6 +106,7 @@ public:
uint fontSet : 1;
int iconVisibleInMenu : 3; // Only has values -1, 0, and 1
int shortcutVisibleInContextMenu : 2; // Only has values -1, 0, and 1
QAction::MenuRole menuRole;
QAction::Priority priority;

View File

@ -74,7 +74,10 @@
#include "private/qapplication_p.h"
#include "private/qshortcutmap_p.h"
#include "qkeysequence.h"
#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \
#define ACCEL_KEY(k) ((qApp->testAttribute(Qt::AA_DontShowIconsInMenus) \
? false \
: qApp->styleHints()->showShortcutsInContextMenus()) \
&& !qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \
QLatin1Char('\t') + QKeySequence(k).toString(QKeySequence::NativeText) : QString())
#else
#define ACCEL_KEY(k) QString()

View File

@ -332,7 +332,7 @@ void QMenuPrivate::updateActionRects(const QRect &screen) const
tabWidth = qMax(int(tabWidth), qfm.width(s.mid(t+1)));
s = s.left(t);
#ifndef QT_NO_SHORTCUT
} else {
} else if (action->isShortcutVisibleInContextMenu()) {
QKeySequence seq = action->shortcut();
if (!seq.isEmpty())
tabWidth = qMax(int(tabWidth), qfm.width(seq.toString(QKeySequence::NativeText)));
@ -1447,7 +1447,8 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action)
option->icon = action->icon();
QString textAndAccel = action->text();
#ifndef QT_NO_SHORTCUT
if (textAndAccel.indexOf(QLatin1Char('\t')) == -1) {
if (action->isShortcutVisibleInContextMenu()
&& textAndAccel.indexOf(QLatin1Char('\t')) == -1) {
QKeySequence seq = action->shortcut();
if (!seq.isEmpty())
textAndAccel += QLatin1Char('\t') + seq.toString(QKeySequence::NativeText);

View File

@ -85,7 +85,10 @@
#include "private/qapplication_p.h"
#include "private/qshortcutmap_p.h"
#include <qkeysequence.h>
#define ACCEL_KEY(k) (!qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \
#define ACCEL_KEY(k) ((qApp->testAttribute(Qt::AA_DontShowIconsInMenus) \
? false \
: qApp->styleHints()->showShortcutsInContextMenus()) \
&& !qApp->d_func()->shortcutMap.hasShortcutForKeySequence(k) ? \
QLatin1Char('\t') + QKeySequence(k).toString(QKeySequence::NativeText) : QString())
#else