diff options
-rw-r--r-- | examples/gallery/main.qml | 4 | ||||
-rw-r--r-- | src/controls/ComboBox.qml | 66 | ||||
-rw-r--r-- | src/controls/ContextMenu.qml | 100 | ||||
-rw-r--r-- | src/controls/controls.pro | 1 | ||||
-rw-r--r-- | src/controls/plugin.cpp | 2 | ||||
-rw-r--r-- | src/controls/plugin.pri | 1 | ||||
-rw-r--r-- | src/controls/qmldir | 1 | ||||
-rw-r--r-- | src/controls/qtmenu.cpp | 249 | ||||
-rw-r--r-- | src/controls/qtmenu_p.h | 65 | ||||
-rw-r--r-- | src/controls/qtmenuitem.cpp | 31 | ||||
-rw-r--r-- | src/controls/qtmenuitem_p.h | 6 | ||||
-rw-r--r-- | src/controls/qtmenuitemcontainer_p.h | 98 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_combobox.qml | 8 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_menu.qml | 3 |
14 files changed, 420 insertions, 215 deletions
diff --git a/examples/gallery/main.qml b/examples/gallery/main.qml index 1db94223..38bb4d5b 100644 --- a/examples/gallery/main.qml +++ b/examples/gallery/main.qml @@ -60,8 +60,8 @@ ApplicationWindow { width: 580 height: 400 - minimumHeight: 400 - minimumWidth: 340 +// minimumHeight: 400 +// minimumWidth: 340 property string loremIpsum: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor "+ "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor "+ diff --git a/src/controls/ComboBox.qml b/src/controls/ComboBox.qml index d96c15cc..e7308f84 100644 --- a/src/controls/ComboBox.qml +++ b/src/controls/ComboBox.qml @@ -120,8 +120,6 @@ Control { onPressedChanged: if (pressed) popup.show() } - ExclusiveGroup { id: eg } - StyleItem { id: styleItem } Component.onCompleted: { @@ -134,11 +132,17 @@ Control { } } - ContextMenu { + Menu { id: popup style: __style.popupStyle + readonly property string selectedText: items[selectedIndex] ? items[selectedIndex].text : "" + property string textRole: "" + property var model + property int modelSize: 0 + property bool ready: false + // 'centerSelectedText' means that the menu will be positioned // so that the selected text' top left corner will be at x, y. property bool centerSelectedText: true @@ -148,9 +152,57 @@ Control { __minimumWidth: comboBox.width __visualItem: comboBox - function finalizeItem(item) { - item.checkable = true - item.exclusiveGroup = eg + property ExclusiveGroup eg: ExclusiveGroup { id: eg } + + onModelChanged: rebuildMenu() + onTextRoleChanged: rebuildMenu() + + Component.onCompleted: { ready = true; rebuildMenu() } + + function rebuildMenu() { + if (!ready) return; + clear() + if (!model) return; + + var isNumberModel = typeof(model) === "number" + modelSize = isNumberModel ? model : (model.count || model.length) + var effectiveTextRole = textRole + if (effectiveTextRole === "" + && model.count !== undefined + && model.get && model.get(0)) { + // No text role set, check whether model has a suitable role + // If 'text' is found, or there's only one role, pick that. + var listElement = model.get(0) + var roleName = "" + var roleCount = 0 + for (var role in listElement) { + if (role === "text") { + roleName = role + break + } else if (!roleName) { + roleName = role + } + ++roleCount + } + if (roleCount > 1 && roleName !== "text") { + console.warn("No suitable 'textRole' found for ComboBox.") + } else { + effectiveTextRole = roleName + } + } + for (var i = 0; i < modelSize; ++i) { + var textValue + if (isNumberModel) + textValue = i + "" + else if (effectiveTextRole !== "") + textValue = model.get(i)[effectiveTextRole] + else + textValue = model[i] + + var item = addItem(textValue) + item.checkable = true + item.exclusiveGroup = eg + } } function show() { @@ -168,5 +220,5 @@ Control { popup.show() } Keys.onUpPressed: { if (selectedIndex > 0) selectedIndex-- } - Keys.onDownPressed: { if (selectedIndex < model.count - 1) selectedIndex++ } + Keys.onDownPressed: { if (selectedIndex < popup.modelSize - 1) selectedIndex++ } } diff --git a/src/controls/ContextMenu.qml b/src/controls/ContextMenu.qml deleted file mode 100644 index ab359743..00000000 --- a/src/controls/ContextMenu.qml +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Quick Controls module 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 Digia Plc and its Subsidiary(-ies) 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.0 -import QtQuick.Controls 1.0 - -Menu { // Move to private - id: root - property string selectedText: items[selectedIndex] ? items[selectedIndex].text : "" - property string textRole - - onModelChanged: if (Component.status === Component.Ready && model !== undefined) rebuildMenu() - - Component.onCompleted: if (model !== undefined) rebuildMenu() - - function rebuildMenu() - { - clear(); - - var nativeModel = root.__hasNativeModel() - - if (model !== undefined) { - var modelCount = nativeModel ? root.__modelCount() : model.count; - for (var j = 0 ; j < modelCount; ++j) { - var textValue - if (nativeModel) { - textValue = root.__modelTextAt(j); - } else { - if (textRole !== "") - textValue = model.get(j)[textRole] - else if (model.count > 0 && root.model.get && root.model.get(0)) { - // ListModel with one role - var listElement = root.model.get(0) - var oneRole = true - var roleName = "" - var roleCount = 0 - for (var role in listElement) { - if (!roleName || role === "text") - roleName = role - ++roleCount - } - if (roleCount > 1 && roleName !== "text") { - oneRole = false - console.log("Warning: No textRole set for ComboBox.") - break - } - - if (oneRole) { - root.textRole = roleName - textValue = root.model.get(j)[textRole] - } - } - } - - var item = addItem(textValue) - if (root["finalizeItem"]) - finalizeItem(item) - } - } - - itemsChanged() - } -} diff --git a/src/controls/controls.pro b/src/controls/controls.pro index 8f527e1b..df9f120f 100644 --- a/src/controls/controls.pro +++ b/src/controls/controls.pro @@ -10,7 +10,6 @@ QML_FILES = \ Button.qml \ CheckBox.qml \ ComboBox.qml \ - ContextMenu.qml \ GroupBox.qml \ Label.qml \ MenuBar.qml \ diff --git a/src/controls/plugin.cpp b/src/controls/plugin.cpp index 20d2f394..4ec08475 100644 --- a/src/controls/plugin.cpp +++ b/src/controls/plugin.cpp @@ -44,6 +44,7 @@ #include "qtexclusivegroup_p.h" #include "qtmenu_p.h" #include "qtmenubar_p.h" +#include "qtmenuitemcontainer_p.h" #include "qpagestatus.h" #include <qimage.h> @@ -82,6 +83,7 @@ void StylePlugin::registerTypes(const char *uri) qmlRegisterType<QtMenu>(uri, 1, 0, "MenuPrivate"); qmlRegisterType<QtMenuBar>(uri, 1, 0, "MenuBarPrivate"); qmlRegisterType<QtMenuItem>(uri, 1, 0, "MenuItem"); + qmlRegisterType<QtMenuItemContainer>(uri, 1, 0, "MenuItemContainer"); qmlRegisterType<QtMenuSeparator>(uri, 1, 0, "MenuSeparator"); qmlRegisterUncreatableType<QtMenuBase>(uri, 1, 0, "MenuBase", QLatin1String("Do not create objects of type MenuBase")); diff --git a/src/controls/plugin.pri b/src/controls/plugin.pri index 338645e4..61bda5da 100644 --- a/src/controls/plugin.pri +++ b/src/controls/plugin.pri @@ -5,6 +5,7 @@ HEADERS += \ $$PWD/qtmenu_p.h \ $$PWD/qtmenubar_p.h \ $$PWD/qtmenuitem_p.h \ + $$PWD/qtmenuitemcontainer_p.h \ $$PWD/qtmenupopupwindow_p.h \ $$PWD/qpagestatus.h diff --git a/src/controls/qmldir b/src/controls/qmldir index 23b65844..377b55ee 100644 --- a/src/controls/qmldir +++ b/src/controls/qmldir @@ -4,7 +4,6 @@ ApplicationWindow 1.0 ApplicationWindow.qml Button 1.0 Button.qml CheckBox 1.0 CheckBox.qml ComboBox 1.0 ComboBox.qml -ContextMenu 1.0 ContextMenu.qml GroupBox 1.0 GroupBox.qml Label 1.0 Label.qml MenuBar 1.0 MenuBar.qml diff --git a/src/controls/qtmenu.cpp b/src/controls/qtmenu.cpp index 1dbc64e4..bed3d6ab 100644 --- a/src/controls/qtmenu.cpp +++ b/src/controls/qtmenu.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qtmenu_p.h" +#include "qtmenuitemcontainer_p.h" #include "qtaction_p.h" #include "qtmenupopupwindow_p.h" @@ -133,14 +134,14 @@ QT_BEGIN_NAMESPACE QtMenu::QtMenu(QObject *parent) : QtMenuText(parent), + m_itemsCount(0), m_selectedIndex(-1), - m_highlightedIndex(0), m_parentWindow(0), - m_hasNativeModel(false), m_minimumWidth(0), m_popupWindow(0), m_menuContentItem(0), - m_popupVisible(false) + m_popupVisible(false), + m_containersCount(0) { connect(this, SIGNAL(__textChanged()), this, SIGNAL(titleChanged())); @@ -155,6 +156,7 @@ QtMenu::QtMenu(QObject *parent) QtMenu::~QtMenu() { delete m_platformMenu; + m_platformMenu = 0; } void QtMenu::updateText() @@ -191,15 +193,15 @@ void QtMenu::setSelectedIndex(int index) void QtMenu::updateSelectedIndex() { - if (QtMenuBase *menuItem = qobject_cast<QtMenuItem*>(sender())) { - int index = m_menuItems.indexOf(menuItem); + if (QtMenuItem *menuItem = qobject_cast<QtMenuItem*>(sender())) { + int index = indexOfMenuItem(menuItem); setSelectedIndex(index); } } -QQmlListProperty<QtMenuBase> QtMenu::menuItems() +QtMenuItems QtMenu::menuItems() { - return QQmlListProperty<QtMenuBase>(this, 0, &QtMenu::append_menuItems, &QtMenu::count_menuItems, &QtMenu::at_menuItems, 0); + return QtMenuItems(this, 0, &QtMenu::append_menuItems, &QtMenu::count_menuItems, &QtMenu::at_menuItems, 0); } QQuickWindow *QtMenu::findParentWindow() @@ -228,12 +230,7 @@ void QtMenu::__popup(qreal x, qreal y, int atItemIndex) setPopupVisible(true); - // If atItemIndex is valid, x and y is specified from the - // the position of the corresponding QtMenuItem: - QtMenuItem *atItem = 0; - if (atItemIndex >= 0) - while (!atItem && atItemIndex < m_menuItems.size()) - atItem = qobject_cast<QtMenuItem *>(m_menuItems[atItemIndex++]); + QtMenuBase *atItem = menuItemAtIndex(atItemIndex); QQuickWindow *parentWindow = findParentWindow(); @@ -324,91 +321,211 @@ void QtMenu::windowVisibleChanged(bool v) } } -void QtMenu::clear() +void QtMenu::itemIndexToListIndex(int itemIndex, int *listIndex, int *containerIndex) const +{ + *listIndex = -1; + QtMenuItemContainer *container = 0; + while (itemIndex >= 0 && ++*listIndex < m_menuItems.count()) + if ((container = qobject_cast<QtMenuItemContainer *>(m_menuItems[*listIndex]))) + itemIndex -= container->items().count(); + else + --itemIndex; + + if (container) + *containerIndex = container->items().count() + itemIndex; + else + *containerIndex = -1; +} + +int QtMenu::itemIndexForListIndex(int listIndex) const +{ + int index = 0; + int i = 0; + while (i < listIndex && i < m_menuItems.count()) + if (QtMenuItemContainer *container = qobject_cast<QtMenuItemContainer *>(m_menuItems[i++])) + index += container->items().count(); + else + ++index; + + return index; +} + +QtMenuBase *QtMenu::nextMenuItem(QtMenu::MenuItemIterator *it) const { - foreach (QtMenuBase *item, m_menuItems) { - if (m_platformMenu) - m_platformMenu->removeMenuItem(item->platformItem()); - delete item; + if (it->containerIndex != -1) { + QtMenuItemContainer *container = qobject_cast<QtMenuItemContainer *>(m_menuItems[it->index]); + if (++it->containerIndex < container->items().count()) + return container->items()[it->containerIndex]; } - m_menuItems.clear(); + + if (++it->index < m_menuItems.count()) { + if (QtMenuItemContainer *container = qobject_cast<QtMenuItemContainer *>(m_menuItems[it->index])) { + it->containerIndex = 0; + return container->items()[0]; + } else { + it->containerIndex = -1; + return m_menuItems[it->index]; + } + } + + return 0; } -void QtMenu::addMenuItem(QtMenuBase *menuItem) +QtMenuBase *QtMenu::menuItemAtIndex(int index) const { - menuItem->setParentMenu(this); - m_menuItems.append(menuItem); - if (QPlatformMenuItem *platformItem = menuItem->platformItem()) { - if (m_platformMenu) - m_platformMenu->insertMenuItem(platformItem, 0 /* append */); + if (0 <= index && index < m_itemsCount) { + if (!m_containersCount) { + return m_menuItems[index]; + } else if (m_containersCount == 1 && m_menuItems.count() == 1) { + QtMenuItemContainer *container = qobject_cast<QtMenuItemContainer *>(m_menuItems[0]); + return container->items()[index]; + } else { + int containerIndex; + int i; + itemIndexToListIndex(index, &i, &containerIndex); + if (containerIndex != -1) { + QtMenuItemContainer *container = qobject_cast<QtMenuItemContainer *>(m_menuItems[i]); + return container->items()[containerIndex]; + } else { + return m_menuItems[i]; + } + } } + + return 0; } -QtMenuItem *QtMenu::addItem(const QString &text) +bool QtMenu::contains(QtMenuBase *item) { - QtMenuItem *menuItem = new QtMenuItem(this); - menuItem->setText(text); - addMenuItem(menuItem); + if (item->container()) + return item->container()->items().contains(item); - emit itemsChanged(); - return menuItem; + return m_menuItems.contains(item); } -QString QtMenu::__modelTextAt(int index) const +int QtMenu::indexOfMenuItem(QtMenuBase *item) const { - if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(m_model.value<QObject*>())) { - return model->data(model->index(index, 0)).toString(); - } else if (m_model.canConvert(QVariant::StringList)) { - return m_model.toStringList().at(index); + if (!item) + return -1; + if (item->container()) { + int containerIndex = m_menuItems.indexOf(item->container()); + if (containerIndex == -1) + return -1; + int index = item->container()->items().indexOf(item); + return index == -1 ? -1 : itemIndexForListIndex(containerIndex) + index; + } else { + int index = m_menuItems.indexOf(item); + return index == -1 ? -1 : itemIndexForListIndex(index); } - return ""; } -int QtMenu::__modelCount() const +QtMenuItem *QtMenu::addItem(QString title) { - if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(m_model.value<QObject*>())) { - return model->rowCount(); - } else if (m_model.canConvert(QVariant::StringList)) { - return m_model.toStringList().count(); + QtMenuItem *item = new QtMenuItem(this); + item->setText(title); + insertItem(m_itemsCount, item); + return item; +} + +void QtMenu::insertItem(int index, QtMenuBase *menuItem) +{ + if (!menuItem) + return; + int itemIndex; + if (m_containersCount) { + QtMenuItemContainer *container = menuItem->parent() != this ? m_containers[menuItem->parent()] : 0; + if (container) { + container->insertItem(index, menuItem); + itemIndex = itemIndexForListIndex(m_menuItems.indexOf(container)) + index; + } else { + itemIndex = itemIndexForListIndex(index); + m_menuItems.insert(itemIndex, menuItem); + } + } else { + itemIndex = index; + m_menuItems.insert(index, menuItem); } - return -1; + + setupMenuItem(menuItem, itemIndex); + emit itemsChanged(); } -void QtMenu::append_menuItems(QQmlListProperty<QtMenuBase> *list, QtMenuBase *menuItem) +void QtMenu::removeItem(QtMenuBase *menuItem) { - if (QtMenu *menu = qobject_cast<QtMenu *>(list->object)) - menu->addMenuItem(menuItem); + if (!menuItem) + return; + menuItem->setParentMenu(0); + + QtMenuItemContainer *container = menuItem->parent() != this ? m_containers[menuItem->parent()] : 0; + if (container) + container->removeItem(menuItem); + else + m_menuItems.removeOne(menuItem); + + --m_itemsCount; + emit itemsChanged(); } -int QtMenu::count_menuItems(QQmlListProperty<QtMenuBase> *list) +void QtMenu::clear() { - QtMenu *menu = qobject_cast<QtMenu *>(list->object); - if (menu) - return menu->m_menuItems.size(); - return 0; + m_containers.clear(); + m_containersCount = 0; + + while (!m_menuItems.empty()) + delete m_menuItems.takeFirst(); + m_itemsCount = 0; } -QtMenuBase *QtMenu::at_menuItems(QQmlListProperty<QtMenuBase> *list, int index) +void QtMenu::setupMenuItem(QtMenuBase *item, int platformIndex) { - QtMenu *menu = qobject_cast<QtMenu *>(list->object); - if (menu && 0 <= index && index < menu->m_menuItems.size()) - return menu->m_menuItems[index]; - return 0; + item->setParentMenu(this); + if (m_platformMenu) { + QPlatformMenuItem *before = 0; + if (platformIndex != -1) + before = m_platformMenu->menuItemAt(platformIndex); + m_platformMenu->insertMenuItem(item->platformItem(), before); + } + ++m_itemsCount; } +void QtMenu::append_menuItems(QtMenuItems *list, QObject *o) +{ + if (QtMenu *menu = qobject_cast<QtMenu *>(list->object)) { + Q_ASSERT(o->parent() == menu); + + if (QtMenuBase *menuItem = qobject_cast<QtMenuBase *>(o)) { + menu->m_menuItems.append(menuItem); + menu->setupMenuItem(menuItem); + } else { + QtMenuItemContainer *menuItemContainer = new QtMenuItemContainer(menu); + menu->m_menuItems.append(menuItemContainer); + menu->m_containers.insert(o, menuItemContainer); + menuItemContainer->setParentMenu(menu); + ++menu->m_containersCount; + foreach (QObject *child, o->children()) { + if (QtMenuBase *item = qobject_cast<QtMenuBase *>(child)) { + menuItemContainer->insertItem(-1, item); + menu->setupMenuItem(item); + } + } + } + } +} + +int QtMenu::count_menuItems(QtMenuItems *list) +{ + if (QtMenu *menu = qobject_cast<QtMenu *>(list->object)) + return menu->m_itemsCount; -void QtMenu::setModel(const QVariant &newModel) { - if (m_model != newModel) { - m_hasNativeModel = false; - m_model = newModel; + return 0; +} - if (qobject_cast<QAbstractItemModel*>(newModel.value<QObject*>())) - m_hasNativeModel = true; - else if (newModel.canConvert(QVariant::StringList)) - m_hasNativeModel = true; +QObject *QtMenu::at_menuItems(QtMenuItems *list, int index) +{ + if (QtMenu *menu = qobject_cast<QtMenu *>(list->object)) + return menu->menuItemAtIndex(index); - emit modelChanged(m_model); - } + return 0; } QT_END_NAMESPACE diff --git a/src/controls/qtmenu_p.h b/src/controls/qtmenu_p.h index bb595328..bd3fc7c8 100644 --- a/src/controls/qtmenu_p.h +++ b/src/controls/qtmenu_p.h @@ -44,7 +44,7 @@ #include "qtmenuitem_p.h" -#include <QtCore/qabstractitemmodel.h> +#include <QtCore/qglobal.h> #include <QtCore/qvariant.h> #include <QtQml/qqml.h> #include <QtQml/qqmllist.h> @@ -53,16 +53,18 @@ QT_BEGIN_NAMESPACE class QPlatformMenu; class QtMenuPopupWindow; +class QtMenuItemContainer; class QQuickWindow; +typedef QQmlListProperty<QObject> QtMenuItems; + class QtMenu : public QtMenuText { Q_OBJECT Q_PROPERTY(QString title READ text WRITE setText NOTIFY titleChanged) - Q_PROPERTY(QQmlListProperty<QtMenuBase> items READ menuItems NOTIFY itemsChanged) + Q_PROPERTY(QQmlListProperty<QObject> items READ menuItems NOTIFY itemsChanged) Q_CLASSINFO("DefaultProperty", "items") Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY selectedIndexChanged) - Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(bool __popupVisible READ popupVisible NOTIFY popupVisibleChanged) Q_PROPERTY(QQuickItem *__contentItem READ menuContentItem WRITE setMenuContentItem) @@ -71,22 +73,20 @@ class QtMenu : public QtMenuText public: Q_INVOKABLE void popup(); - - Q_INVOKABLE QtMenuItem *addItem(const QString &text); - Q_INVOKABLE void clear(); + Q_INVOKABLE QtMenuItem *addItem(QString); Q_INVOKABLE void __popup(qreal x, qreal y, int atActionIndex = -1); - Q_INVOKABLE QString __modelTextAt(int index) const; - Q_INVOKABLE int __modelCount() const; - Q_INVOKABLE bool __hasNativeModel() const { return m_hasNativeModel; } public Q_SLOTS: + void insertItem(int, QtMenuBase *); + void removeItem(QtMenuBase *); + void clear(); + void __closeMenu(); void __dismissMenu(); Q_SIGNALS: void selectedIndexChanged(); - void modelChanged(const QVariant &newModel); void itemsChanged(); void titleChanged(); @@ -100,54 +100,63 @@ public: int selectedIndex() const { return m_selectedIndex; } void setSelectedIndex(int index); - QQmlListProperty<QtMenuBase> menuItems(); + QtMenuItems menuItems(); + QtMenuBase *menuItemAtIndex(int index) const; + bool contains(QtMenuBase *); + int indexOfMenuItem(QtMenuBase *) const; - QPlatformMenu* platformMenu() { return m_platformMenu; } - void addMenuItem(QtMenuBase *); + QPlatformMenu *platformMenu() const { return m_platformMenu; } int minimumWidth() const { return m_minimumWidth; } void setMinimumWidth(int w); void setFont(const QFont &font); - QVariant model() const { return m_model; } - QQuickItem *menuContentItem() const { return m_menuContentItem; } bool popupVisible() const { return m_popupVisible; } - void setModel(const QVariant &newModel); + bool isNative() { return m_platformMenu != 0; } + +protected Q_SLOTS: + void updateSelectedIndex(); void setMenuContentItem(QQuickItem *); void setPopupVisible(bool); - bool isNative() { return m_platformMenu != 0; } - - -protected Q_SLOTS: void updateText(); void windowVisibleChanged(bool); - void updateSelectedIndex(); private: QQuickWindow *findParentWindow(); - static void append_menuItems(QQmlListProperty<QtMenuBase> *list, QtMenuBase *menuItem); - static int count_menuItems(QQmlListProperty<QtMenuBase> *list); - static QtMenuBase *at_menuItems(QQmlListProperty<QtMenuBase> *list, int index); + int itemIndexForListIndex(int listIndex) const; + void itemIndexToListIndex(int, int *, int *) const; + + struct MenuItemIterator + { + MenuItemIterator(): index(-1), containerIndex(-1) {} + int index, containerIndex; + }; + + QtMenuBase *nextMenuItem(MenuItemIterator *) const; + + static void append_menuItems(QtMenuItems *list, QObject *o); + static int count_menuItems(QtMenuItems *list); + static QObject *at_menuItems(QtMenuItems *list, int index); + void setupMenuItem(QtMenuBase *item, int platformIndex = -1); QPlatformMenu *m_platformMenu; QList<QtMenuBase *> m_menuItems; + QHash<QObject *, QtMenuItemContainer *> m_containers; + int m_itemsCount; int m_selectedIndex; int m_highlightedIndex; QQuickWindow *m_parentWindow; - bool m_hasNativeModel; - QVariant m_model; int m_minimumWidth; QtMenuPopupWindow *m_popupWindow; QQuickItem * m_menuContentItem; bool m_popupVisible; - - friend class QtMenuBase; + int m_containersCount; }; QT_END_NAMESPACE diff --git a/src/controls/qtmenuitem.cpp b/src/controls/qtmenuitem.cpp index 839a3b2d..2e01cb6a 100644 --- a/src/controls/qtmenuitem.cpp +++ b/src/controls/qtmenuitem.cpp @@ -42,6 +42,7 @@ #include "qtmenuitem_p.h" #include "qtaction_p.h" #include "qtmenu_p.h" +#include "qtmenuitemcontainer_p.h" #include <private/qguiapplication_p.h> #include <QtGui/qpa/qplatformtheme.h> @@ -51,15 +52,18 @@ QT_BEGIN_NAMESPACE QtMenuBase::QtMenuBase(QObject *parent) - : QObject(parent), m_visible(true), - m_parentMenu(0), m_visualItem(0) + : QObject(parent), m_visible(true), m_parentMenu(0), m_container(0), m_visualItem(0) { m_platformItem = QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem(); } QtMenuBase::~QtMenuBase() { - delete m_platformItem; + setParentMenu(0); + if (m_platformItem) { + delete m_platformItem; + m_platformItem = 0; + } } void QtMenuBase::setVisible(bool v) @@ -83,14 +87,27 @@ QtMenu *QtMenuBase::parentMenu() const void QtMenuBase::setParentMenu(QtMenu *parentMenu) { + if (m_parentMenu && m_parentMenu->platformMenu()) + m_parentMenu->platformMenu()->removeMenuItem(m_platformItem); + m_parentMenu = parentMenu; } +QtMenuItemContainer *QtMenuBase::container() const +{ + return m_container; +} + +void QtMenuBase::setContainer(QtMenuItemContainer *c) +{ + m_container = c; +} + void QtMenuBase::syncWithPlatformMenu() { - QtMenu *menu = qobject_cast<QtMenu *>(parent()); + QtMenu *menu = parentMenu(); if (menu && menu->platformMenu() && platformItem() - && menu->m_menuItems.contains(this)) // If not, it'll be added later and then sync'ed + && menu->contains(this)) // If not, it'll be added later and then sync'ed menu->platformMenu()->syncMenuItem(platformItem()); } @@ -379,7 +396,8 @@ QtMenuItem::~QtMenuItem() void QtMenuItem::setParentMenu(QtMenu *parentMenu) { QtMenuText::setParentMenu(parentMenu); - connect(this, SIGNAL(triggered()), parentMenu, SLOT(updateSelectedIndex())); + if (parentMenu) + connect(this, SIGNAL(triggered()), parentMenu, SLOT(updateSelectedIndex())); } void QtMenuItem::bindToAction(QtAction *action) @@ -541,6 +559,7 @@ void QtMenuItem::updateChecked() platformItem()->setChecked(checked); syncWithPlatformMenu(); } + emit toggled(checked); } diff --git a/src/controls/qtmenuitem_p.h b/src/controls/qtmenuitem_p.h index 81b27c49..d00f821e 100644 --- a/src/controls/qtmenuitem_p.h +++ b/src/controls/qtmenuitem_p.h @@ -47,6 +47,7 @@ #include <QtCore/qpointer.h> #include <QtCore/qurl.h> #include <QtGui/qicon.h> +#include <QtQml/QQmlListProperty> QT_BEGIN_NAMESPACE @@ -56,6 +57,7 @@ class QQuickItem; class QtAction; class QtExclusiveGroup; class QtMenu; +class QtMenuItemContainer; class QtMenuBase: public QObject { @@ -79,6 +81,9 @@ public: QtMenu *parentMenu() const; virtual void setParentMenu(QtMenu *parentMenu); + QtMenuItemContainer *container() const; + void setContainer(QtMenuItemContainer *); + inline QPlatformMenuItem *platformItem() { return m_platformItem; } void syncWithPlatformMenu(); @@ -90,6 +95,7 @@ public: private: bool m_visible; QtMenu *m_parentMenu; + QtMenuItemContainer *m_container; QPlatformMenuItem *m_platformItem; QPointer<QQuickItem> m_visualItem; }; diff --git a/src/controls/qtmenuitemcontainer_p.h b/src/controls/qtmenuitemcontainer_p.h new file mode 100644 index 00000000..b4168b74 --- /dev/null +++ b/src/controls/qtmenuitemcontainer_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 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 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QTMENUITEMSCONTAINER_P_H +#define QTMENUITEMSCONTAINER_P_H + +#include "qtmenuitem_p.h" +#include <QtCore/qlist.h> + +QT_BEGIN_NAMESPACE + +class QtMenuItemContainer : public QtMenuBase +{ + Q_OBJECT +public: + explicit QtMenuItemContainer(QObject *parent = 0) + : QtMenuBase(parent) + { } + + ~QtMenuItemContainer() + { + clear(); + } + + void insertItem(int index, QtMenuBase *item) + { + if (index == -1) + index = m_menuItems.count(); + m_menuItems.insert(index, item); + item->setContainer(this); + } + + void removeItem(QtMenuBase *item) + { + item->setParentMenu(0); + item->setContainer(0); + m_menuItems.removeOne(item); + } + + const QList<QtMenuBase *> &items() + { + return m_menuItems; + } + + void clear() + { + while (!m_menuItems.empty()) { + QtMenuBase *item = m_menuItems.takeFirst(); + item->setParentMenu(0); + item->setContainer(0); + } + } + +private: + QList<QtMenuBase *> m_menuItems; +}; + +QT_END_NAMESPACE + +#endif // QTMENUITEMCONTAINER_H diff --git a/tests/auto/controls/data/tst_combobox.qml b/tests/auto/controls/data/tst_combobox.qml index 9a86ee9d..781cada0 100644 --- a/tests/auto/controls/data/tst_combobox.qml +++ b/tests/auto/controls/data/tst_combobox.qml @@ -58,7 +58,7 @@ TestCase { function test_keyupdown() { var comboBox = Qt.createQmlObject('import QtQuick.Controls 1.0 ; ComboBox {}', testCase, ''); - comboBox.model = model + comboBox.model = 4 compare(comboBox.selectedIndex, 0) @@ -74,10 +74,12 @@ TestCase { function test_textrole() { var comboBox = Qt.createQmlObject('import QtQuick.Controls 1.0 ; ComboBox {}', testCase, ''); - comboBox.model = model comboBox.textRole = "text" + comboBox.model = model compare(comboBox.selectedIndex, 0) - expectFail('', "QTCOMPONENTS-1301") compare(comboBox.selectedText, "Banana") + comboBox.textRole = "color" + compare(comboBox.selectedIndex, 0) + compare(comboBox.selectedText, "Yellow") } } diff --git a/tests/auto/controls/data/tst_menu.qml b/tests/auto/controls/data/tst_menu.qml index 66aa8f09..9884d466 100644 --- a/tests/auto/controls/data/tst_menu.qml +++ b/tests/auto/controls/data/tst_menu.qml @@ -95,10 +95,11 @@ TestCase { id: modelCreationComponent // TODO Update when model patch is in // Menu { MenuItemRepeater { model: testcase.itemsText MenuItem { text: modelData } } - ContextMenu { model: testcase.itemsText } + Menu {} } function test_modelCreation() { + testcase.skip("No support for model in Menu. It'll come back") var menu = modelCreationComponent.createObject(testcase) compare(menu.items.length, testcase.itemsText.length) for (var i = 0; i < menu.items.length; i++) |