From acc70f6b41c5d1da6e072e8f3422aa7c8c807e7c Mon Sep 17 00:00:00 2001 From: Jens Bache-Wiig Date: Mon, 23 Jan 2012 11:39:30 +0100 Subject: Add support for native model in ComboBox and ContextMenu This adds some basic support for C++ item models. I also added a textRole property to be consistent with other model based components. --- components/ComboBox.qml | 3 ++ components/ContextMenu.qml | 47 +++++++++++++++++++++++--- src/qtmenu.cpp | 83 ++++++++++++++++++++++++++++------------------ src/qtmenu.h | 44 +++++++++++++++++++----- 4 files changed, 130 insertions(+), 47 deletions(-) diff --git a/components/ComboBox.qml b/components/ComboBox.qml index c55171120..37ebb915f 100644 --- a/components/ComboBox.qml +++ b/components/ComboBox.qml @@ -83,10 +83,13 @@ Custom.BasicButton { width: implicitWidth height: implicitHeight + implicitWidth: Math.max(80, backgroundItem.implicitWidth) implicitHeight: backgroundItem.implicitHeight + onWidthChanged: popup.setMinimumWidth(width) checkable: false + onPressedChanged: if (pressed) popup.visible = true ContextMenu { diff --git a/components/ContextMenu.qml b/components/ContextMenu.qml index a439d4a8f..08d779588 100644 --- a/components/ContextMenu.qml +++ b/components/ContextMenu.qml @@ -2,12 +2,12 @@ import QtQuick 1.1 Menu { id: root - property ListModel model property string selectedText: itemTextAt(selectedIndex) property string hoveredText: itemTextAt(hoveredIndex) property int x property int y property bool visible + property string textRole // 'centerSelectedText' means that the menu will be positioned // so that the selected text' top left corner will be at x, y. @@ -16,7 +16,10 @@ Menu { visible: false onMenuClosed: visible = false onModelChanged: if (Component.status === Component.Ready && model != undefined) rebuildMenu() - Component.onCompleted: if (model != undefined) rebuildMenu() + + Component.onCompleted: if (model !== undefined) rebuildMenu() + + onRebuildMenu: rebuildMenu() onHoveredIndexChanged: { if (hoveredIndex < menuItems.length) @@ -40,11 +43,45 @@ Menu { function rebuildMenu() { clearMenuItems(); + for (var i=0; i 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 i in listElement) { + roleName = i + ++roleCount + if (roleCount > 1) { + oneRole = false + root.enabled = false + console.log("When multiple roles used, provide textRole for the ComboBox.") + break + } + } + if (oneRole) { + root.textRole = roleName + textValue = root.model.get(j)[textRole] + } + } + } + addMenuItem(textValue) + } } } } diff --git a/src/qtmenu.cpp b/src/qtmenu.cpp index 6200968df..ce1775ad0 100644 --- a/src/qtmenu.cpp +++ b/src/qtmenu.cpp @@ -28,49 +28,49 @@ #include "qdebug.h" #include #include - +#include #include "qtoplevelwindow.h" QtMenu::QtMenu(QObject *parent) : QtMenuBase(parent), dummy(0), - _selectedIndex(0), - _highlightedIndex(0) + m_selectedIndex(0), + m_highlightedIndex(0) { - _qmenu = new QMenu(0); - connect(_qmenu, SIGNAL(aboutToHide()), this, SIGNAL(menuClosed())); + m_qmenu = new QMenu(0); + connect(m_qmenu, SIGNAL(aboutToHide()), this, SIGNAL(menuClosed())); } QtMenu::~QtMenu() { - delete _qmenu; + delete m_qmenu; } void QtMenu::setText(const QString &text) { - _qmenu->setTitle(text); + m_qmenu->setTitle(text); } QString QtMenu::text() const { - return _qmenu->title(); + return m_qmenu->title(); } void QtMenu::setSelectedIndex(int index) { - _selectedIndex = index; - QList actionList = _qmenu->actions(); - if (_selectedIndex >= 0 && _selectedIndex < actionList.size()) - _qmenu->setActiveAction(actionList[_selectedIndex]); + m_selectedIndex = index; + QList actionList = m_qmenu->actions(); + if (m_selectedIndex >= 0 && m_selectedIndex < actionList.size()) + m_qmenu->setActiveAction(actionList[m_selectedIndex]); emit selectedIndexChanged(); } void QtMenu::setHoveredIndex(int index) { - _highlightedIndex = index; - QList actionList = _qmenu->actions(); - if (_highlightedIndex >= 0 && _highlightedIndex < actionList.size()) - _qmenu->setActiveAction(actionList[_highlightedIndex]); + m_highlightedIndex = index; + QList actionList = m_qmenu->actions(); + if (m_highlightedIndex >= 0 && m_highlightedIndex < actionList.size()) + m_qmenu->setActiveAction(actionList[m_highlightedIndex]); emit hoveredIndexChanged(); } @@ -81,14 +81,14 @@ QDeclarativeListProperty QtMenu::menuItems() void QtMenu::showPopup(qreal x, qreal y, int atActionIndex) { - if (_qmenu->isVisible()) + if (m_qmenu->isVisible()) return; // If atActionIndex is valid, x and y is specified from the // the position of the corresponding QAction: QAction *atAction = 0; - if (atActionIndex >= 0 && atActionIndex < _qmenu->actions().size()) - atAction = _qmenu->actions()[atActionIndex]; + if (atActionIndex >= 0 && atActionIndex < m_qmenu->actions().size()) + atAction = m_qmenu->actions()[atActionIndex]; // x,y are in view coordinates, QMenu expects screen coordinates // ### activeWindow hack @@ -102,40 +102,40 @@ void QtMenu::showPopup(qreal x, qreal y, int atActionIndex) QPoint screenPosition = window->mapToGlobal(QPoint(x, y+menuBarHeight)); - setHoveredIndex(_selectedIndex); - _qmenu->popup(screenPosition, atAction); + setHoveredIndex(m_selectedIndex); + m_qmenu->popup(screenPosition, atAction); } void QtMenu::hidePopup() { - _qmenu->close(); + m_qmenu->close(); } QAction* QtMenu::action() { - return _qmenu->menuAction(); + return m_qmenu->menuAction(); } Q_INVOKABLE void QtMenu::clearMenuItems() { - _qmenu->clear(); - foreach (QtMenuBase *item, _qmenuItems) { + m_qmenu->clear(); + foreach (QtMenuBase *item, m_qmenuItems) { delete item; } - _qmenuItems.clear(); + m_qmenuItems.clear(); } void QtMenu::addMenuItem(const QString &text) { QtMenuItem *menuItem = new QtMenuItem(this); menuItem->setText(text); - _qmenuItems.append(menuItem); - _qmenu->addAction(menuItem->action()); + m_qmenuItems.append(menuItem); + m_qmenu->addAction(menuItem->action()); connect(menuItem->action(), SIGNAL(triggered()), this, SLOT(emitSelected())); connect(menuItem->action(), SIGNAL(hovered()), this, SLOT(emitHovered())); - if (_qmenu->actions().size() == 1) + if (m_qmenu->actions().size() == 1) // Inform QML that the selected action (0) now has changed contents: emit selectedIndexChanged(); } @@ -145,7 +145,7 @@ void QtMenu::emitSelected() QAction *act = qobject_cast(sender()); if (!act) return; - _selectedIndex = _qmenu->actions().indexOf(act); + m_selectedIndex = m_qmenu->actions().indexOf(act); emit selectedIndexChanged(); } @@ -154,25 +154,42 @@ void QtMenu::emitHovered() QAction *act = qobject_cast(sender()); if (!act) return; - _highlightedIndex = _qmenu->actions().indexOf(act); + m_highlightedIndex = m_qmenu->actions().indexOf(act); emit hoveredIndexChanged(); } QString QtMenu::itemTextAt(int index) const { - QList actionList = _qmenu->actions(); + QList actionList = m_qmenu->actions(); if (index >= 0 && index < actionList.size()) return actionList[index]->text(); else return ""; } +QString QtMenu::modelTextAt(int index) const +{ + if (QAbstractItemModel *model = qobject_cast(m_model.value())) { + return model->data(model->index(index, 0)).toString(); + } + return ""; +} + +int QtMenu::modelCount() const +{ + if (QAbstractItemModel *model = qobject_cast(m_model.value())) { + return model->rowCount(); + } + return -1; +} + + void QtMenu::append_qmenuItem(QDeclarativeListProperty *list, QtMenuBase *menuItem) { QtMenu *menu = qobject_cast(list->object); if (menu) { menuItem->setParent(menu); - menu->_qmenuItems.append(menuItem); + menu->m_qmenuItems.append(menuItem); menu->qmenu()->addAction(menuItem->action()); } } diff --git a/src/qtmenu.h b/src/qtmenu.h index c9cfd68e1..2c1f9fede 100644 --- a/src/qtmenu.h +++ b/src/qtmenu.h @@ -30,12 +30,16 @@ #include #include #include +#include +#include #include "qtmenuitem.h" class QtMenu : public QtMenuBase { Q_OBJECT Q_PROPERTY(QString text READ text WRITE setText) + Q_PROPERTY(bool hasNativeModel READ hasNativeModel) + Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged) Q_PROPERTY(int selectedIndex READ selectedIndex WRITE setSelectedIndex NOTIFY selectedIndexChanged) Q_PROPERTY(int hoveredIndex READ hoveredIndex WRITE setHoveredIndex NOTIFY hoveredIndexChanged) Q_PROPERTY(QDeclarativeListProperty menuItems READ menuItems) @@ -47,28 +51,48 @@ public: void setText(const QString &text); QString text() const; - int selectedIndex() const { return _selectedIndex; } + int selectedIndex() const { return m_selectedIndex; } void setSelectedIndex(int index); - int hoveredIndex() const { return _highlightedIndex; } + int hoveredIndex() const { return m_highlightedIndex; } void setHoveredIndex(int index); QDeclarativeListProperty menuItems(); - QMenu* qmenu() { return _qmenu; } + QMenu* qmenu() { return m_qmenu; } QAction* action(); - Q_INVOKABLE int minimumWidth() const { return _qmenu->minimumWidth(); } - Q_INVOKABLE void setMinimumWidth(int w) { _qmenu->setMinimumWidth(w); } + Q_INVOKABLE int minimumWidth() const { return m_qmenu->minimumWidth(); } + Q_INVOKABLE void setMinimumWidth(int w) { m_qmenu->setMinimumWidth(w); } Q_INVOKABLE void showPopup(qreal x, qreal y, int atActionIndex = -1); Q_INVOKABLE void hidePopup(); Q_INVOKABLE void clearMenuItems(); Q_INVOKABLE void addMenuItem(const QString &text); Q_INVOKABLE QString itemTextAt(int index) const; + Q_INVOKABLE QString modelTextAt(int index) const; + Q_INVOKABLE int modelCount() const; + QVariant model() const { return m_model; } + bool hasNativeModel() const { return m_hasNativeModel; } + +public slots: + + void setModel(const QVariant arg) { + if (m_model != arg) { + if (QAbstractItemModel *model = qobject_cast(arg.value())) { + connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(rebuildMenu())); + } + m_model = arg; + emit modelChanged(m_model); + } + } + +public: Q_SIGNALS: void menuClosed(); void selectedIndexChanged(); void hoveredIndexChanged(); + void modelChanged(const QVariant&); + void rebuldMenu(); private Q_SLOTS: void emitSelected(); @@ -79,10 +103,12 @@ private: private: QWidget *dummy; - QMenu *_qmenu; - QList _qmenuItems; - int _selectedIndex; - int _highlightedIndex; + QMenu *m_qmenu; + QList m_qmenuItems; + int m_selectedIndex; + int m_highlightedIndex; + bool m_hasNativeModel; + QVariant m_model; }; QML_DECLARE_TYPE(QtMenu) -- cgit v1.2.3