aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-06-01 20:09:44 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2017-06-02 14:05:45 +0000
commitecef73ddb0c6038f6e0208121cfb8786c2cab7f2 (patch)
tree7d5834b7afdd8eb635e6a301b6d670a3938ee4f2
parent1b98cac7c0f7d5515f7bcc6e55e8291eff9e43b7 (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.qml2
-rw-r--r--src/imports/controls/fusion/Menu.qml2
-rw-r--r--src/imports/controls/material/Menu.qml2
-rw-r--r--src/imports/controls/universal/Menu.qml2
-rw-r--r--src/quicktemplates2/qquickmenu.cpp80
-rw-r--r--src/quicktemplates2/qquickmenu_p.h6
-rw-r--r--src/quicktemplates2/qquickmenu_p_p.h4
-rw-r--r--tests/auto/menu/data/actions.qml67
-rw-r--r--tests/auto/menu/tst_menu.cpp32
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"