diff options
| -rw-r--r-- | src/controls/Menu.qml | 28 | ||||
| -rw-r--r-- | src/controls/plugin.cpp | 2 | ||||
| -rw-r--r-- | src/controls/qtmenu.cpp | 39 | ||||
| -rw-r--r-- | src/controls/qtmenu_p.h | 2 | ||||
| -rw-r--r-- | src/controls/qtmenuitem_p.h | 17 | ||||
| -rw-r--r-- | src/controls/qtmenuitemcontainer_p.h | 10 | ||||
| -rw-r--r-- | src/private/qstyleitem.cpp | 2 | ||||
| -rw-r--r-- | src/styles/Desktop/MenuStyle.qml | 2 | ||||
| -rw-r--r-- | src/styles/MenuStyle.qml | 2 | ||||
| -rw-r--r-- | tests/auto/controls/data/tst_menu.qml | 43 |
10 files changed, 129 insertions, 18 deletions
diff --git a/src/controls/Menu.qml b/src/controls/Menu.qml index 9ee03e46f..6ac930ef2 100644 --- a/src/controls/Menu.qml +++ b/src/controls/Menu.qml @@ -103,6 +103,20 @@ import "Styles/Settings.js" as Settings MenuPrivate { id: root + /*! + Adds a submenu to the menu. Returns the newly created \l Menu. + */ + function addMenu(title) { + if (!__selfComponent) + __selfComponent = Qt.createComponent("Menu.qml", root) + var submenu = __selfComponent.createObject(__selfComponent, { "title": title }) + root.insertItem(items.length, submenu) + return submenu + } + + /*! internal */ + property Component __selfComponent: null + /*! \internal */ property Component style: Qt.createComponent(Settings.THEME_PATH + "/MenuStyle.qml", root) @@ -183,7 +197,7 @@ MenuPrivate { Keys.onRightPressed: { var item = itemsRepeater.itemAt(root.__currentIndex) - if (item && item.hasSubmenu) { + if (item && item.isSubmenu) { item.showSubMenu(true) item.menuItem.__currentIndex = 0 } @@ -197,7 +211,7 @@ MenuPrivate { var item = itemsRepeater.itemAt(root.__currentIndex) if (item && !item.isSeparator) { root.__dismissMenu() - if (!item.hasSubmenu) + if (!item.isSubmenu) item.menuItem.trigger() } } @@ -229,12 +243,12 @@ MenuPrivate { function updateCurrentItem(mouse) { var pos = mapToItem(column, mouse.x, mouse.y) if (!currentItem || !currentItem.contains(Qt.point(pos.x - currentItem.x, pos.y - currentItem.y))) { - if (currentItem && !pressed && currentItem.hasSubmenu) + if (currentItem && !pressed && currentItem.isSubmenu) currentItem.closeSubMenu() currentItem = column.childAt(pos.x, pos.y) if (currentItem) { root.__currentIndex = currentItem.menuItemIndex - if (currentItem.hasSubmenu && !currentItem.menuItem.__popupVisible) + if (currentItem.isSubmenu && !currentItem.menuItem.__popupVisible) currentItem.showSubMenu(false) } else { root.__currentIndex = -1 @@ -255,10 +269,10 @@ MenuPrivate { id: menuItemLoader property var menuItem: modelData - property bool isSeparator: menuItem ? !menuItem.hasOwnProperty("enabled") : true - property bool hasSubmenu: menuItem ? !!menuItem["items"] : false + readonly property bool isSeparator: !!menuItem && menuItem.type === MenuItemType.Separator + readonly property bool isSubmenu: !!menuItem && menuItem.type === MenuItemType.Menu property bool selected: !isSeparator && root.__currentIndex === index - property string text: hasSubmenu ? menuItem.title : !isSeparator ? menuItem.text : "" + property string text: isSubmenu ? menuItem.title : !isSeparator ? menuItem.text : "" property int menuItemIndex: index diff --git a/src/controls/plugin.cpp b/src/controls/plugin.cpp index b7dd36cd3..50c8fe69c 100644 --- a/src/controls/plugin.cpp +++ b/src/controls/plugin.cpp @@ -82,6 +82,8 @@ void StylePlugin::registerTypes(const char *uri) qmlRegisterType<QtMenu>(uri, 1, 0, "MenuPrivate"); qmlRegisterType<QtMenuBar>(uri, 1, 0, "MenuBarPrivate"); qmlRegisterType<QtMenuItem>(uri, 1, 0, "MenuItem"); + qmlRegisterUncreatableType<QtMenuItemType>(uri, 1, 0, "MenuItemType", + QLatin1String("Do not create objects of type MenuItemType")); 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/qtmenu.cpp b/src/controls/qtmenu.cpp index 150efcee1..dbcbe1137 100644 --- a/src/controls/qtmenu.cpp +++ b/src/controls/qtmenu.cpp @@ -123,6 +123,38 @@ QT_BEGIN_NAMESPACE */ /*! + \qmlmethod MenuItem Menu::addItem(text) + + Adds an item to the menu. Returns the newly created \l MenuItem. +*/ + +/*! + \qmlmethod MenuSeparator Menu::addSeparator() + + Adds a separator to the menu. Returns the newly created \l MenuSeparator. +*/ + +/*! + \qmlmethod void Menu::insertItem(before, item) + + Inserts the \c item at the index \c before in the current menu. + In this case, \c item can be either a \l MenuItem, a \l MenuSeparator, + or a \l Menu. + + \sa removeItem() +*/ + +/*! + \qmlmethod void Menu::removeItem(item) + + Removes the \c item from the menu. + In this case, \c item can be either a \l MenuItem, a \l MenuSeparator, + or a \l Menu. + + \sa insertItem() +*/ + +/*! \qmlproperty var Menu::model */ @@ -402,6 +434,13 @@ QtMenuItem *QtMenu::addItem(QString title) return item; } +QtMenuSeparator *QtMenu::addSeparator() +{ + QtMenuSeparator *item = new QtMenuSeparator(this); + insertItem(m_itemsCount, item); + return item; +} + void QtMenu::insertItem(int index, QtMenuBase *menuItem) { if (!menuItem) diff --git a/src/controls/qtmenu_p.h b/src/controls/qtmenu_p.h index 650d8e80f..9d0418734 100644 --- a/src/controls/qtmenu_p.h +++ b/src/controls/qtmenu_p.h @@ -74,6 +74,7 @@ class QtMenu : public QtMenuText public: Q_INVOKABLE void popup(); Q_INVOKABLE QtMenuItem *addItem(QString); + Q_INVOKABLE QtMenuSeparator *addSeparator(); Q_INVOKABLE void __popup(qreal x, qreal y, int atActionIndex = -1); @@ -115,6 +116,7 @@ public: QQuickItem *menuContentItem() const { return m_menuContentItem; } bool popupVisible() const { return m_popupVisible; } + QtMenuItemType::MenuItemType type() { return QtMenuItemType::Menu; } bool isNative() { return m_platformMenu != 0; } protected Q_SLOTS: diff --git a/src/controls/qtmenuitem_p.h b/src/controls/qtmenuitem_p.h index d00f821ed..4762d6e2f 100644 --- a/src/controls/qtmenuitem_p.h +++ b/src/controls/qtmenuitem_p.h @@ -59,10 +59,24 @@ class QtExclusiveGroup; class QtMenu; class QtMenuItemContainer; +class QtMenuItemType +{ + Q_GADGET + Q_ENUMS(MenuItemType) + +public: + enum MenuItemType { + Separator, + Item, + Menu + }; +}; + class QtMenuBase: public QObject { Q_OBJECT Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged) + Q_PROPERTY(QtMenuItemType::MenuItemType type READ type CONSTANT) Q_PROPERTY(QtMenu *__parentMenu READ parentMenu CONSTANT) Q_PROPERTY(bool __isNative READ isNative CONSTANT) @@ -90,6 +104,7 @@ public: QQuickItem *visualItem() const; void setVisualItem(QQuickItem *item); + virtual QtMenuItemType::MenuItemType type() { return QtMenuItemType::Item; } virtual bool isNative() { return m_platformItem != 0; } private: @@ -105,6 +120,8 @@ class QtMenuSeparator : public QtMenuBase Q_OBJECT public: QtMenuSeparator(QObject *parent = 0); + + QtMenuItemType::MenuItemType type() { return QtMenuItemType::Separator; } }; class QtMenuText: public QtMenuBase diff --git a/src/controls/qtmenuitemcontainer_p.h b/src/controls/qtmenuitemcontainer_p.h index b4168b74d..2dbad6c62 100644 --- a/src/controls/qtmenuitemcontainer_p.h +++ b/src/controls/qtmenuitemcontainer_p.h @@ -75,7 +75,7 @@ public: m_menuItems.removeOne(item); } - const QList<QtMenuBase *> &items() + const QList<QPointer<QtMenuBase> > &items() { return m_menuItems; } @@ -84,13 +84,15 @@ public: { while (!m_menuItems.empty()) { QtMenuBase *item = m_menuItems.takeFirst(); - item->setParentMenu(0); - item->setContainer(0); + if (item) { + item->setParentMenu(0); + item->setContainer(0); + } } } private: - QList<QtMenuBase *> m_menuItems; + QList<QPointer<QtMenuBase> > m_menuItems; }; QT_END_NAMESPACE diff --git a/src/private/qstyleitem.cpp b/src/private/qstyleitem.cpp index 3d2710924..1e50d3726 100644 --- a/src/private/qstyleitem.cpp +++ b/src/private/qstyleitem.cpp @@ -368,7 +368,7 @@ void QStyleItem::initStyleOption() } else { opt->text = text(); - if (m_properties["hasSubmenu"].toBool()) { + if (m_properties["isSubmenu"].toBool()) { opt->menuItemType = QStyleOptionMenuItem::SubMenu; } else { QString shortcut = m_properties["shortcut"].toString(); diff --git a/src/styles/Desktop/MenuStyle.qml b/src/styles/Desktop/MenuStyle.qml index 6de5c95a5..7bfee4e0b 100644 --- a/src/styles/Desktop/MenuStyle.qml +++ b/src/styles/Desktop/MenuStyle.qml @@ -88,7 +88,7 @@ Style { "checkable": !!menuItem && !!menuItem["checkable"], "exclusive": !!menuItem && !!menuItem["exclusiveGroup"], "shortcut": !!menuItem && menuItem["shortcut"] || "", - "hasSubmenu": hasSubmenu, + "isSubmenu": isSubmenu, "icon": !!menuItem && menuItem.__icon } } diff --git a/src/styles/MenuStyle.qml b/src/styles/MenuStyle.qml index d80ba9e6e..dfc25ac50 100644 --- a/src/styles/MenuStyle.qml +++ b/src/styles/MenuStyle.qml @@ -72,7 +72,7 @@ Style { Text { id: text visible: !isSeparator - text: menuItem.text + (hasSubmenu ? " \u25b6" : "") + text: menuItem.text + (isSubmenu ? " \u25b6" : "") x: 6 anchors.verticalCenter: parent.verticalCenter renderType: Text.NativeRendering diff --git a/tests/auto/controls/data/tst_menu.qml b/tests/auto/controls/data/tst_menu.qml index 7d6219123..3c109347f 100644 --- a/tests/auto/controls/data/tst_menu.qml +++ b/tests/auto/controls/data/tst_menu.qml @@ -93,13 +93,20 @@ TestCase { Component { id: modelCreationComponent - // TODO Update when model patch is in - // Menu { MenuItemRepeater { model: testcase.itemsText MenuItem { text: modelData } } - Menu {} + Menu { + id: modelMenu + Instantiator { + model: itemsText + MenuItem { + text: modelData + } + onObjectAdded: modelMenu.insertItem(index, object) + } + + } } 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++) @@ -182,4 +189,32 @@ TestCase { compare(menu.__selectedIndex, 2) verify(menu.items[menu.__selectedIndex].checked) } + + function test_dynamicItems() { + menu.clear() + compare(menu.items.length, 0) + var n = 6 + var separatorIdx = 4 + var submenuIdx = 5 + for (var i = 0; i < n; ++i) { + if (i === separatorIdx) + var item = menu.addSeparator() + else if (i === submenuIdx) + item = menu.addMenu("Submenu") + else + item = menu.addItem("Item " + i) + } + compare(menu.items.length, n) + + for (i = 0; i < n; ++i) { + item = menu.items[i] + compare(item.type, i === submenuIdx ? MenuItemType.Menu : + i === separatorIdx ? MenuItemType.Separator : + MenuItemType.Item) + if (i === submenuIdx) + compare(item.title, "Submenu") + else if (i !== separatorIdx) + compare(item.text, "Item " + i) + } + } } |
