summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/gallery/main.qml4
-rw-r--r--src/controls/ComboBox.qml66
-rw-r--r--src/controls/ContextMenu.qml100
-rw-r--r--src/controls/controls.pro1
-rw-r--r--src/controls/plugin.cpp2
-rw-r--r--src/controls/plugin.pri1
-rw-r--r--src/controls/qmldir1
-rw-r--r--src/controls/qtmenu.cpp249
-rw-r--r--src/controls/qtmenu_p.h65
-rw-r--r--src/controls/qtmenuitem.cpp31
-rw-r--r--src/controls/qtmenuitem_p.h6
-rw-r--r--src/controls/qtmenuitemcontainer_p.h98
-rw-r--r--tests/auto/controls/data/tst_combobox.qml8
-rw-r--r--tests/auto/controls/data/tst_menu.qml3
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++)