aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2016-05-22 19:04:03 +0200
committerJ-P Nurmi <jpnurmi@qt.io>2016-06-16 06:50:30 +0000
commite9e68baf652eca70c6a4c080ed9e49c70c8c9984 (patch)
tree33e4c8b3ffe5e1be597c4fe6fa87ed65239ed7b2
parent30d931b866bf6cdf7900d0c7f85734e0bfe03a6f (diff)
Platform menus
Change-Id: Ifbca41ef384ca8fe8afefc61869f85c17db0f8c7 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
-rw-r--r--src/imports/platform/doc/images/qtlabsplatform-menu.pngbin0 -> 6377 bytes
-rw-r--r--src/imports/platform/doc/images/qtlabsplatform-menubar.pngbin0 -> 71036 bytes
-rw-r--r--src/imports/platform/platform.pri12
-rw-r--r--src/imports/platform/qquickplatformmenu.cpp792
-rw-r--r--src/imports/platform/qquickplatformmenu_p.h206
-rw-r--r--src/imports/platform/qquickplatformmenubar.cpp326
-rw-r--r--src/imports/platform/qquickplatformmenubar_p.h120
-rw-r--r--src/imports/platform/qquickplatformmenuitem.cpp605
-rw-r--r--src/imports/platform/qquickplatformmenuitem_p.h191
-rw-r--r--src/imports/platform/qquickplatformmenuitemgroup.cpp390
-rw-r--r--src/imports/platform/qquickplatformmenuitemgroup_p.h123
-rw-r--r--src/imports/platform/qtlabsplatformplugin.cpp10
-rw-r--r--tests/auto/platform/data/tst_menu.qml235
-rw-r--r--tests/auto/platform/data/tst_menubar.qml229
-rw-r--r--tests/auto/platform/data/tst_menuitem.qml107
-rw-r--r--tests/auto/platform/data/tst_menuitemgroup.qml380
16 files changed, 3723 insertions, 3 deletions
diff --git a/src/imports/platform/doc/images/qtlabsplatform-menu.png b/src/imports/platform/doc/images/qtlabsplatform-menu.png
new file mode 100644
index 00000000..120d263b
--- /dev/null
+++ b/src/imports/platform/doc/images/qtlabsplatform-menu.png
Binary files differ
diff --git a/src/imports/platform/doc/images/qtlabsplatform-menubar.png b/src/imports/platform/doc/images/qtlabsplatform-menubar.png
new file mode 100644
index 00000000..685d03b3
--- /dev/null
+++ b/src/imports/platform/doc/images/qtlabsplatform-menubar.png
Binary files differ
diff --git a/src/imports/platform/platform.pri b/src/imports/platform/platform.pri
index 453ed447..a0ba0450 100644
--- a/src/imports/platform/platform.pri
+++ b/src/imports/platform/platform.pri
@@ -1,5 +1,13 @@
HEADERS += \
- $$PWD/qquickplatformiconloader_p.h
+ $$PWD/qquickplatformiconloader_p.h \
+ $$PWD/qquickplatformmenu_p.h \
+ $$PWD/qquickplatformmenubar_p.h \
+ $$PWD/qquickplatformmenuitem_p.h \
+ $$PWD/qquickplatformmenuitemgroup_p.h
SOURCES += \
- $$PWD/qquickplatformiconloader.cpp
+ $$PWD/qquickplatformiconloader.cpp \
+ $$PWD/qquickplatformmenu.cpp \
+ $$PWD/qquickplatformmenubar.cpp \
+ $$PWD/qquickplatformmenuitem.cpp \
+ $$PWD/qquickplatformmenuitemgroup.cpp
diff --git a/src/imports/platform/qquickplatformmenu.cpp b/src/imports/platform/qquickplatformmenu.cpp
new file mode 100644
index 00000000..7849adf0
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenu.cpp
@@ -0,0 +1,792 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform 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 "qquickplatformmenu_p.h"
+#include "qquickplatformmenubar_p.h"
+#include "qquickplatformmenuitem_p.h"
+#include "qquickplatformiconloader_p.h"
+
+#include <QtGui/qicon.h>
+#include <QtGui/qcursor.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qv4scopedvalue_p.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <QtQuick/qquickrendercontrol.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Menu
+ \inherits QtObject
+ \instantiates QQuickPlatformMenu
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menu.
+
+ The Menu type provides a QML API for native platform menu popups.
+
+ \image qtlabsplatform-menu.png
+
+ Menu can be used in a \l MenuBar, or as a stand-alone context menu.
+ The following example shows how to open a context menu on right mouse
+ click:
+
+ \code
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: zoomMenu.open()
+ }
+
+ Menu {
+ id: zoomMenu
+
+ MenuItem {
+ text: qsTr("Zoom In")
+ shortcut: StandardKey.ZoomIn
+ onTriggered: zoomIn()
+ }
+
+ MenuItem {
+ text: qsTr("Zoom Out")
+ shortcut: StandardKey.ZoomOut
+ onTriggered: zoomOut()
+ }
+ }
+ \endcode
+
+ Menu is currently available on the following platforms:
+
+ \list
+ \li OS X
+ \li iOS
+ \li Android
+ \li Linux (only available as a stand-alone context menu when running with the GTK platform theme)
+ \endlist
+
+ \labs
+
+ \sa MenuItem, MenuBar
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::Menu::aboutToShow()
+
+ This signal is emitted when the menu is about to be shown to the user.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::Menu::aboutToHide()
+
+ This signal is emitted when the menu is about to be hidden from the user.
+*/
+
+QQuickPlatformMenu::QQuickPlatformMenu(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_enabled(true),
+ m_visible(true),
+ m_minimumWidth(-1),
+ m_type(QPlatformMenu::DefaultMenu),
+ m_menuBar(nullptr),
+ m_parentMenu(nullptr),
+ m_menuItem(nullptr),
+ m_iconLoader(nullptr),
+ m_handle(nullptr)
+{
+}
+
+QQuickPlatformMenu::~QQuickPlatformMenu()
+{
+ if (m_menuBar)
+ m_menuBar->removeMenu(this);
+ if (m_parentMenu)
+ m_parentMenu->removeMenu(this);
+ for (QQuickPlatformMenuItem *item : m_items) {
+ if (QQuickPlatformMenu *subMenu = item->subMenu())
+ subMenu->setParentMenu(nullptr);
+ item->setMenu(nullptr);
+ }
+ delete m_iconLoader;
+ m_iconLoader = nullptr;
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+QPlatformMenu *QQuickPlatformMenu::handle() const
+{
+ return m_handle;
+}
+
+QPlatformMenu * QQuickPlatformMenu::create()
+{
+ if (!m_handle) {
+ if (m_menuBar && m_menuBar->handle())
+ m_handle = m_menuBar->handle()->createMenu();
+ else if (m_parentMenu && m_parentMenu->handle())
+ m_handle = m_parentMenu->handle()->createSubMenu();
+
+ // TODO: implement ^
+ // - QCocoaMenuBar::createMenu()
+ // - QCocoaMenu::createSubMenu()
+ if (!m_handle)
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
+
+ if (m_handle) {
+ connect(m_handle, &QPlatformMenu::aboutToShow, this, &QQuickPlatformMenu::aboutToShow);
+ connect(m_handle, &QPlatformMenu::aboutToHide, this, &QQuickPlatformMenu::aboutToHide);
+
+ for (QQuickPlatformMenuItem *item : m_items)
+ m_handle->insertMenuItem(item->create(), nullptr);
+
+ if (m_menuItem) {
+ if (QPlatformMenuItem *handle = m_menuItem->create())
+ handle->setMenu(m_handle);
+ }
+ }
+ }
+ return m_handle;
+}
+
+void QQuickPlatformMenu::destroy()
+{
+ if (!m_handle)
+ return;
+
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+void QQuickPlatformMenu::sync()
+{
+ if (!m_complete || !create())
+ return;
+
+ m_handle->setText(m_title);
+ m_handle->setEnabled(m_enabled);
+ m_handle->setVisible(m_visible);
+ m_handle->setMinimumWidth(m_minimumWidth);
+ m_handle->setMenuType(m_type);
+ m_handle->setFont(m_font);
+
+ if (m_menuBar && m_menuBar->handle())
+ m_menuBar->handle()->syncMenu(m_handle);
+
+ for (QQuickPlatformMenuItem *item : m_items)
+ item->sync();
+}
+
+/*!
+ \default
+ \qmlproperty list<Object> Qt.labs.platform::Menu::data
+
+ This default property holds the list of all objects declared as children of
+ the menu. The data property includes objects that are not \l MenuItem instances,
+ such as \l Timer and \l QtObject.
+
+ \sa items
+*/
+QQmlListProperty<QObject> QQuickPlatformMenu::data()
+{
+ return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear);
+}
+
+/*!
+ \qmlproperty list<MenuItem> Qt.labs.platform::Menu::items
+
+ This property holds the list of items in the menu.
+*/
+QQmlListProperty<QQuickPlatformMenuItem> QQuickPlatformMenu::items()
+{
+ return QQmlListProperty<QQuickPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
+}
+
+/*!
+ \readonly
+ \qmlproperty MenuBar Qt.labs.platform::Menu::menuBar
+
+ This property holds the menubar that the menu belongs to, or \c null if the
+ menu is not in a menubar.
+*/
+QQuickPlatformMenuBar *QQuickPlatformMenu::menuBar() const
+{
+ return m_menuBar;
+}
+
+void QQuickPlatformMenu::setMenuBar(QQuickPlatformMenuBar *menuBar)
+{
+ if (m_menuBar == menuBar)
+ return;
+
+ m_menuBar = menuBar;
+ destroy();
+ emit menuBarChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::Menu::parentMenu
+
+ This property holds the parent menu that the menu belongs to, or \c null if the
+ menu is not a sub-menu.
+*/
+QQuickPlatformMenu *QQuickPlatformMenu::parentMenu() const
+{
+ return m_parentMenu;
+}
+
+void QQuickPlatformMenu::setParentMenu(QQuickPlatformMenu *menu)
+{
+ if (m_parentMenu == menu)
+ return;
+
+ m_parentMenu = menu;
+ destroy();
+ emit parentMenuChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty MenuItem Qt.labs.platform::Menu::menuItem
+
+ This property holds the item that presents the menu (in a parent menu).
+*/
+QQuickPlatformMenuItem *QQuickPlatformMenu::menuItem() const
+{
+ if (!m_menuItem) {
+ QQuickPlatformMenu *that = const_cast<QQuickPlatformMenu *>(this);
+ m_menuItem = new QQuickPlatformMenuItem(that);
+ m_menuItem->setSubMenu(that);
+ m_menuItem->setText(m_title);
+ m_menuItem->setIconName(iconName());
+ m_menuItem->setIconSource(iconSource());
+ m_menuItem->setVisible(m_visible);
+ m_menuItem->setEnabled(m_enabled);
+ m_menuItem->componentComplete();
+ }
+ return m_menuItem;
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Menu::enabled
+
+ This property holds whether the menu is enabled. The default value is \c true.
+*/
+bool QQuickPlatformMenu::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickPlatformMenu::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setEnabled(enabled);
+
+ m_enabled = enabled;
+ sync();
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Menu::visible
+
+ This property holds whether the menu is visible. The default value is \c true.
+*/
+bool QQuickPlatformMenu::isVisible() const
+{
+ return m_visible;
+}
+
+void QQuickPlatformMenu::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setVisible(visible);
+
+ m_visible = visible;
+ sync();
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty int Qt.labs.platform::Menu::minimumWidth
+
+ This property holds the minimum width of the menu. The default value is \c -1 (no minimum width).
+*/
+int QQuickPlatformMenu::minimumWidth() const
+{
+ return m_minimumWidth;
+}
+
+void QQuickPlatformMenu::setMinimumWidth(int width)
+{
+ if (m_minimumWidth == width)
+ return;
+
+ m_minimumWidth = width;
+ sync();
+ emit minimumWidthChanged();
+}
+
+/*!
+ \qmlproperty enumeration Qt.labs.platform::Menu::type
+
+ This property holds the type of the menu.
+
+ Available values:
+ \value Menu.DefaultMenu A normal menu (default).
+ \value Menu.EditMenu An edit menu with pre-populated cut, copy and paste items.
+*/
+QPlatformMenu::MenuType QQuickPlatformMenu::type() const
+{
+ return m_type;
+}
+
+void QQuickPlatformMenu::setType(QPlatformMenu::MenuType type)
+{
+ if (m_type == type)
+ return;
+
+ m_type = type;
+ sync();
+ emit typeChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::Menu::title
+
+ This property holds the menu's title.
+*/
+QString QQuickPlatformMenu::title() const
+{
+ return m_title;
+}
+
+void QQuickPlatformMenu::setTitle(const QString &title)
+{
+ if (m_title == title)
+ return;
+
+ m_title = title;
+ sync();
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::Menu::iconSource
+
+ This property holds the url of the menu's icon.
+
+ \sa iconName
+*/
+QUrl QQuickPlatformMenu::iconSource() const
+{
+ if (!m_iconLoader)
+ return QUrl();
+
+ return m_iconLoader->iconSource();
+}
+
+void QQuickPlatformMenu::setIconSource(const QUrl& source)
+{
+ if (source == iconSource())
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setIconSource(source);
+
+ iconLoader()->setIconSource(source);
+ emit iconSourceChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::Menu::iconName
+
+ This property holds the theme name of the menu's icon.
+
+ \sa iconSource, QIcon::fromTheme()
+*/
+QString QQuickPlatformMenu::iconName() const
+{
+ if (!m_iconLoader)
+ return QString();
+
+ return m_iconLoader->iconName();
+}
+
+void QQuickPlatformMenu::setIconName(const QString& name)
+{
+ if (name == iconName())
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setIconName(name);
+
+ iconLoader()->setIconName(name);
+ emit iconNameChanged();
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::Menu::font
+
+ This property holds the menu's font.
+
+ \sa text
+*/
+QFont QQuickPlatformMenu::font() const
+{
+ return m_font;
+}
+
+void QQuickPlatformMenu::setFont(const QFont& font)
+{
+ if (m_font == font)
+ return;
+
+ m_font = font;
+ sync();
+ emit fontChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::addItem(MenuItem item)
+
+ Adds an \a item to the end of the menu.
+*/
+void QQuickPlatformMenu::addItem(QQuickPlatformMenuItem *item)
+{
+ insertItem(m_items.count(), item);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::insertItem(int index, MenuItem item)
+
+ Inserts an \a item at the specified \a index in the menu.
+*/
+void QQuickPlatformMenu::insertItem(int index, QQuickPlatformMenuItem *item)
+{
+ if (!item || m_items.contains(item))
+ return;
+
+ m_items.insert(index, item);
+ m_data.append(item);
+ item->setMenu(this);
+ if (m_handle && item->create()) {
+ QQuickPlatformMenuItem *before = m_items.value(index + 1);
+ m_handle->insertMenuItem(item->handle(), before ? before->create() : nullptr);
+ }
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::removeItem(MenuItem item)
+
+ Removes an \a item from the menu.
+*/
+void QQuickPlatformMenu::removeItem(QQuickPlatformMenuItem *item)
+{
+ if (!item || !m_items.removeOne(item))
+ return;
+
+ m_data.removeOne(item);
+ if (m_handle)
+ m_handle->removeMenuItem(item->handle());
+ item->setMenu(nullptr);
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::addMenu(Menu submenu)
+
+ Adds a \a submenu to the end of the menu.
+*/
+void QQuickPlatformMenu::addMenu(QQuickPlatformMenu *menu)
+{
+ insertMenu(m_items.count(), menu);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::insertMenu(int index, Menu submenu)
+
+ Inserts a \a submenu at the specified \a index in the menu.
+*/
+void QQuickPlatformMenu::insertMenu(int index, QQuickPlatformMenu *menu)
+{
+ if (!menu)
+ return;
+
+ menu->setParentMenu(this);
+ insertItem(index, menu->menuItem());
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::removeMenu(Menu submenu)
+
+ Removes a \a submenu from the menu.
+*/
+void QQuickPlatformMenu::removeMenu(QQuickPlatformMenu *menu)
+{
+ if (!menu)
+ return;
+
+ menu->setParentMenu(nullptr);
+ removeItem(menu->menuItem());
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::clear()
+
+ Removes all items from the menu.
+*/
+void QQuickPlatformMenu::clear()
+{
+ if (m_items.isEmpty())
+ return;
+
+ for (QQuickPlatformMenuItem *item : m_items) {
+ m_data.removeOne(item);
+ if (m_handle)
+ m_handle->removeMenuItem(item->handle());
+ item->setMenu(nullptr);
+ delete item;
+ }
+
+ m_items.clear();
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::open(MenuItem item)
+
+ Opens the menu at the current mouse position, optionally aligned to a menu \a item.
+*/
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::open(Item target, MenuItem item)
+
+ Opens the menu at the specified \a target item, optionally aligned to a menu \a item.
+*/
+void QQuickPlatformMenu::open(QQmlV4Function *args)
+{
+ if (!m_handle)
+ return;
+
+ if (args->length() > 2) {
+ args->v4engine()->throwTypeError();
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ QQuickItem *targetItem = nullptr;
+ if (args->length() > 0) {
+ QV4::ScopedValue value(scope, (*args)[0]);
+ QV4::Scoped<QV4::QObjectWrapper> object(scope, value->as<QV4::QObjectWrapper>());
+ if (object)
+ targetItem = qobject_cast<QQuickItem *>(object->object());
+ }
+
+ QQuickPlatformMenuItem *menuItem = nullptr;
+ if (args->length() > 1) {
+ QV4::ScopedValue value(scope, (*args)[1]);
+ QV4::Scoped<QV4::QObjectWrapper> object(scope, value->as<QV4::QObjectWrapper>());
+ if (object)
+ menuItem = qobject_cast<QQuickPlatformMenuItem *>(object->object());
+ }
+
+ QPoint offset;
+ QWindow *window = findWindow(targetItem, &offset);
+
+ QRect targetRect;
+ if (targetItem) {
+ QRectF sceneBounds = targetItem->mapRectToScene(targetItem->boundingRect());
+ targetRect = sceneBounds.toAlignedRect().translated(offset);
+ } else {
+#ifndef QT_NO_CURSOR
+ QPoint pos = QCursor::pos();
+ if (window)
+ pos = window->mapFromGlobal(pos);
+ targetRect.moveTo(pos);
+#endif
+ }
+
+ m_handle->showPopup(window, targetRect, menuItem ? menuItem->handle() : nullptr);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::close()
+
+ Closes the menu.
+*/
+void QQuickPlatformMenu::close()
+{
+ if (m_handle)
+ m_handle->dismiss();
+}
+
+void QQuickPlatformMenu::classBegin()
+{
+}
+
+void QQuickPlatformMenu::componentComplete()
+{
+ m_complete = true;
+ if (m_handle && m_iconLoader)
+ m_iconLoader->setEnabled(true);
+ sync();
+}
+
+QQuickPlatformIconLoader *QQuickPlatformMenu::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickPlatformMenu *that = const_cast<QQuickPlatformMenu *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickPlatformIconLoader(slot, that);
+ m_iconLoader->setEnabled(m_complete);
+ }
+ return m_iconLoader;
+}
+
+static QWindow *effectiveWindow(QWindow *window, QPoint *offset)
+{
+ QQuickWindow *quickWindow = qobject_cast<QQuickWindow *>(window);
+ if (quickWindow) {
+ QWindow *renderWindow = QQuickRenderControl::renderWindowFor(quickWindow, offset);
+ if (renderWindow)
+ return renderWindow;
+ }
+ return window;
+}
+
+QWindow *QQuickPlatformMenu::findWindow(QQuickItem *target, QPoint *offset) const
+{
+ if (target)
+ return effectiveWindow(target->window(), offset);
+
+ if (m_menuBar && m_menuBar->window())
+ return effectiveWindow(m_menuBar->window(), offset);
+
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return effectiveWindow(window, offset);
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return effectiveWindow(item->window(), offset);
+
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+void QQuickPlatformMenu::data_append(QQmlListProperty<QObject> *property, QObject *object)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ if (QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem *>(object))
+ menu->addItem(item);
+ else if (QQuickPlatformMenu *subMenu = qobject_cast<QQuickPlatformMenu *>(object))
+ menu->addMenu(subMenu);
+ else
+ menu->m_data.append(object);
+}
+
+int QQuickPlatformMenu::data_count(QQmlListProperty<QObject> *property)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ return menu->m_data.count();
+}
+
+QObject *QQuickPlatformMenu::data_at(QQmlListProperty<QObject> *property, int index)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ return menu->m_data.value(index);
+}
+
+void QQuickPlatformMenu::data_clear(QQmlListProperty<QObject> *property)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ menu->m_data.clear();
+}
+
+void QQuickPlatformMenu::items_append(QQmlListProperty<QQuickPlatformMenuItem> *property, QQuickPlatformMenuItem *item)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ menu->addItem(item);
+}
+
+int QQuickPlatformMenu::items_count(QQmlListProperty<QQuickPlatformMenuItem> *property)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ return menu->m_items.count();
+}
+
+QQuickPlatformMenuItem *QQuickPlatformMenu::items_at(QQmlListProperty<QQuickPlatformMenuItem> *property, int index)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ return menu->m_items.value(index);
+}
+
+void QQuickPlatformMenu::items_clear(QQmlListProperty<QQuickPlatformMenuItem> *property)
+{
+ QQuickPlatformMenu *menu = static_cast<QQuickPlatformMenu *>(property->object);
+ menu->clear();
+}
+
+void QQuickPlatformMenu::updateIcon()
+{
+ if (!m_handle || !m_iconLoader)
+ return;
+
+ m_handle->setIcon(m_iconLoader->icon());
+ sync();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/platform/qquickplatformmenu_p.h b/src/imports/platform/qquickplatformmenu_p.h
new file mode 100644
index 00000000..2846c628
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenu_p.h
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform 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 QQUICKPLATFORMMENU_P_H
+#define QQUICKPLATFORMMENU_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 <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIcon;
+class QWindow;
+class QQuickItem;
+class QPlatformMenu;
+class QQmlV4Function;
+class QQuickPlatformMenuBar;
+class QQuickPlatformMenuItem;
+class QQuickPlatformIconLoader;
+
+class QQuickPlatformMenu : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickPlatformMenuItem> items READ items NOTIFY itemsChanged FINAL)
+ Q_PROPERTY(QQuickPlatformMenuBar *menuBar READ menuBar NOTIFY menuBarChanged FINAL)
+ Q_PROPERTY(QQuickPlatformMenu *parentMenu READ parentMenu NOTIFY parentMenuChanged FINAL)
+ Q_PROPERTY(QQuickPlatformMenuItem *menuItem READ menuItem CONSTANT FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(int minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged FINAL)
+ Q_PROPERTY(QPlatformMenu::MenuType type READ type WRITE setType NOTIFY typeChanged FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged FINAL)
+ Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)
+ Q_ENUMS(QPlatformMenu::MenuType)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ explicit QQuickPlatformMenu(QObject *parent = nullptr);
+ ~QQuickPlatformMenu();
+
+ QPlatformMenu *handle() const;
+ QPlatformMenu *create();
+ void destroy();
+ void sync();
+
+ QQmlListProperty<QObject> data();
+ QQmlListProperty<QQuickPlatformMenuItem> items();
+
+ QQuickPlatformMenuBar *menuBar() const;
+ void setMenuBar(QQuickPlatformMenuBar *menuBar);
+
+ QQuickPlatformMenu *parentMenu() const;
+ void setParentMenu(QQuickPlatformMenu *menu);
+
+ QQuickPlatformMenuItem *menuItem() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ int minimumWidth() const;
+ void setMinimumWidth(int width);
+
+ QPlatformMenu::MenuType type() const;
+ void setType(QPlatformMenu::MenuType type);
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ QUrl iconSource() const;
+ void setIconSource(const QUrl &source);
+
+ QString iconName() const;
+ void setIconName(const QString &name);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ Q_INVOKABLE void addItem(QQuickPlatformMenuItem *item);
+ Q_INVOKABLE void insertItem(int index, QQuickPlatformMenuItem *item);
+ Q_INVOKABLE void removeItem(QQuickPlatformMenuItem *item);
+
+ Q_INVOKABLE void addMenu(QQuickPlatformMenu *menu);
+ Q_INVOKABLE void insertMenu(int index, QQuickPlatformMenu *menu);
+ Q_INVOKABLE void removeMenu(QQuickPlatformMenu *menu);
+
+ Q_INVOKABLE void clear();
+
+public Q_SLOTS:
+ void open(QQmlV4Function *args);
+ void close();
+
+Q_SIGNALS:
+ void aboutToShow();
+ void aboutToHide();
+
+ void itemsChanged();
+ void menuBarChanged();
+ void parentMenuChanged();
+ void titleChanged();
+ void iconSourceChanged();
+ void iconNameChanged();
+ void enabledChanged();
+ void visibleChanged();
+ void minimumWidthChanged();
+ void fontChanged();
+ void typeChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ QQuickPlatformIconLoader *iconLoader() const;
+
+ QWindow *findWindow(QQuickItem *target, QPoint *offset) const;
+
+ static void data_append(QQmlListProperty<QObject> *property, QObject *object);
+ static int data_count(QQmlListProperty<QObject> *property);
+ static QObject *data_at(QQmlListProperty<QObject> *property, int index);
+ static void data_clear(QQmlListProperty<QObject> *property);
+
+ static void items_append(QQmlListProperty<QQuickPlatformMenuItem> *property, QQuickPlatformMenuItem *item);
+ static int items_count(QQmlListProperty<QQuickPlatformMenuItem> *property);
+ static QQuickPlatformMenuItem *items_at(QQmlListProperty<QQuickPlatformMenuItem> *property, int index);
+ static void items_clear(QQmlListProperty<QQuickPlatformMenuItem> *property);
+
+private Q_SLOTS:
+ void updateIcon();
+
+private:
+ bool m_complete;
+ bool m_enabled;
+ bool m_visible;
+ int m_minimumWidth;
+ QPlatformMenu::MenuType m_type;
+ QString m_title;
+ QFont m_font;
+ QList<QObject *> m_data;
+ QList<QQuickPlatformMenuItem *> m_items;
+ QQuickPlatformMenuBar *m_menuBar;
+ QQuickPlatformMenu *m_parentMenu;
+ mutable QQuickPlatformMenuItem *m_menuItem;
+ mutable QQuickPlatformIconLoader *m_iconLoader;
+ QPlatformMenu *m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPlatformMenu)
+
+#endif // QQUICKPLATFORMMENU_P_H
diff --git a/src/imports/platform/qquickplatformmenubar.cpp b/src/imports/platform/qquickplatformmenubar.cpp
new file mode 100644
index 00000000..249bb014
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenubar.cpp
@@ -0,0 +1,326 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform 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 "qquickplatformmenubar_p.h"
+#include "qquickplatformmenu_p.h"
+
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuBar
+ \inherits QtObject
+ \instantiates QQuickPlatformMenuBar
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menubar.
+
+ The MenuBar type provides a QML API for native platform menubars.
+
+ \image qtlabsplatform-menubar.png
+
+ A menubar consists of a list of drop-down menus.
+
+ \code
+ MenuBar {
+ id: menuBar
+
+ Menu {
+ id: fileMenu
+ title: qsTr("File")
+ // ...
+ }
+
+ Menu {
+ id: editMenu
+ title: qsTr("&Edit")
+ // ...
+ }
+
+ Menu {
+ id: viewMenu
+ title: qsTr("&View")
+ // ...
+ }
+
+ Menu {
+ id: helpMenu
+ title: qsTr("&Help")
+ // ...
+ }
+ }
+ \endcode
+
+ MenuBar is currently available on the following platforms:
+
+ \list
+ \li OS X
+ \li Android
+ \li Linux (only available on desktop environments that provide a global D-Bus menu bar)
+ \endlist
+
+ \labs
+
+ \sa Menu
+*/
+
+QQuickPlatformMenuBar::QQuickPlatformMenuBar(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_window(nullptr),
+ m_handle(nullptr)
+{
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
+}
+
+QQuickPlatformMenuBar::~QQuickPlatformMenuBar()
+{
+ for (QQuickPlatformMenu *menu : m_menus)
+ menu->setMenuBar(nullptr);
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+QPlatformMenuBar *QQuickPlatformMenuBar::handle() const
+{
+ return m_handle;
+}
+
+/*!
+ \default
+ \qmlproperty list<Object> Qt.labs.platform::MenuBar::data
+
+ This default property holds the list of all objects declared as children of
+ the menubar. The data property includes objects that are not \l Menu instances,
+ such as \l Timer and \l QtObject.
+
+ \sa menus
+*/
+QQmlListProperty<QObject> QQuickPlatformMenuBar::data()
+{
+ return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear);
+}
+
+/*!
+ \qmlproperty list<Menu> Qt.labs.platform::MenuBar::menus
+
+ This property holds the list of menus in the menubar.
+*/
+QQmlListProperty<QQuickPlatformMenu> QQuickPlatformMenuBar::menus()
+{
+ return QQmlListProperty<QQuickPlatformMenu>(this, nullptr, menus_append, menus_count, menus_at, menus_clear);
+}
+
+/*!
+ \qmlproperty Window Qt.labs.platform::MenuBar::window
+
+ This property holds the menubar's window.
+
+ Unless explicitly set, the window is automatically resolved by iterating
+ the QML parent objects until a \l Window or an \l Item that has a window
+ is found.
+*/
+QWindow *QQuickPlatformMenuBar::window() const
+{
+ return m_window;
+}
+
+void QQuickPlatformMenuBar::setWindow(QWindow *window)
+{
+ if (m_window == window)
+ return;
+
+ if (m_handle)
+ m_handle->handleReparent(window);
+
+ m_window = window;
+ emit windowChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::addMenu(Menu menu)
+
+ Adds a \a menu to end of the menubar.
+*/
+void QQuickPlatformMenuBar::addMenu(QQuickPlatformMenu *menu)
+{
+ insertMenu(m_menus.count(), menu);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::insertMenu(int index, Menu menu)
+
+ Inserts a \a menu at the specified \a index in the menubar.
+*/
+void QQuickPlatformMenuBar::insertMenu(int index, QQuickPlatformMenu *menu)
+{
+ if (!menu || m_menus.contains(menu))
+ return;
+
+ QQuickPlatformMenu *before = m_menus.value(index);
+ m_menus.insert(index, menu);
+ m_data.append(menu);
+ menu->setMenuBar(this);
+ if (m_handle)
+ m_handle->insertMenu(menu->create(), before ? before->handle() : nullptr);
+ emit menusChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::removeMenu(Menu menu)
+
+ Removes a \a menu from the menubar.
+*/
+void QQuickPlatformMenuBar::removeMenu(QQuickPlatformMenu *menu)
+{
+ if (!menu || !m_menus.removeOne(menu))
+ return;
+
+ m_data.removeOne(menu);
+ if (m_handle)
+ m_handle->removeMenu(menu->handle());
+ menu->setMenuBar(nullptr);
+ emit menusChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::clear()
+
+ Removes all menus from the menubar.
+*/
+void QQuickPlatformMenuBar::clear()
+{
+ if (m_menus.isEmpty())
+ return;
+
+ for (QQuickPlatformMenu *menu : m_menus) {
+ m_data.removeOne(menu);
+ if (m_handle)
+ m_handle->removeMenu(menu->handle());
+ menu->setMenuBar(nullptr);
+ delete menu;
+ }
+
+ m_menus.clear();
+ emit menusChanged();
+}
+
+void QQuickPlatformMenuBar::classBegin()
+{
+}
+
+void QQuickPlatformMenuBar::componentComplete()
+{
+ m_complete = true;
+ for (QQuickPlatformMenu *menu : m_menus)
+ menu->sync();
+ if (!m_window)
+ setWindow(findWindow());
+}
+
+QWindow *QQuickPlatformMenuBar::findWindow() const
+{
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return window;
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return item->window();
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+void QQuickPlatformMenuBar::data_append(QQmlListProperty<QObject> *property, QObject *object)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ QQuickPlatformMenu *menu = qobject_cast<QQuickPlatformMenu *>(object);
+ if (menu)
+ menuBar->addMenu(menu);
+ else
+ menuBar->m_data.append(object);
+}
+
+int QQuickPlatformMenuBar::data_count(QQmlListProperty<QObject> *property)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ return menuBar->m_data.count();
+}
+
+QObject *QQuickPlatformMenuBar::data_at(QQmlListProperty<QObject> *property, int index)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ return menuBar->m_data.value(index);
+}
+
+void QQuickPlatformMenuBar::data_clear(QQmlListProperty<QObject> *property)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ menuBar->m_data.clear();
+}
+
+void QQuickPlatformMenuBar::menus_append(QQmlListProperty<QQuickPlatformMenu> *property, QQuickPlatformMenu *menu)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ menuBar->addMenu(menu);
+}
+
+int QQuickPlatformMenuBar::menus_count(QQmlListProperty<QQuickPlatformMenu> *property)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ return menuBar->m_menus.count();
+}
+
+QQuickPlatformMenu *QQuickPlatformMenuBar::menus_at(QQmlListProperty<QQuickPlatformMenu> *property, int index)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ return menuBar->m_menus.value(index);
+}
+
+void QQuickPlatformMenuBar::menus_clear(QQmlListProperty<QQuickPlatformMenu> *property)
+{
+ QQuickPlatformMenuBar *menuBar = static_cast<QQuickPlatformMenuBar *>(property->object);
+ menuBar->clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/platform/qquickplatformmenubar_p.h b/src/imports/platform/qquickplatformmenubar_p.h
new file mode 100644
index 00000000..059acfe6
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenubar_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform 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 QQUICKPLATFORMMENUBAR_P_H
+#define QQUICKPLATFORMMENUBAR_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 <QtCore/qobject.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QPlatformMenuBar;
+class QQuickPlatformMenu;
+
+class QQuickPlatformMenuBar : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickPlatformMenu> menus READ menus NOTIFY menusChanged FINAL)
+ Q_PROPERTY(QWindow *window READ window WRITE setWindow NOTIFY windowChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ explicit QQuickPlatformMenuBar(QObject *parent = nullptr);
+ ~QQuickPlatformMenuBar();
+
+ QPlatformMenuBar *handle() const;
+
+ QQmlListProperty<QObject> data();
+ QQmlListProperty<QQuickPlatformMenu> menus();
+
+ QWindow *window() const;
+ void setWindow(QWindow *window);
+
+ Q_INVOKABLE void addMenu(QQuickPlatformMenu *menu);
+ Q_INVOKABLE void insertMenu(int index, QQuickPlatformMenu *menu);
+ Q_INVOKABLE void removeMenu(QQuickPlatformMenu *menu);
+ Q_INVOKABLE void clear();
+
+Q_SIGNALS:
+ void menusChanged();
+ void windowChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ QWindow *findWindow() const;
+
+ static void data_append(QQmlListProperty<QObject> *property, QObject *object);
+ static int data_count(QQmlListProperty<QObject> *property);
+ static QObject *data_at(QQmlListProperty<QObject> *property, int index);
+ static void data_clear(QQmlListProperty<QObject> *property);
+
+ static void menus_append(QQmlListProperty<QQuickPlatformMenu> *property, QQuickPlatformMenu *menu);
+ static int menus_count(QQmlListProperty<QQuickPlatformMenu> *property);
+ static QQuickPlatformMenu *menus_at(QQmlListProperty<QQuickPlatformMenu> *property, int index);
+ static void menus_clear(QQmlListProperty<QQuickPlatformMenu> *property);
+
+private:
+ bool m_complete;
+ QWindow *m_window;
+ QList<QObject *> m_data;
+ QList<QQuickPlatformMenu *> m_menus;
+ QPlatformMenuBar *m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPlatformMenuBar)
+
+#endif // QQUICKPLATFORMMENUBAR_P_H
diff --git a/src/imports/platform/qquickplatformmenuitem.cpp b/src/imports/platform/qquickplatformmenuitem.cpp
new file mode 100644
index 00000000..115714f8
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenuitem.cpp
@@ -0,0 +1,605 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform 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 "qquickplatformmenuitem_p.h"
+#include "qquickplatformmenu_p.h"
+#include "qquickplatformmenuitemgroup_p.h"
+#include "qquickplatformiconloader_p.h"
+
+#include <QtGui/qicon.h>
+#include <QtGui/qkeysequence.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuItem
+ \inherits QtObject
+ \instantiates QQuickPlatformMenuItem
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menu item.
+
+ The MenuItem type provides a QML API for native platform menu items.
+
+ \image qtlabsplatform-menu.png
+
+ A menu item consists of an \l {iconSource}{icon}, \l text, and \l shortcut.
+
+ \code
+ Menu {
+ id: zoomMenu
+
+ MenuItem {
+ text: qsTr("Zoom In")
+ shortcut: StandardKey.ZoomIn
+ onTriggered: zoomIn()
+ }
+
+ MenuItem {
+ text: qsTr("Zoom Out")
+ shortcut: StandardKey.ZoomOut
+ onTriggered: zoomOut()
+ }
+ }
+ \endcode
+
+ \labs
+
+ \sa Menu, MenuItemGroup
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItem::triggered()
+
+ This signal is emitted when the menu item is triggered by the user.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItem::hovered()
+
+ This signal is emitted when the menu item is hovered by the user.
+*/
+
+QQuickPlatformMenuItem::QQuickPlatformMenuItem(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_enabled(true),
+ m_visible(true),
+ m_separator(false),
+ m_checkable(false),
+ m_checked(false),
+ m_role(QPlatformMenuItem::TextHeuristicRole),
+ m_menu(nullptr),
+ m_subMenu(nullptr),
+ m_group(nullptr),
+ m_iconLoader(nullptr),
+ m_handle(nullptr)
+{
+}
+
+QQuickPlatformMenuItem::~QQuickPlatformMenuItem()
+{
+ if (m_menu)
+ m_menu->removeItem(this);
+ if (m_group)
+ m_group->removeItem(this);
+ delete m_iconLoader;
+ m_iconLoader = nullptr;
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+QPlatformMenuItem *QQuickPlatformMenuItem::handle() const
+{
+ return m_handle;
+}
+
+QPlatformMenuItem *QQuickPlatformMenuItem::create()
+{
+ if (!m_handle && m_menu && m_menu->handle()) {
+ m_handle = m_menu->handle()->createMenuItem();
+
+ // TODO: implement QCocoaMenu::createMenuItem()
+ if (!m_handle)
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem();
+
+ if (m_handle) {
+ connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::triggered);
+ connect(m_handle, &QPlatformMenuItem::hovered, this, &QQuickPlatformMenuItem::hovered);
+ if (m_checkable)
+ connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::toggle);
+ }
+ }
+ return m_handle;
+}
+
+void QQuickPlatformMenuItem::sync()
+{
+ if (!m_complete || !create())
+ return;
+
+ m_handle->setEnabled(isEnabled());
+ m_handle->setVisible(isVisible());
+ m_handle->setIsSeparator(m_separator);
+ m_handle->setCheckable(m_checkable);
+ m_handle->setChecked(m_checked);
+ m_handle->setRole(m_role);
+ m_handle->setText(m_text);
+ m_handle->setFont(m_font);
+ m_handle->setHasExclusiveGroup(m_group && m_group->isExclusive());
+ if (m_subMenu && m_subMenu->handle())
+ m_handle->setMenu(m_subMenu->handle());
+
+ QKeySequence sequence;
+ if (m_shortcut.type() == QVariant::Int)
+ sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt()));
+ else
+ sequence = QKeySequence::fromString(m_shortcut.toString());
+ m_handle->setShortcut(sequence.toString());
+
+ if (m_menu && m_menu->handle())
+ m_menu->handle()->syncMenuItem(m_handle);
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::MenuItem::menu
+
+ This property holds the menu that the item belongs to, or \c null if the
+ item is not in a menu.
+*/
+QQuickPlatformMenu *QQuickPlatformMenuItem::menu() const
+{
+ return m_menu;
+}
+
+void QQuickPlatformMenuItem::setMenu(QQuickPlatformMenu *menu)
+{
+ if (m_menu == menu)
+ return;
+
+ m_menu = menu;
+ emit menuChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::MenuItem::subMenu
+
+ This property holds the sub-menu that the item contains, or \c null if
+ the item is not a sub-menu item.
+*/
+QQuickPlatformMenu *QQuickPlatformMenuItem::subMenu() const
+{
+ return m_subMenu;
+}
+
+void QQuickPlatformMenuItem::setSubMenu(QQuickPlatformMenu *menu)
+{
+ if (m_subMenu == menu)
+ return;
+
+ m_subMenu = menu;
+ sync();
+ emit subMenuChanged();
+}
+
+/*!
+ \qmlproperty MenuItemGroup Qt.labs.platform::MenuItem::group
+
+ This property holds the group that the item belongs to, or \c null if the
+ item is not in a group.
+*/
+QQuickPlatformMenuItemGroup *QQuickPlatformMenuItem::group() const
+{
+ return m_group;
+}
+
+void QQuickPlatformMenuItem::setGroup(QQuickPlatformMenuItemGroup *group)
+{
+ if (m_group == group)
+ return;
+
+ bool wasEnabled = isEnabled();
+ bool wasVisible = isVisible();
+
+ if (group)
+ group->addItem(this);
+
+ m_group = group;
+ sync();
+ emit groupChanged();
+
+ if (isEnabled() != wasEnabled)
+ emit enabledChanged();
+ if (isVisible() != wasVisible)
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::enabled
+
+ This property holds whether the item is enabled. The default value is \c true.
+
+ Disabled items cannot be triggered by the user. They do not disappear from menus,
+ but they are displayed in a way which indicates that they are unavailable. For
+ example, they might be displayed using only shades of gray.
+
+ When an item is disabled, it is not possible to trigger it through its \l shortcut.
+*/
+bool QQuickPlatformMenuItem::isEnabled() const
+{
+ return m_enabled && (!m_group || m_group->isEnabled());
+}
+
+void QQuickPlatformMenuItem::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ bool wasEnabled = isEnabled();
+ m_enabled = enabled;
+ sync();
+ if (isEnabled() != wasEnabled)
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::visible
+
+ This property holds whether the item is visible. The default value is \c true.
+*/
+bool QQuickPlatformMenuItem::isVisible() const
+{
+ return m_visible && (!m_group || m_group->isVisible());
+}
+
+void QQuickPlatformMenuItem::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ bool wasVisible = isVisible();
+ m_visible = visible;
+ sync();
+ if (isVisible() != wasVisible)
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::separator
+
+ This property holds whether the item is a separator line. The default value
+ is \c false.
+*/
+bool QQuickPlatformMenuItem::isSeparator() const
+{
+ return m_separator;
+}
+
+void QQuickPlatformMenuItem::setSeparator(bool separator)
+{
+ if (m_separator == separator)
+ return;
+
+ m_separator = separator;
+ sync();
+ emit separatorChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::checkable
+
+ This property holds whether the item is checkable.
+
+ A checkable menu item has an on/off state. For example, in a word processor,
+ a "Bold" menu item may be either on or off. A menu item that is not checkable
+ is a command item that is simply executed, e.g. file save.
+
+ The default value is \c false.
+
+ \sa checked, MenuItemGroup
+*/
+bool QQuickPlatformMenuItem::isCheckable() const
+{
+ return m_checkable;
+}
+
+void QQuickPlatformMenuItem::setCheckable(bool checkable)
+{
+ if (m_checkable == checkable)
+ return;
+
+ if (m_handle) {
+ if (checkable)
+ connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::toggle);
+ else
+ disconnect(m_handle, &QPlatformMenuItem::activated, this, &QQuickPlatformMenuItem::toggle);
+ }
+
+ m_checkable = checkable;
+ sync();
+ emit checkableChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::checked
+
+ This property holds whether the item is checked (on) or unchecked (off).
+ The default value is \c false.
+
+ \sa checkable, MenuItemGroup
+*/
+bool QQuickPlatformMenuItem::isChecked() const
+{
+ return m_checked;
+}
+
+void QQuickPlatformMenuItem::setChecked(bool checked)
+{
+ if (m_checked == checked)
+ return;
+
+ if (checked && !m_checkable)
+ setCheckable(true);
+
+ m_checked = checked;
+ sync();
+ emit checkedChanged();
+}
+
+/*!
+ \qmlproperty enumeration Qt.labs.platform::MenuItem::role
+
+ This property holds the role of the item. The role determines whether
+ the item should be placed into the application menu on OS X.
+
+ Available values:
+ \value MenuItem.NoRole The item should not be put into the application menu
+ \value MenuItem.TextHeuristicRole The item should be put in the application menu based on the action's text (default)
+ \value MenuItem.ApplicationSpecificRole The item should be put in the application menu with an application-specific role
+ \value MenuItem.AboutQtRole The item handles the "About Qt" menu item.
+ \value MenuItem.AboutRole The item should be placed where the "About" menu item is in the application menu. The text of
+ the menu item will be set to "About <application name>". The application name is fetched from the
+ \c{Info.plist} file in the application's bundle (See \l{Qt for OS X - Deployment}).
+ \value MenuItem.PreferencesRole The item should be placed where the "Preferences..." menu item is in the application menu.
+ \value MenuItem.QuitRole The item should be placed where the Quit menu item is in the application menu.
+
+ Specifying the role only has effect on items that are in the immediate
+ menus of a menubar, not in the submenus of those menus. For example, if
+ you have a "File" menu in your menubar and the "File" menu has a submenu,
+ specifying a role for the items in that submenu has no effect. They will
+ never be moved to the application menu.
+*/
+QPlatformMenuItem::MenuRole QQuickPlatformMenuItem::role() const
+{
+ return m_role;
+}
+
+void QQuickPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
+{
+ if (m_role == role)
+ return;
+
+ m_role = role;
+ sync();
+ emit roleChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::MenuItem::text
+
+ This property holds the menu item's text.
+*/
+QString QQuickPlatformMenuItem::text() const
+{
+ return m_text;
+}
+
+void QQuickPlatformMenuItem::setText(const QString &text)
+{
+ if (m_text == text)
+ return;
+
+ m_text = text;
+ sync();
+ emit textChanged();
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::MenuItem::iconSource
+
+ This property holds the url of the menu item's icon.
+
+ \code
+ MenuItem {
+ iconName: "edit-undo"
+ iconSource: "qrc:/images/undo.png"
+ }
+ \endcode
+
+ \sa iconName
+*/
+QUrl QQuickPlatformMenuItem::iconSource() const
+{
+ if (!m_iconLoader)
+ return QUrl();
+
+ return m_iconLoader->iconSource();
+}
+
+void QQuickPlatformMenuItem::setIconSource(const QUrl& source)
+{
+ if (source == iconSource())
+ return;
+
+ iconLoader()->setIconSource(source);
+ emit iconSourceChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::MenuItem::iconName
+
+ This property holds the theme name of the menu item's icon.
+
+ \code
+ MenuItem {
+ iconName: "edit-undo"
+ iconSource: "qrc:/images/undo.png"
+ }
+ \endcode
+
+ \sa iconSource, QIcon::fromTheme()
+*/
+QString QQuickPlatformMenuItem::iconName() const
+{
+ if (!m_iconLoader)
+ return QString();
+
+ return m_iconLoader->iconName();
+}
+
+void QQuickPlatformMenuItem::setIconName(const QString& name)
+{
+ if (name == iconName())
+ return;
+
+ iconLoader()->setIconName(name);
+ emit iconNameChanged();
+}
+
+/*!
+ \qmlproperty keysequence Qt.labs.platform::MenuItem::shortcut
+
+ This property holds the menu item's shortcut.
+
+ The shortcut key sequence can be set to one of the
+ \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or it can be
+ specified by a string containing a sequence of up to four key presses
+ that are needed to \l{triggered}{trigger} the shortcut.
+
+ The default value is an empty key sequence.
+
+ \code
+ MenuItem {
+ shortcut: "Ctrl+E,Ctrl+W"
+ onTriggered: edit.wrapMode = TextEdit.Wrap
+ }
+ \endcode
+*/
+QVariant QQuickPlatformMenuItem::shortcut() const
+{
+ return m_shortcut;
+}
+
+void QQuickPlatformMenuItem::setShortcut(const QVariant& shortcut)
+{
+ if (m_shortcut == shortcut)
+ return;
+
+ m_shortcut = shortcut;
+ sync();
+ emit shortcutChanged();
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::MenuItem::font
+
+ This property holds the menu item's font.
+
+ \sa text
+*/
+QFont QQuickPlatformMenuItem::font() const
+{
+ return m_font;
+}
+
+void QQuickPlatformMenuItem::setFont(const QFont& font)
+{
+ if (m_font == font)
+ return;
+
+ m_font = font;
+ sync();
+ emit fontChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItem::toggle()
+
+ Toggles the \l checked state to its opposite state.
+*/
+void QQuickPlatformMenuItem::toggle()
+{
+ if (m_checkable)
+ setChecked(!m_checked);
+}
+
+void QQuickPlatformMenuItem::classBegin()
+{
+}
+
+void QQuickPlatformMenuItem::componentComplete()
+{
+ if (m_handle && m_iconLoader)
+ m_iconLoader->setEnabled(true);
+ m_complete = true;
+ sync();
+}
+
+QQuickPlatformIconLoader *QQuickPlatformMenuItem::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickPlatformMenuItem *that = const_cast<QQuickPlatformMenuItem *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickPlatformIconLoader(slot, that);
+ m_iconLoader->setEnabled(m_complete);
+ }
+ return m_iconLoader;
+}
+
+void QQuickPlatformMenuItem::updateIcon()
+{
+ if (!m_handle || !m_iconLoader)
+ return;
+
+ m_handle->setIcon(m_iconLoader->icon());
+ sync();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/platform/qquickplatformmenuitem_p.h b/src/imports/platform/qquickplatformmenuitem_p.h
new file mode 100644
index 00000000..48a5603e
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenuitem_p.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform 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 QQUICKPLATFORMMENUITEM_P_H
+#define QQUICKPLATFORMMENUITEM_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 <QtCore/qobject.h>
+#include <QtCore/qurl.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformMenuItem;
+class QQuickPlatformMenu;
+class QQuickPlatformIconLoader;
+class QQuickPlatformMenuItemGroup;
+
+class QQuickPlatformMenuItem : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQuickPlatformMenu *menu READ menu NOTIFY menuChanged FINAL)
+ Q_PROPERTY(QQuickPlatformMenu *subMenu READ subMenu NOTIFY subMenuChanged FINAL)
+ Q_PROPERTY(QQuickPlatformMenuItemGroup *group READ group WRITE setGroup NOTIFY groupChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(bool separator READ isSeparator WRITE setSeparator NOTIFY separatorChanged FINAL)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL)
+ Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL)
+ Q_PROPERTY(QPlatformMenuItem::MenuRole role READ role WRITE setRole NOTIFY roleChanged FINAL)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(QUrl iconSource READ iconSource WRITE setIconSource NOTIFY iconSourceChanged FINAL)
+ Q_PROPERTY(QString iconName READ iconName WRITE setIconName NOTIFY iconNameChanged FINAL)
+ Q_PROPERTY(QVariant shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)
+ Q_ENUMS(QPlatformMenuItem::MenuRole)
+
+public:
+ explicit QQuickPlatformMenuItem(QObject *parent = nullptr);
+ ~QQuickPlatformMenuItem();
+
+ QPlatformMenuItem *handle() const;
+ QPlatformMenuItem *create();
+ void sync();
+
+ QQuickPlatformMenu *menu() const;
+ void setMenu(QQuickPlatformMenu* menu);
+
+ QQuickPlatformMenu *subMenu() const;
+ void setSubMenu(QQuickPlatformMenu *menu);
+
+ QQuickPlatformMenuItemGroup *group() const;
+ void setGroup(QQuickPlatformMenuItemGroup *group);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ bool isSeparator() const;
+ void setSeparator(bool separator);
+
+ bool isCheckable() const;
+ void setCheckable(bool checkable);
+
+ bool isChecked() const;
+ void setChecked(bool checked);
+
+ QPlatformMenuItem::MenuRole role() const;
+ void setRole(QPlatformMenuItem::MenuRole role);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ QUrl iconSource() const;
+ void setIconSource(const QUrl &source);
+
+ QString iconName() const;
+ void setIconName(const QString &name);
+
+ QVariant shortcut() const;
+ void setShortcut(const QVariant& shortcut);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+public Q_SLOTS:
+ void toggle();
+
+Q_SIGNALS:
+ void triggered();
+ void hovered();
+
+ void menuChanged();
+ void subMenuChanged();
+ void groupChanged();
+ void enabledChanged();
+ void visibleChanged();
+ void separatorChanged();
+ void checkableChanged();
+ void checkedChanged();
+ void roleChanged();
+ void textChanged();
+ void iconSourceChanged();
+ void iconNameChanged();
+ void shortcutChanged();
+ void fontChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ QQuickPlatformIconLoader *iconLoader() const;
+
+private Q_SLOTS:
+ void updateIcon();
+
+private:
+ bool m_complete;
+ bool m_enabled;
+ bool m_visible;
+ bool m_separator;
+ bool m_checkable;
+ bool m_checked;
+ QPlatformMenuItem::MenuRole m_role;
+ QString m_text;
+ QVariant m_shortcut;
+ QFont m_font;
+ QQuickPlatformMenu *m_menu;
+ QQuickPlatformMenu *m_subMenu;
+ QQuickPlatformMenuItemGroup *m_group;
+ mutable QQuickPlatformIconLoader *m_iconLoader;
+ QPlatformMenuItem *m_handle;
+
+ friend class QQuickPlatformMenu;
+ friend class QQuickPlatformMenuItemGroup;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPlatformMenuItem)
+
+#endif // QQUICKPLATFORMMENUITEM_P_H
diff --git a/src/imports/platform/qquickplatformmenuitemgroup.cpp b/src/imports/platform/qquickplatformmenuitemgroup.cpp
new file mode 100644
index 00000000..1f4dda3c
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenuitemgroup.cpp
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates 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 "qquickplatformmenuitemgroup_p.h"
+#include "qquickplatformmenuitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuItemGroup
+ \inherits QtObject
+ \instantiates QQuickPlatformMenuItemGroup
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A group for managing native menu items.
+
+ The MenuItemGroup groups native menu items together.
+
+ MenuItemGroup is exclusive by default. In an exclusive menu item
+ group, only one item can be checked at any time; checking another
+ item automatically unchecks the previously checked one. MenuItemGroup
+ can be configured as non-exclusive, which is particularly useful for
+ showing, hiding, enabling and disabling items together as a group.
+
+ The most straight-forward way to use MenuItemGroup is to assign
+ a list of items.
+
+ \code
+ Menu {
+ id: verticalMenu
+ title: qsTr("Vertical")
+
+ MenuItemGroup {
+ id: verticalGroup
+ items: verticalMenu.items
+ }
+
+ MenuItem { text: qsTr("Top"); checkable: true }
+ MenuItem { text: qsTr("Center"); checked: true }
+ MenuItem { text: qsTr("Bottom"); checkable: true }
+ }
+ \endcode
+
+ The same menu may sometimes contain items that should not be included
+ in the same exclusive group. Such cases are best handled using the
+ \l {MenuItem::group}{group} property.
+
+ \code
+ Menu {
+ id: horizontalMenu
+ title: qsTr("Horizontal")
+
+ MenuItemGroup {
+ id: horizontalGroup
+ }
+
+ MenuItem {
+ checked: true
+ text: qsTr("Left")
+ group: horizontalGroup
+ }
+ MenuItem {
+ checkable: true
+ text: qsTr("Center")
+ group: horizontalGroup
+ }
+ MenuItem {
+ text: qsTr("Right")
+ checkable: true
+ group: horizontalGroup
+ }
+
+ MenuItem { separator: true }
+ MenuItem { text: qsTr("Justify"); checkable: true }
+ MenuItem { text: qsTr("Absolute"); checkable: true }
+ }
+ \endcode
+
+ More advanced use cases can be handled using the addItem() and
+ removeItem() methods.
+
+ \labs
+
+ \sa MenuItem
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItemGroup::triggered(MenuItem item)
+
+ This signal is emitted when an \a item in the group is triggered by the user.
+
+ \sa MenuItem::triggered()
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItemGroup::hovered(MenuItem item)
+
+ This signal is emitted when an \a item in the group is hovered by the user.
+
+ \sa MenuItem::hovered()
+*/
+
+QQuickPlatformMenuItemGroup::QQuickPlatformMenuItemGroup(QObject *parent)
+ : QObject(parent), m_enabled(true), m_visible(true), m_exclusive(true), m_checkedItem(nullptr)
+{
+}
+
+QQuickPlatformMenuItemGroup::~QQuickPlatformMenuItemGroup()
+{
+ clear();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItemGroup::enabled
+
+ This property holds whether the group is enabled. The default value is \c true.
+
+ The enabled state of the group affects the enabled state of each item in the group,
+ except that explicitly disabled items are not enabled even if the group is enabled.
+*/
+bool QQuickPlatformMenuItemGroup::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickPlatformMenuItemGroup::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ m_enabled = enabled;
+ emit enabledChanged();
+
+ for (QQuickPlatformMenuItem *item : m_items) {
+ if (item->m_enabled) {
+ item->sync();
+ emit item->enabledChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItemGroup::visible
+
+ This property holds whether the group is visible. The default value is \c true.
+
+ The visibility of the group affects the visibility of each item in the group,
+ except that explicitly hidden items are not visible even if the group is visible.
+*/
+bool QQuickPlatformMenuItemGroup::isVisible() const
+{
+ return m_visible;
+}
+
+void QQuickPlatformMenuItemGroup::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ m_visible = visible;
+ emit visibleChanged();
+
+ for (QQuickPlatformMenuItem *item : m_items) {
+ if (item->m_visible) {
+ item->sync();
+ emit item->visibleChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItemGroup::exclusive
+
+ This property holds whether the group is exclusive. The default value is \c true.
+
+ In an exclusive menu item group, only one item can be checked at any time;
+ checking another item automatically unchecks the previously checked one.
+*/
+bool QQuickPlatformMenuItemGroup::isExclusive() const
+{
+ return m_exclusive;
+}
+
+void QQuickPlatformMenuItemGroup::setExclusive(bool exclusive)
+{
+ if (m_exclusive == exclusive)
+ return;
+
+ m_exclusive = exclusive;
+ emit exclusiveChanged();
+
+ for (QQuickPlatformMenuItem *item : m_items)
+ item->sync();
+}
+
+/*!
+ \qmlproperty MenuItem Qt.labs.platform::MenuItemGroup::checkedItem
+
+ This property holds the currently checked item in the group, or \c null if no item is checked.
+*/
+QQuickPlatformMenuItem *QQuickPlatformMenuItemGroup::checkedItem() const
+{
+ return m_checkedItem;
+}
+
+void QQuickPlatformMenuItemGroup::setCheckedItem(QQuickPlatformMenuItem *item)
+{
+ if (m_checkedItem == item)
+ return;
+
+ if (m_checkedItem)
+ m_checkedItem->setChecked(false);
+
+ m_checkedItem = item;
+ emit checkedItemChanged();
+
+ if (item)
+ item->setChecked(true);
+}
+
+/*!
+ \qmlproperty list<MenuItem> Qt.labs.platform::MenuItemGroup::items
+
+ This property holds the list of items in the group.
+*/
+QQmlListProperty<QQuickPlatformMenuItem> QQuickPlatformMenuItemGroup::items()
+{
+ return QQmlListProperty<QQuickPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItemGroup::addItem(MenuItem item)
+
+ Adds an \a item to the group.
+*/
+void QQuickPlatformMenuItemGroup::addItem(QQuickPlatformMenuItem *item)
+{
+ if (!item || m_items.contains(item))
+ return;
+
+ m_items.append(item);
+ item->setGroup(this);
+
+ connect(item, &QQuickPlatformMenuItem::checkedChanged, this, &QQuickPlatformMenuItemGroup::updateCurrent);
+ connect(item, &QQuickPlatformMenuItem::triggered, this, &QQuickPlatformMenuItemGroup::activateItem);
+ connect(item, &QQuickPlatformMenuItem::hovered, this, &QQuickPlatformMenuItemGroup::hoverItem);
+
+ if (m_exclusive && item->isChecked())
+ setCheckedItem(item);
+
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItemGroup::removeItem(MenuItem item)
+
+ Removes an \a item from the group.
+*/
+void QQuickPlatformMenuItemGroup::removeItem(QQuickPlatformMenuItem *item)
+{
+ if (!item || !m_items.contains(item))
+ return;
+
+ m_items.removeOne(item);
+ item->setGroup(nullptr);
+
+ disconnect(item, &QQuickPlatformMenuItem::checkedChanged, this, &QQuickPlatformMenuItemGroup::updateCurrent);
+ disconnect(item, &QQuickPlatformMenuItem::triggered, this, &QQuickPlatformMenuItemGroup::activateItem);
+ disconnect(item, &QQuickPlatformMenuItem::hovered, this, &QQuickPlatformMenuItemGroup::hoverItem);
+
+ if (m_checkedItem == item)
+ setCheckedItem(nullptr);
+
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItemGroup::clear()
+
+ Removes all items from the group.
+*/
+void QQuickPlatformMenuItemGroup::clear()
+{
+ if (m_items.isEmpty())
+ return;
+
+ for (QQuickPlatformMenuItem *item : m_items) {
+ item->setGroup(nullptr);
+ disconnect(item, &QQuickPlatformMenuItem::checkedChanged, this, &QQuickPlatformMenuItemGroup::updateCurrent);
+ disconnect(item, &QQuickPlatformMenuItem::triggered, this, &QQuickPlatformMenuItemGroup::activateItem);
+ disconnect(item, &QQuickPlatformMenuItem::hovered, this, &QQuickPlatformMenuItemGroup::hoverItem);
+ }
+
+ setCheckedItem(nullptr);
+
+ m_items.clear();
+ emit itemsChanged();
+}
+
+QQuickPlatformMenuItem *QQuickPlatformMenuItemGroup::findCurrent() const
+{
+ for (QQuickPlatformMenuItem *item : m_items) {
+ if (item->isChecked())
+ return item;
+ }
+ return nullptr;
+}
+
+void QQuickPlatformMenuItemGroup::updateCurrent()
+{
+ if (!m_exclusive)
+ return;
+
+ QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem*>(sender());
+ if (item && item->isChecked())
+ setCheckedItem(item);
+}
+
+void QQuickPlatformMenuItemGroup::activateItem()
+{
+ QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem*>(sender());
+ if (item)
+ emit triggered(item);
+}
+
+void QQuickPlatformMenuItemGroup::hoverItem()
+{
+ QQuickPlatformMenuItem *item = qobject_cast<QQuickPlatformMenuItem*>(sender());
+ if (item)
+ emit hovered(item);
+}
+
+void QQuickPlatformMenuItemGroup::items_append(QQmlListProperty<QQuickPlatformMenuItem> *prop, QQuickPlatformMenuItem *item)
+{
+ QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object);
+ group->addItem(item);
+}
+
+int QQuickPlatformMenuItemGroup::items_count(QQmlListProperty<QQuickPlatformMenuItem> *prop)
+{
+ QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object);
+ return group->m_items.count();
+}
+
+QQuickPlatformMenuItem *QQuickPlatformMenuItemGroup::items_at(QQmlListProperty<QQuickPlatformMenuItem> *prop, int index)
+{
+ QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object);
+ return group->m_items.value(index);
+}
+
+void QQuickPlatformMenuItemGroup::items_clear(QQmlListProperty<QQuickPlatformMenuItem> *prop)
+{
+ QQuickPlatformMenuItemGroup *group = static_cast<QQuickPlatformMenuItemGroup *>(prop->object);
+ group->clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/imports/platform/qquickplatformmenuitemgroup_p.h b/src/imports/platform/qquickplatformmenuitemgroup_p.h
new file mode 100644
index 00000000..f5797eff
--- /dev/null
+++ b/src/imports/platform/qquickplatformmenuitemgroup_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates 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 QQUICKPLATFORMMENUITEMGROUP_P_H
+#define QQUICKPLATFORMMENUITEMGROUP_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 <QtCore/qobject.h>
+#include <QtCore/qvector.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPlatformMenuItem;
+class QQuickPlatformMenuItemGroupPrivate;
+
+class QQuickPlatformMenuItemGroup : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(bool exclusive READ isExclusive WRITE setExclusive NOTIFY exclusiveChanged FINAL)
+ Q_PROPERTY(QQuickPlatformMenuItem *checkedItem READ checkedItem WRITE setCheckedItem NOTIFY checkedItemChanged FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickPlatformMenuItem> items READ items NOTIFY itemsChanged FINAL)
+
+public:
+ explicit QQuickPlatformMenuItemGroup(QObject *parent = nullptr);
+ ~QQuickPlatformMenuItemGroup();
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ bool isExclusive() const;
+ void setExclusive(bool exclusive);
+
+ QQuickPlatformMenuItem *checkedItem() const;
+ void setCheckedItem(QQuickPlatformMenuItem *item);
+
+ QQmlListProperty<QQuickPlatformMenuItem> items();
+
+ Q_INVOKABLE void addItem(QQuickPlatformMenuItem *item);
+ Q_INVOKABLE void removeItem(QQuickPlatformMenuItem *item);
+ Q_INVOKABLE void clear();
+
+Q_SIGNALS:
+ void triggered(QQuickPlatformMenuItem *item);
+ void hovered(QQuickPlatformMenuItem *item);
+
+ void enabledChanged();
+ void visibleChanged();
+ void exclusiveChanged();
+ void checkedItemChanged();
+ void itemsChanged();
+
+private:
+ QQuickPlatformMenuItem *findCurrent() const;
+ void updateCurrent();
+ void activateItem();
+ void hoverItem();
+
+ static void items_append(QQmlListProperty<QQuickPlatformMenuItem> *prop, QQuickPlatformMenuItem *obj);
+ static int items_count(QQmlListProperty<QQuickPlatformMenuItem> *prop);
+ static QQuickPlatformMenuItem *items_at(QQmlListProperty<QQuickPlatformMenuItem> *prop, int index);
+ static void items_clear(QQmlListProperty<QQuickPlatformMenuItem> *prop);
+
+ bool m_enabled;
+ bool m_visible;
+ bool m_exclusive;
+ QQuickPlatformMenuItem *m_checkedItem;
+ QVector<QQuickPlatformMenuItem*> m_items;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPlatformMenuItemGroup)
+
+#endif // QQUICKPLATFORMMENUITEMGROUP_P_H
diff --git a/src/imports/platform/qtlabsplatformplugin.cpp b/src/imports/platform/qtlabsplatformplugin.cpp
index c691e1cf..05199971 100644
--- a/src/imports/platform/qtlabsplatformplugin.cpp
+++ b/src/imports/platform/qtlabsplatformplugin.cpp
@@ -37,6 +37,11 @@
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
+#include "qquickplatformmenu_p.h"
+#include "qquickplatformmenubar_p.h"
+#include "qquickplatformmenuitem_p.h"
+#include "qquickplatformmenuitemgroup_p.h"
+
static inline void initResources()
{
#ifdef QT_STATIC
@@ -63,7 +68,10 @@ QtLabsPlatformPlugin::QtLabsPlatformPlugin(QObject *parent) : QQmlExtensionPlugi
void QtLabsPlatformPlugin::registerTypes(const char *uri)
{
- Q_UNUSED(uri)
+ qmlRegisterType<QQuickPlatformMenu>(uri, 1, 0, "Menu");
+ qmlRegisterType<QQuickPlatformMenuBar>(uri, 1, 0, "MenuBar");
+ qmlRegisterType<QQuickPlatformMenuItem>(uri, 1, 0, "MenuItem");
+ qmlRegisterType<QQuickPlatformMenuItemGroup>(uri, 1, 0, "MenuItemGroup");
}
QT_END_NAMESPACE
diff --git a/tests/auto/platform/data/tst_menu.qml b/tests/auto/platform/data/tst_menu.qml
new file mode 100644
index 00000000..cc846d99
--- /dev/null
+++ b/tests/auto/platform/data/tst_menu.qml
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.2
+import QtTest 1.0
+import Qt.labs.platform 1.0
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "Menu"
+
+ Component {
+ id: item
+ MenuItem { }
+ }
+
+ Component {
+ id: menu
+ Menu { }
+ }
+
+ SignalSpy {
+ id: itemsSpy
+ signalName: "itemsChanged"
+ }
+
+ function init() {
+ verify(!itemsSpy.target)
+ compare(itemsSpy.count, 0)
+ }
+
+ function cleanup() {
+ itemsSpy.target = null
+ itemsSpy.clear()
+ }
+
+ function test_addRemove() {
+ var control = menu.createObject(testCase)
+
+ itemsSpy.target = control
+ verify(itemsSpy.valid)
+
+ control.addItem(item.createObject(control, {text: "1"}))
+ compare(control.items.length, 1)
+ compare(control.items[0].text, "1")
+ compare(itemsSpy.count, 1)
+
+ control.addItem(item.createObject(control, {text: "2"}))
+ compare(control.items.length, 2)
+ compare(control.items[0].text, "1")
+ compare(control.items[1].text, "2")
+ compare(itemsSpy.count, 2)
+
+ control.insertItem(1, item.createObject(control, {text: "3"}))
+ compare(control.items.length, 3)
+ compare(control.items[0].text, "1")
+ compare(control.items[1].text, "3")
+ compare(control.items[2].text, "2")
+ compare(itemsSpy.count, 3)
+
+ control.insertItem(0, item.createObject(control, {text: "4"}))
+ compare(control.items.length, 4)
+ compare(control.items[0].text, "4")
+ compare(control.items[1].text, "1")
+ compare(control.items[2].text, "3")
+ compare(control.items[3].text, "2")
+ compare(itemsSpy.count, 4)
+
+ control.insertItem(control.items.length, item.createObject(control, {text: "5"}))
+ compare(control.items.length, 5)
+ compare(control.items[0].text, "4")
+ compare(control.items[1].text, "1")
+ compare(control.items[2].text, "3")
+ compare(control.items[3].text, "2")
+ compare(control.items[4].text, "5")
+ compare(itemsSpy.count, 5)
+
+ control.removeItem(control.items[4])
+ compare(control.items.length, 4)
+ compare(control.items[0].text, "4")
+ compare(control.items[1].text, "1")
+ compare(control.items[2].text, "3")
+ compare(control.items[3].text, "2")
+ compare(itemsSpy.count, 6)
+
+ control.removeItem(control.items[0])
+ compare(control.items.length, 3)
+ compare(control.items[0].text, "1")
+ compare(control.items[1].text, "3")
+ compare(control.items[2].text, "2")
+ compare(itemsSpy.count, 7)
+
+ control.removeItem(control.items[1])
+ compare(control.items.length, 2)
+ compare(control.items[0].text, "1")
+ compare(control.items[1].text, "2")
+ compare(itemsSpy.count, 8)
+
+ control.removeItem(control.items[1])
+ compare(control.items.length, 1)
+ compare(control.items[0].text, "1")
+ compare(itemsSpy.count, 9)
+
+ control.removeItem(control.items[0])
+ compare(control.items.length, 0)
+ compare(itemsSpy.count, 10)
+
+ control.destroy()
+ }
+
+ Component {
+ id: contentMenu
+ Menu {
+ QtObject { objectName: "object" }
+ MenuItem { objectName: "item1" }
+ Timer { objectName: "timer" }
+ MenuItem { objectName: "item2" }
+ Component { MenuItem { } }
+ }
+ }
+
+ function test_content() {
+ var control = contentMenu.createObject(testCase)
+
+ function compareObjectNames(content, names) {
+ if (content.length !== names.length)
+ return false
+ for (var i = 0; i < names.length; ++i) {
+ if (content[i].objectName !== names[i])
+ return false
+ }
+ return true
+ }
+
+ itemsSpy.target = control
+ verify(itemsSpy.valid)
+
+ verify(compareObjectNames(control.data, ["object", "item1", "timer", "item2", ""]))
+ verify(compareObjectNames(control.items, ["item1", "item2"]))
+
+ control.addItem(item.createObject(control, {objectName: "item3"}))
+ verify(compareObjectNames(control.data, ["object", "item1", "timer", "item2", "", "item3"]))
+ verify(compareObjectNames(control.items, ["item1", "item2", "item3"]))
+ compare(itemsSpy.count, 1)
+
+ control.insertItem(0, item.createObject(control, {objectName: "item4"}))
+ verify(compareObjectNames(control.data, ["object", "item1", "timer", "item2", "", "item3", "item4"]))
+ verify(compareObjectNames(control.items, ["item4", "item1", "item2", "item3"]))
+ compare(itemsSpy.count, 2)
+
+ control.removeItem(control.items[1])
+ verify(compareObjectNames(control.data, ["object", "timer", "item2", "", "item3", "item4"]))
+ verify(compareObjectNames(control.items, ["item4", "item2", "item3"]))
+ compare(itemsSpy.count, 3)
+
+ control.destroy()
+ }
+
+ Component {
+ id: dynamicMenu
+ Menu {
+ id: dmenu
+ MenuItem { text: "static" }
+ Component.onCompleted: {
+ addItem(item.createObject(dmenu, {text: "added"}))
+ insertItem(0, item.createObject(dmenu, {text: "inserted"}))
+ }
+ }
+ }
+
+ function test_dynamic() {
+ var control = dynamicMenu.createObject(testCase)
+
+ // insertItem(), addItem(), and static MenuItem {}
+ compare(control.items.length, 3)
+ compare(control.items[0].text, "inserted")
+
+ var dying = item.createObject(control, {text: "dying"})
+ control.addItem(dying)
+ compare(control.items.length, 4)
+ compare(control.items[3].text, "dying")
+ dying.destroy()
+ wait(0)
+ compare(control.items.length, 3)
+
+ control.destroy()
+ }
+
+ function test_type() {
+ // Q_ENUMS(QPlatformMenu::MenuType)
+ compare(Menu.DefaultMenu, 0)
+ compare(Menu.EditMenu, 1)
+ }
+}
diff --git a/tests/auto/platform/data/tst_menubar.qml b/tests/auto/platform/data/tst_menubar.qml
new file mode 100644
index 00000000..6c29f164
--- /dev/null
+++ b/tests/auto/platform/data/tst_menubar.qml
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.2
+import QtTest 1.0
+import Qt.labs.platform 1.0
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "MenuBar"
+
+ Component {
+ id: menu
+ Menu { }
+ }
+
+ Component {
+ id: menuBar
+ MenuBar { }
+ }
+
+ SignalSpy {
+ id: menusSpy
+ signalName: "menusChanged"
+ }
+
+ function init() {
+ verify(!menusSpy.target)
+ compare(menusSpy.count, 0)
+ }
+
+ function cleanup() {
+ menusSpy.target = null
+ menusSpy.clear()
+ }
+
+ function test_addRemove() {
+ var control = menuBar.createObject(testCase)
+
+ menusSpy.target = control
+ verify(menusSpy.valid)
+
+ control.addMenu(menu.createObject(control, {title: "1"}))
+ compare(control.menus.length, 1)
+ compare(control.menus[0].title, "1")
+ compare(menusSpy.count, 1)
+
+ control.addMenu(menu.createObject(control, {title: "2"}))
+ compare(control.menus.length, 2)
+ compare(control.menus[0].title, "1")
+ compare(control.menus[1].title, "2")
+ compare(menusSpy.count, 2)
+
+ control.insertMenu(1, menu.createObject(control, {title: "3"}))
+ compare(control.menus.length, 3)
+ compare(control.menus[0].title, "1")
+ compare(control.menus[1].title, "3")
+ compare(control.menus[2].title, "2")
+ compare(menusSpy.count, 3)
+
+ control.insertMenu(0, menu.createObject(control, {title: "4"}))
+ compare(control.menus.length, 4)
+ compare(control.menus[0].title, "4")
+ compare(control.menus[1].title, "1")
+ compare(control.menus[2].title, "3")
+ compare(control.menus[3].title, "2")
+ compare(menusSpy.count, 4)
+
+ control.insertMenu(control.menus.length, menu.createObject(control, {title: "5"}))
+ compare(control.menus.length, 5)
+ compare(control.menus[0].title, "4")
+ compare(control.menus[1].title, "1")
+ compare(control.menus[2].title, "3")
+ compare(control.menus[3].title, "2")
+ compare(control.menus[4].title, "5")
+ compare(menusSpy.count, 5)
+
+ control.removeMenu(control.menus[4])
+ compare(control.menus.length, 4)
+ compare(control.menus[0].title, "4")
+ compare(control.menus[1].title, "1")
+ compare(control.menus[2].title, "3")
+ compare(control.menus[3].title, "2")
+ compare(menusSpy.count, 6)
+
+ control.removeMenu(control.menus[0])
+ compare(control.menus.length, 3)
+ compare(control.menus[0].title, "1")
+ compare(control.menus[1].title, "3")
+ compare(control.menus[2].title, "2")
+ compare(menusSpy.count, 7)
+
+ control.removeMenu(control.menus[1])
+ compare(control.menus.length, 2)
+ compare(control.menus[0].title, "1")
+ compare(control.menus[1].title, "2")
+ compare(menusSpy.count, 8)
+
+ control.removeMenu(control.menus[1])
+ compare(control.menus.length, 1)
+ compare(control.menus[0].title, "1")
+ compare(menusSpy.count, 9)
+
+ control.removeMenu(control.menus[0])
+ compare(control.menus.length, 0)
+ compare(menusSpy.count, 10)
+
+ control.destroy()
+ }
+
+ Component {
+ id: contentBar
+ MenuBar {
+ QtObject { objectName: "object" }
+ Menu { objectName: "menu1" }
+ Timer { objectName: "timer" }
+ Menu { objectName: "menu2" }
+ Component { Menu { } }
+ }
+ }
+
+ function test_content() {
+ var control = contentBar.createObject(testCase)
+
+ function compareObjectNames(content, names) {
+ if (content.length !== names.length)
+ return false
+ for (var i = 0; i < names.length; ++i) {
+ if (content[i].objectName !== names[i])
+ return false
+ }
+ return true
+ }
+
+ menusSpy.target = control
+ verify(menusSpy.valid)
+
+ verify(compareObjectNames(control.data, ["object", "menu1", "timer", "menu2", ""]))
+ verify(compareObjectNames(control.menus, ["menu1", "menu2"]))
+
+ control.addMenu(menu.createObject(control, {objectName: "menu3"}))
+ verify(compareObjectNames(control.data, ["object", "menu1", "timer", "menu2", "", "menu3"]))
+ verify(compareObjectNames(control.menus, ["menu1", "menu2", "menu3"]))
+ compare(menusSpy.count, 1)
+
+ control.insertMenu(0, menu.createObject(control, {objectName: "menu4"}))
+ verify(compareObjectNames(control.data, ["object", "menu1", "timer", "menu2", "", "menu3", "menu4"]))
+ verify(compareObjectNames(control.menus, ["menu4", "menu1", "menu2", "menu3"]))
+ compare(menusSpy.count, 2)
+
+ control.removeMenu(control.menus[1])
+ verify(compareObjectNames(control.data, ["object", "timer", "menu2", "", "menu3", "menu4"]))
+ verify(compareObjectNames(control.menus, ["menu4", "menu2", "menu3"]))
+ compare(menusSpy.count, 3)
+
+ control.destroy()
+ }
+
+ Component {
+ id: dynamicBar
+ MenuBar {
+ id: dbar
+ Menu { title: "static" }
+ Component.onCompleted: {
+ addMenu(menu.createObject(dbar, {title: "added"}))
+ insertMenu(0, menu.createObject(dbar, {title: "inserted"}))
+ }
+ }
+ }
+
+ function test_dynamic() {
+ var control = dynamicBar.createObject(testCase)
+
+ // insertMenu(), addMenu(), and static Menu {}
+ compare(control.menus.length, 3)
+ compare(control.menus[0].title, "inserted")
+
+ var dying = menu.createObject(control, {title: "dying"})
+ control.addMenu(dying)
+ compare(control.menus.length, 4)
+ compare(control.menus[3].title, "dying")
+ dying.destroy()
+ wait(0)
+ compare(control.menus.length, 3)
+
+ control.destroy()
+ }
+}
diff --git a/tests/auto/platform/data/tst_menuitem.qml b/tests/auto/platform/data/tst_menuitem.qml
new file mode 100644
index 00000000..7c2dd8f5
--- /dev/null
+++ b/tests/auto/platform/data/tst_menuitem.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.2
+import QtTest 1.0
+import Qt.labs.platform 1.0
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "MenuItem"
+
+ Component {
+ id: menuItem
+ MenuItem { }
+ }
+
+ SignalSpy {
+ id: spy
+ }
+
+ function test_properties_data() {
+ return [
+ {tag: "enabled", signal: "enabledChanged", init: true, value: false},
+ {tag: "visible", signal: "visibleChanged", init: true, value: false},
+ {tag: "separator", signal: "separatorChanged", init: false, value: true},
+ {tag: "checkable", signal: "checkableChanged", init: false, value: true},
+ {tag: "checked", signal: "checkedChanged", init: false, value: true},
+ {tag: "role", signal: "roleChanged", init: MenuItem.TextHeuristicRole, value: MenuItem.AboutRole},
+ {tag: "text", signal: "textChanged", init: "", value: "text"},
+ {tag: "iconSource", signal: "iconSourceChanged", init: "", value: "qrc:/undo.png"},
+ {tag: "iconName", signal: "iconNameChanged", init: "", value: "edit-undo"},
+ {tag: "shortcut", signal: "shortcutChanged", init: undefined, value: StandardKey.Undo}
+ ]
+ }
+
+ function test_properties(data) {
+ var item = menuItem.createObject(testCase)
+ verify(item)
+
+ spy.target = item
+ spy.signalName = data.signal
+ verify(spy.valid)
+
+ compare(item[data.tag], data.init)
+ item[data.tag] = data.value
+ compare(spy.count, 1)
+ compare(item[data.tag], data.value)
+
+ item[data.tag] = data.value
+ compare(spy.count, 1)
+
+ spy.clear()
+ item.destroy()
+ }
+
+ function test_role() {
+ // Q_ENUMS(QPlatformMenuItem::MenuRole)
+ compare(MenuItem.NoRole, 0)
+ compare(MenuItem.TextHeuristicRole, 1)
+ compare(MenuItem.ApplicationSpecificRole, 2)
+ compare(MenuItem.AboutQtRole, 3)
+ compare(MenuItem.AboutRole, 4)
+ compare(MenuItem.PreferencesRole, 5)
+ compare(MenuItem.QuitRole, 6)
+ }
+}
diff --git a/tests/auto/platform/data/tst_menuitemgroup.qml b/tests/auto/platform/data/tst_menuitemgroup.qml
new file mode 100644
index 00000000..31fc18b1
--- /dev/null
+++ b/tests/auto/platform/data/tst_menuitemgroup.qml
@@ -0,0 +1,380 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.2
+import QtTest 1.0
+import Qt.labs.platform 1.0
+
+TestCase {
+ id: testCase
+ width: 200
+ height: 200
+ visible: true
+ when: windowShown
+ name: "MenuItemGroup"
+
+ Component {
+ id: menuItemGroup
+ MenuItemGroup { }
+ }
+
+ SignalSpy {
+ id: checkedItemSpy
+ signalName: "checkedItemChanged"
+ }
+
+ SignalSpy {
+ id: itemsSpy
+ signalName: "itemsChanged"
+ }
+
+ function init() {
+ verify(!checkedItemSpy.target)
+ compare(checkedItemSpy.count, 0)
+
+ verify(!itemsSpy.target)
+ compare(itemsSpy.count, 0)
+ }
+
+ function cleanup() {
+ checkedItemSpy.target = null
+ checkedItemSpy.clear()
+
+ itemsSpy.target = null
+ itemsSpy.clear()
+ }
+
+ function test_null() {
+ var group = menuItemGroup.createObject(testCase)
+ verify(group)
+
+ group.addItem(null)
+ group.removeItem(null)
+
+ group.destroy()
+ }
+
+ Component {
+ id: item
+ MenuItem { }
+ }
+
+ function test_exclusive() {
+ var group = menuItemGroup.createObject(testCase)
+ verify(group)
+
+ compare(group.exclusive, true)
+
+ checkedItemSpy.target = group
+ verify(checkedItemSpy.valid)
+ verify(!group.checkedItem)
+
+ var item1 = item.createObject(testCase, {checked: true})
+ var item2 = item.createObject(testCase, {checked: false})
+ var item3 = item.createObject(testCase, {checked: true})
+
+ // add checked
+ group.addItem(item1)
+ compare(group.checkedItem, item1)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 1)
+
+ // add non-checked
+ group.addItem(item2)
+ compare(group.checkedItem, item1)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 1)
+
+ // add checked
+ group.addItem(item3)
+ compare(group.checkedItem, item3)
+ compare(item1.checked, false)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 2)
+
+ // change checked
+ group.checkedItem = item2
+ compare(group.checkedItem, item2)
+ compare(item1.checked, false)
+ compare(item2.checked, true)
+ compare(item3.checked, false)
+ compare(checkedItemSpy.count, 3)
+
+ // check
+ item1.checked = true
+ compare(group.checkedItem, item1)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, false)
+ compare(checkedItemSpy.count, 4)
+
+ // remove non-checked
+ group.removeItem(item2)
+ compare(group.checkedItem, item1)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, false)
+ compare(checkedItemSpy.count, 4)
+
+ // remove checked
+ group.removeItem(item1)
+ compare(group.checkedItem, null)
+ compare(item1.checked, false)
+ compare(item2.checked, false)
+ compare(item3.checked, false)
+ compare(checkedItemSpy.count, 5)
+
+ group.destroy()
+ }
+
+ function test_nonExclusive() {
+ var group = menuItemGroup.createObject(testCase, {exclusive: false})
+ verify(group)
+
+ compare(group.exclusive, false)
+
+ checkedItemSpy.target = group
+ verify(checkedItemSpy.valid)
+ verify(!group.checkedItem)
+
+ var item1 = item.createObject(testCase, {checked: true})
+ var item2 = item.createObject(testCase, {checked: false})
+ var item3 = item.createObject(testCase, {checked: true})
+
+ // add checked
+ group.addItem(item1)
+ compare(group.checkedItem, null)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 0)
+
+ // add non-checked
+ group.addItem(item2)
+ compare(group.checkedItem, null)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 0)
+
+ // add checked
+ group.addItem(item3)
+ compare(group.checkedItem, null)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 0)
+
+ // change checked
+ group.checkedItem = item2
+ compare(group.checkedItem, item2)
+ compare(item1.checked, true)
+ compare(item2.checked, true)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 1)
+
+ // check
+ item1.checked = false
+ item1.checked = true
+ compare(group.checkedItem, item2)
+ compare(item1.checked, true)
+ compare(item2.checked, true)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 1)
+
+ // remove checked
+ group.removeItem(item2)
+ compare(group.checkedItem, null)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 2)
+
+ // remove non-checked
+ group.removeItem(item1)
+ compare(group.checkedItem, null)
+ compare(item1.checked, true)
+ compare(item2.checked, false)
+ compare(item3.checked, true)
+ compare(checkedItemSpy.count, 2)
+
+ group.destroy()
+ }
+
+ function test_items() {
+ var group = menuItemGroup.createObject(testCase)
+ verify(group)
+
+ itemsSpy.target = group
+ verify(itemsSpy.valid)
+
+ compare(group.items.length, 0)
+ compare(group.checkedItem, null)
+
+ var item1 = item.createObject(testCase, {checked: true})
+ var item2 = item.createObject(testCase, {checked: false})
+
+ group.items = [item1, item2]
+ compare(group.items.length, 2)
+ compare(group.items[0], item1)
+ compare(group.items[1], item2)
+ compare(group.checkedItem, item1)
+ compare(itemsSpy.count, 2)
+
+ var item3 = item.createObject(testCase, {checked: true})
+
+ group.addItem(item3)
+ compare(group.items.length, 3)
+ compare(group.items[0], item1)
+ compare(group.items[1], item2)
+ compare(group.items[2], item3)
+ compare(group.checkedItem, item3)
+ compare(itemsSpy.count, 3)
+
+ group.removeItem(item1)
+ compare(group.items.length, 2)
+ compare(group.items[0], item2)
+ compare(group.items[1], item3)
+ compare(group.checkedItem, item3)
+ compare(itemsSpy.count, 4)
+
+ group.items = []
+ compare(group.items.length, 0)
+ compare(group.checkedItem, null)
+ compare(itemsSpy.count, 5)
+
+ group.destroy()
+ }
+
+ function test_itemDestroyed() {
+ var group = menuItemGroup.createObject(testCase)
+ verify(group)
+
+ itemsSpy.target = group
+ verify(itemsSpy.valid)
+
+ var item1 = item.createObject(testCase, {checked: true})
+
+ group.addItem(item1)
+ compare(group.items.length, 1)
+ compare(group.items[0], item1)
+ compare(group.checkedItem, item1)
+ compare(itemsSpy.count, 1)
+
+ item1.destroy()
+ wait(0)
+ compare(group.items.length, 0)
+ compare(group.checkedItem, null)
+ compare(itemsSpy.count, 2)
+
+ group.destroy()
+ }
+
+ function test_visible() {
+ var group = menuItemGroup.createObject(testCase)
+ verify(group)
+
+ compare(group.visible, true)
+
+ for (var i = 0; i < 3; ++i) {
+ group.addItem(item.createObject(testCase))
+ compare(group.items[i].visible, true)
+ }
+
+ group.visible = false
+ compare(group.visible, false)
+
+ for (i = 0; i < 3; ++i)
+ compare(group.items[i].visible, false)
+
+ group.items[1].visible = true
+ compare(group.items[1].visible, false)
+
+ group.items[1].visible = false
+ compare(group.items[1].visible, false)
+
+ group.visible = true
+ compare(group.visible, true)
+
+ compare(group.items[0].visible, true)
+ compare(group.items[1].visible, false)
+ compare(group.items[2].visible, true)
+
+ group.destroy()
+ }
+
+ function test_enabled() {
+ var group = menuItemGroup.createObject(testCase)
+ verify(group)
+
+ compare(group.enabled, true)
+
+ for (var i = 0; i < 3; ++i) {
+ group.addItem(item.createObject(testCase))
+ compare(group.items[i].enabled, true)
+ }
+
+ group.enabled = false
+ compare(group.enabled, false)
+
+ for (i = 0; i < 3; ++i)
+ compare(group.items[i].enabled, false)
+
+ group.items[1].enabled = true
+ compare(group.items[1].enabled, false)
+
+ group.items[1].enabled = false
+ compare(group.items[1].enabled, false)
+
+ group.enabled = true
+ compare(group.enabled, true)
+
+ compare(group.items[0].enabled, true)
+ compare(group.items[1].enabled, false)
+ compare(group.items[2].enabled, true)
+
+ group.destroy()
+ }
+}