diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-06-14 16:40:50 +0200 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-11-02 13:12:28 +0000 |
commit | 7ae55889805bc1d62c0268938eeca20bec9b773c (patch) | |
tree | eda6308c079d08ba2cc6f8e4ca514c3982bf9adf | |
parent | 287411a3923f5fc1cf10aff7eeec66d834810790 (diff) |
Visualize mnemonics
Unfortunately this comes a bit late in the 5.10 cycle, but this should
be released together with the rest of the mnemonics stuff going out in
5.10, because it affects the value of AbstractButton/Menu(Bar)Item::text.
As the removed TODO comments and altered tests indicate, previously the
ampersand was blatantly stripped out. It would be worse to change it
later once people have already started using mnemonics and rely on the
behavior in custom styles.
The necessary modifications to QQuickText were added in qtdeclarative
commit 65ef4ba.
Task-number: QTBUG-61422
Change-Id: Iaa73da8c012e9a6019743cf98f5bdc02527064e5
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r-- | src/imports/controls/doc/snippets/qtquickcontrols2-menubar.qml | 24 | ||||
-rw-r--r-- | src/imports/controls/qtquickcontrols2plugin.cpp | 2 | ||||
-rw-r--r-- | src/quickcontrols2/qquickiconlabel.cpp | 3 | ||||
-rw-r--r-- | src/quickcontrols2/qquickiconlabel_p_p.h | 4 | ||||
-rw-r--r-- | src/quickcontrols2/qquickmnemoniclabel.cpp | 133 | ||||
-rw-r--r-- | src/quickcontrols2/qquickmnemoniclabel_p.h | 82 | ||||
-rw-r--r-- | src/quickcontrols2/quickcontrols2.pri | 2 | ||||
-rw-r--r-- | src/quicktemplates2/qquickabstractbutton.cpp | 2 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_abstractbutton.qml | 4 |
9 files changed, 238 insertions, 18 deletions
diff --git a/src/imports/controls/doc/snippets/qtquickcontrols2-menubar.qml b/src/imports/controls/doc/snippets/qtquickcontrols2-menubar.qml index 2c0b6c8e..550680f6 100644 --- a/src/imports/controls/doc/snippets/qtquickcontrols2-menubar.qml +++ b/src/imports/controls/doc/snippets/qtquickcontrols2-menubar.qml @@ -44,23 +44,23 @@ ApplicationWindow { menuBar: MenuBar { Menu { - title: qsTr("File") - Action { text: qsTr("New...") } - Action { text: qsTr("Open...") } - Action { text: qsTr("Save") } - Action { text: qsTr("Save As...") } + title: qsTr("&File") + Action { text: qsTr("&New...") } + Action { text: qsTr("&Open...") } + Action { text: qsTr("&Save") } + Action { text: qsTr("Save &As...") } MenuSeparator { } - Action { text: qsTr("Quit") } + Action { text: qsTr("&Quit") } } Menu { - title: qsTr("Edit") - Action { text: qsTr("Cut") } - Action { text: qsTr("Copy") } - Action { text: qsTr("Paste") } + title: qsTr("&Edit") + Action { text: qsTr("Cu&t") } + Action { text: qsTr("&Copy") } + Action { text: qsTr("&Paste") } } Menu { - title: qsTr("Help") - Action { text: qsTr("About") } + title: qsTr("&Help") + Action { text: qsTr("&About") } } } } diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 5f019a4e..4ac5b7e0 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -40,6 +40,7 @@ #include <QtQuickControls2/private/qquickcolor_p.h> #include <QtQuickControls2/private/qquickcolorimage_p.h> #include <QtQuickControls2/private/qquickiconimage_p.h> +#include <QtQuickControls2/private/qquickmnemoniclabel_p.h> #include <QtQuickControls2/private/qquickpaddedrectangle_p.h> #include <QtQuickControls2/private/qquickplaceholdertext_p.h> #include <QtQuickControls2/private/qquickiconlabel_p.h> @@ -200,6 +201,7 @@ void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char *ur qmlRegisterSingletonType<QQuickColor>(import, 2, 3, "Color", colorSingleton); qmlRegisterType<QQuickIconLabel>(import, 2, 3, "IconLabel"); qmlRegisterType<QQuickCheckLabel>(import, 2, 3, "CheckLabel"); + qmlRegisterType<QQuickMnemonicLabel>(import, 2, 3, "MnemonicLabel"); qmlRegisterRevision<QQuickText, 6>(import, 2, 3); } diff --git a/src/quickcontrols2/qquickiconlabel.cpp b/src/quickcontrols2/qquickiconlabel.cpp index 06d74d43..266d30d7 100644 --- a/src/quickcontrols2/qquickiconlabel.cpp +++ b/src/quickcontrols2/qquickiconlabel.cpp @@ -37,6 +37,7 @@ #include "qquickiconlabel_p.h" #include "qquickiconlabel_p_p.h" #include "qquickiconimage_p.h" +#include "qquickmnemoniclabel_p.h" #include <QtGui/private/qguiapplication_p.h> #include <QtQuick/private/qquickitem_p.h> @@ -147,7 +148,7 @@ bool QQuickIconLabelPrivate::createLabel() if (label) return false; - label = new QQuickText(q); + label = new QQuickMnemonicLabel(q); watchChanges(label); beginClass(label); label->setObjectName(QStringLiteral("label")); diff --git a/src/quickcontrols2/qquickiconlabel_p_p.h b/src/quickcontrols2/qquickiconlabel_p_p.h index 5762187c..f0f4df4c 100644 --- a/src/quickcontrols2/qquickiconlabel_p_p.h +++ b/src/quickcontrols2/qquickiconlabel_p_p.h @@ -54,8 +54,8 @@ QT_BEGIN_NAMESPACE -class QQuickText; class QQuickIconImage; +class QQuickMnemonicLabel; class QQuickIconLabelPrivate : public QQuickItemPrivate, public QQuickItemChangeListener { @@ -105,7 +105,7 @@ public: QString text; QQuickIcon icon; QQuickIconImage *image; - QQuickText *label; + QQuickMnemonicLabel *label; }; QT_END_NAMESPACE diff --git a/src/quickcontrols2/qquickmnemoniclabel.cpp b/src/quickcontrols2/qquickmnemoniclabel.cpp new file mode 100644 index 00000000..9c8e9ab1 --- /dev/null +++ b/src/quickcontrols2/qquickmnemoniclabel.cpp @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickmnemoniclabel_p.h" + +#include <QtQuick/private/qquicktext_p_p.h> + +QT_BEGIN_NAMESPACE + +QQuickMnemonicLabel::QQuickMnemonicLabel(QQuickItem *parent) + : QQuickText(parent), + m_mnemonicVisible(true) +{ +} + +QString QQuickMnemonicLabel::text() const +{ + return m_fullText; +} + +void QQuickMnemonicLabel::setText(const QString &text) +{ + if (m_fullText == text) + return; + + m_fullText = text; + updateMnemonic(); +} + +bool QQuickMnemonicLabel::isMnemonicVisible() const +{ + return m_mnemonicVisible; +} + +void QQuickMnemonicLabel::setMnemonicVisible(bool visible) +{ + if (m_mnemonicVisible == visible) + return; + + m_mnemonicVisible = visible; + updateMnemonic(); + + if (isComponentComplete()) + forceLayout(); +} + +static QTextLayout::FormatRange underlineRange(int start, int length = 1) +{ + QTextLayout::FormatRange range; + range.start = start; + range.length = length; + range.format.setFontUnderline(true); + return range; +} + +// based on QPlatformTheme::removeMnemonics() +void QQuickMnemonicLabel::updateMnemonic() +{ + QString text(m_fullText.size(), 0); + int idx = 0; + int pos = 0; + int len = m_fullText.length(); + QVector<QTextLayout::FormatRange> formats; + while (len) { + if (m_fullText.at(pos) == QLatin1Char('&') && (len == 1 || m_fullText.at(pos + 1) != QLatin1Char('&'))) { + if (m_mnemonicVisible && (pos == 0 || m_fullText.at(pos - 1) != QLatin1Char('&'))) + formats += underlineRange(pos); + ++pos; + --len; + if (len == 0) + break; + } else if (m_fullText.at(pos) == QLatin1Char('(') && len >= 4 && + m_fullText.at(pos + 1) == QLatin1Char('&') && + m_fullText.at(pos + 2) != QLatin1Char('&') && + m_fullText.at(pos + 3) == QLatin1Char(')')) { + // a mnemonic with format "\s*(&X)" + if (m_mnemonicVisible) { + formats += underlineRange(pos + 1); + } else { + int n = 0; + while (idx > n && text.at(idx - n - 1).isSpace()) + ++n; + idx -= n; + pos += 4; + len -= 4; + continue; + } + } + text[idx] = m_fullText.at(pos); + ++pos; + ++idx; + --len; + } + text.truncate(idx); + + QQuickTextPrivate::get(this)->layout.setFormats(formats); + QQuickText::setText(text); +} + +QT_END_NAMESPACE diff --git a/src/quickcontrols2/qquickmnemoniclabel_p.h b/src/quickcontrols2/qquickmnemoniclabel_p.h new file mode 100644 index 00000000..33bc1e08 --- /dev/null +++ b/src/quickcontrols2/qquickmnemoniclabel_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKMNEMONICLABEL_P_H +#define QQUICKMNEMONICLABEL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtQuick/private/qquicktext_p.h> +#include <QtQuickControls2/private/qtquickcontrols2global_p.h> + +QT_BEGIN_NAMESPACE + +class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickMnemonicLabel : public QQuickText +{ + Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText FINAL) + Q_PROPERTY(bool mnemonicVisible READ isMnemonicVisible WRITE setMnemonicVisible FINAL) + +public: + explicit QQuickMnemonicLabel(QQuickItem *parent = nullptr); + + QString text() const; + void setText(const QString &text); + + bool isMnemonicVisible() const; + void setMnemonicVisible(bool visible); + +private: + void updateMnemonic(); + + bool m_mnemonicVisible; + QString m_fullText; +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickMnemonicLabel) + +#endif // QQUICKMNEMONICLABEL_P_H diff --git a/src/quickcontrols2/quickcontrols2.pri b/src/quickcontrols2/quickcontrols2.pri index 66a109f5..6537a599 100644 --- a/src/quickcontrols2/quickcontrols2.pri +++ b/src/quickcontrols2/quickcontrols2.pri @@ -8,6 +8,7 @@ HEADERS += \ $$PWD/qquickiconimage_p_p.h \ $$PWD/qquickiconlabel_p.h \ $$PWD/qquickiconlabel_p_p.h \ + $$PWD/qquickmnemoniclabel_p.h \ $$PWD/qquickpaddedrectangle_p.h \ $$PWD/qquickplaceholdertext_p.h \ $$PWD/qquickproxytheme_p.h \ @@ -26,6 +27,7 @@ SOURCES += \ $$PWD/qquickcolorimage.cpp \ $$PWD/qquickiconimage.cpp \ $$PWD/qquickiconlabel.cpp \ + $$PWD/qquickmnemoniclabel.cpp \ $$PWD/qquickpaddedrectangle.cpp \ $$PWD/qquickplaceholdertext.cpp \ $$PWD/qquickproxytheme.cpp \ diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index 2c77d941..03f525f0 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -409,7 +409,7 @@ void QQuickAbstractButton::setText(const QString &text) setShortcut(QKeySequence::mnemonic(text)); #endif - d->text = QPlatformTheme::removeMnemonics(text); // ### TODO: visualize mnemonics + d->text = text; setAccessibleName(d->text); buttonChange(ButtonTextChange); emit textChanged(); diff --git a/tests/auto/controls/data/tst_abstractbutton.qml b/tests/auto/controls/data/tst_abstractbutton.qml index 168844a0..90c6567f 100644 --- a/tests/auto/controls/data/tst_abstractbutton.qml +++ b/tests/auto/controls/data/tst_abstractbutton.qml @@ -303,7 +303,7 @@ TestCase { verify(control) control.text = "&Hello" - compare(control.text, "Hello") // ### TODO: visualize mnemonics + compare(control.text, "&Hello") var clickSpy = signalSpy.createObject(control, {target: control, signalName: "clicked"}) verify(clickSpy.valid) @@ -320,7 +320,7 @@ TestCase { compare(clickSpy.count, 2) control.text = "Te&st" - compare(control.text, "Test") // ### TODO: visualize mnemonics + compare(control.text, "Te&st") keyClick(Qt.Key_H, Qt.AltModifier) compare(clickSpy.count, 2) |