diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-06-01 20:09:44 +0200 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-06-02 14:05:45 +0000 |
commit | ecef73ddb0c6038f6e0208121cfb8786c2cab7f2 (patch) | |
tree | 7d5834b7afdd8eb635e6a301b6d670a3938ee4f2 | |
parent | 1b98cac7c0f7d5515f7bcc6e55e8291eff9e43b7 (diff) |
QQuickMenu: add support for declaring Actions
[ChangeLog][Controls][Menu] Added support for declaring Actions.
The new "delegate" property is used to define a Component that is
used to create menu items that present the actions.
Change-Id: If26f38f6910aa5592879703429a2b418193d5710
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r-- | src/imports/controls/Menu.qml | 2 | ||||
-rw-r--r-- | src/imports/controls/fusion/Menu.qml | 2 | ||||
-rw-r--r-- | src/imports/controls/material/Menu.qml | 2 | ||||
-rw-r--r-- | src/imports/controls/universal/Menu.qml | 2 | ||||
-rw-r--r-- | src/quicktemplates2/qquickmenu.cpp | 80 | ||||
-rw-r--r-- | src/quicktemplates2/qquickmenu_p.h | 6 | ||||
-rw-r--r-- | src/quicktemplates2/qquickmenu_p_p.h | 4 | ||||
-rw-r--r-- | tests/auto/menu/data/actions.qml | 67 | ||||
-rw-r--r-- | tests/auto/menu/tst_menu.cpp | 32 |
9 files changed, 196 insertions, 1 deletions
diff --git a/src/imports/controls/Menu.qml b/src/imports/controls/Menu.qml index 9e4ce902..31c9230a 100644 --- a/src/imports/controls/Menu.qml +++ b/src/imports/controls/Menu.qml @@ -49,6 +49,8 @@ T.Menu { margins: 0 + delegate: MenuItem { } + contentItem: ListView { implicitHeight: contentHeight model: control.contentModel diff --git a/src/imports/controls/fusion/Menu.qml b/src/imports/controls/fusion/Menu.qml index 9343afea..3fd4caa2 100644 --- a/src/imports/controls/fusion/Menu.qml +++ b/src/imports/controls/fusion/Menu.qml @@ -52,6 +52,8 @@ T.Menu { margins: 0 padding: 1 + delegate: MenuItem { } + contentItem: ListView { implicitHeight: contentHeight model: control.contentModel diff --git a/src/imports/controls/material/Menu.qml b/src/imports/controls/material/Menu.qml index 9767eed0..1d0d368a 100644 --- a/src/imports/controls/material/Menu.qml +++ b/src/imports/controls/material/Menu.qml @@ -56,6 +56,8 @@ T.Menu { transformOrigin: Item.Top + delegate: MenuItem { } + enter: Transition { // grow_fade_in NumberAnimation { property: "scale"; from: 0.9; to: 1.0; easing.type: Easing.OutQuint; duration: 220 } diff --git a/src/imports/controls/universal/Menu.qml b/src/imports/controls/universal/Menu.qml index 60dc8904..d7a27563 100644 --- a/src/imports/controls/universal/Menu.qml +++ b/src/imports/controls/universal/Menu.qml @@ -49,6 +49,8 @@ T.Menu { margins: 0 + delegate: MenuItem { } + contentItem: ListView { implicitHeight: contentHeight model: control.contentModel diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index 726a0fca..63d5d00c 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -39,11 +39,14 @@ #include "qquickmenuitem_p.h" #include "qquickcontrol_p_p.h" #include "qquickpopupitem_p_p.h" +#include "qquickaction_p.h" #include <QtGui/qevent.h> #include <QtGui/qcursor.h> #include <QtGui/qpa/qplatformintegration.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtQml/qqmlcontext.h> +#include <QtQml/qqmlcomponent.h> #include <QtQml/private/qqmlengine_p.h> #include <QtQml/private/qv4scopedvalue_p.h> #include <QtQml/private/qv4variantobject_p.h> @@ -129,6 +132,17 @@ QT_BEGIN_NAMESPACE } \endcode + Since QtQuick.Controls 2.3 (Qt 5.10), it is also possible to declare + Action objects inside Menu: + + \code + Menu { + Action { text: "Cut" } + Action { text: "Copy" } + Action { text: "Paste" } + } + \endcode + Typically, menu items are statically declared as children of the menu, but Menu also provides API to \l {addItem}{add}, \l {insertItem}{insert}, \l {moveItem}{move} and \l {removeItem}{remove} items dynamically. The @@ -143,7 +157,8 @@ QT_BEGIN_NAMESPACE QQuickMenuPrivate::QQuickMenuPrivate() : contentItem(nullptr), - contentModel(nullptr) + contentModel(nullptr), + delegate(nullptr) { Q_Q(QQuickMenu); contentModel = new QQmlObjectModel(q); @@ -196,6 +211,30 @@ void QQuickMenuPrivate::removeItem(int index, QQuickItem *item) } } +QQuickItem *QQuickMenuPrivate::createItem(QQuickAction *action) +{ + Q_Q(QQuickMenu); + if (!delegate) + return nullptr; + + QQmlContext *creationContext = delegate->creationContext(); + if (!creationContext) + creationContext = qmlContext(q); + QQmlContext *context = new QQmlContext(creationContext, q); + context->setContextObject(q); + + QObject *object = delegate->beginCreate(context); + if (QQuickItem *item = qobject_cast<QQuickItem *>(object)) { + if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(object)) + button->setAction(action); + delegate->completeCreate(); + return item; + } + + delete object; + return nullptr; +} + void QQuickMenuPrivate::resizeItem(QQuickItem *item) { if (!item || !contentItem) @@ -293,7 +332,13 @@ void QQuickMenuPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObj { QQuickMenuPrivate *p = static_cast<QQuickMenuPrivate *>(prop->data); QQuickMenu *q = static_cast<QQuickMenu *>(prop->object); + QQuickItem *item = qobject_cast<QQuickItem *>(obj); + if (!item) { + if (QQuickAction *action = qobject_cast<QQuickAction *>(obj)) + item = p->createItem(action); + } + if (item) { if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) { QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder); @@ -493,6 +538,39 @@ void QQuickMenu::setTitle(QString &title) /*! \since QtQuick.Controls 2.3 (Qt 5.10) + \qmlproperty Component QtQuick.Controls::Menu::delegate + + This property holds the component that is used to create items + to present actions. + + \code + Menu { + Action { text: "Cut" } + Action { text: "Copy" } + Action { text: "Paste" } + } + \endcode + + \sa Action +*/ +QQmlComponent *QQuickMenu::delegate() const +{ + Q_D(const QQuickMenu); + return d->delegate; +} + +void QQuickMenu::setDelegate(QQmlComponent *delegate) +{ + Q_D(QQuickMenu); + if (d->delegate == delegate) + return; + + d->delegate = delegate; + emit delegateChanged(); +} + +/*! + \since QtQuick.Controls 2.3 (Qt 5.10) \qmlmethod void QtQuick.Controls::Menu::popup(MenuItem item = null) Opens the menu at the mouse cursor on desktop platforms that have a mouse cursor diff --git a/src/quicktemplates2/qquickmenu_p.h b/src/quicktemplates2/qquickmenu_p.h index 868daaa3..bfb1d605 100644 --- a/src/quicktemplates2/qquickmenu_p.h +++ b/src/quicktemplates2/qquickmenu_p.h @@ -55,6 +55,7 @@ QT_BEGIN_NAMESPACE +class QQmlComponent; class QQuickMenuItem; class QQuickMenuPrivate; @@ -64,6 +65,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenu : public QQuickPopup Q_PROPERTY(QVariant contentModel READ contentModel CONSTANT FINAL) Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL) Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged) + Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL REVISION 3) Q_CLASSINFO("DefaultProperty", "contentData") public: @@ -81,6 +83,9 @@ public: QString title() const; void setTitle(QString &title); + QQmlComponent *delegate() const; + void setDelegate(QQmlComponent *delegate); + Q_REVISION(3) Q_INVOKABLE void popup(QQmlV4Function *args); protected: @@ -91,6 +96,7 @@ protected: Q_SIGNALS: void titleChanged(); + Q_REVISION(3) void delegateChanged(); protected: QPalette defaultPalette() const override; diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h index 504bc74d..e78076ad 100644 --- a/src/quicktemplates2/qquickmenu_p_p.h +++ b/src/quicktemplates2/qquickmenu_p_p.h @@ -55,6 +55,8 @@ QT_BEGIN_NAMESPACE +class QQuickAction; +class QQmlComponent; class QQmlObjectModel; class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuPrivate : public QQuickPopupPrivate @@ -68,6 +70,7 @@ public: void insertItem(int index, QQuickItem *item); void moveItem(int from, int to); void removeItem(int index, QQuickItem *item); + QQuickItem *createItem(QQuickAction *action); void resizeItem(QQuickItem *item); void resizeItems(); @@ -92,6 +95,7 @@ public: QQuickItem *contentItem; // TODO: cleanup QVector<QObject *> contentData; QQmlObjectModel *contentModel; + QQmlComponent *delegate; QString title; }; diff --git a/tests/auto/menu/data/actions.qml b/tests/auto/menu/data/actions.qml new file mode 100644 index 00000000..7cb1215c --- /dev/null +++ b/tests/auto/menu/data/actions.qml @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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 https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.9 +import QtQuick.Controls 2.3 + +ApplicationWindow { + width: 400 + height: 400 + + property alias menu: menu + + Menu { + id: menu + Action { text: "action1" } + MenuItem { text: "menuitem2" } + Action { text: "action3" } + MenuItem { text: "menuitem4" } + } +} diff --git a/tests/auto/menu/tst_menu.cpp b/tests/auto/menu/tst_menu.cpp index 48a0b27a..739488ec 100644 --- a/tests/auto/menu/tst_menu.cpp +++ b/tests/auto/menu/tst_menu.cpp @@ -71,6 +71,7 @@ private slots: void repeater(); void order(); void popup(); + void actions(); }; void tst_menu::defaults() @@ -449,6 +450,37 @@ void tst_menu::popup() #endif } +void tst_menu::actions() +{ + QQuickApplicationHelper helper(this, QLatin1String("actions.qml")); + QQuickWindow *window = helper.window; + window->show(); + QVERIFY(QTest::qWaitForWindowActive(window)); + + QQuickMenu *menu = window->property("menu").value<QQuickMenu *>(); + QVERIFY(menu); + + QQuickMenuItem *menuItem1 = qobject_cast<QQuickMenuItem *>(menu->itemAt(0)); + QVERIFY(menuItem1); + QVERIFY(menuItem1->action()); + QCOMPARE(menuItem1->text(), "action1"); + + QQuickMenuItem *menuItem2 = qobject_cast<QQuickMenuItem *>(menu->itemAt(1)); + QVERIFY(menuItem2); + QVERIFY(!menuItem2->action()); + QCOMPARE(menuItem2->text(), "menuitem2"); + + QQuickMenuItem *menuItem3 = qobject_cast<QQuickMenuItem *>(menu->itemAt(2)); + QVERIFY(menuItem3); + QVERIFY(menuItem3->action()); + QCOMPARE(menuItem3->text(), "action3"); + + QQuickMenuItem *menuItem4 = qobject_cast<QQuickMenuItem *>(menu->itemAt(3)); + QVERIFY(menuItem4); + QVERIFY(!menuItem4->action()); + QCOMPARE(menuItem4->text(), "menuitem4"); +} + QTEST_MAIN(tst_menu) #include "tst_menu.moc" |