summaryrefslogtreecommitdiff
path: root/src/qtdesktop/qtmenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qtdesktop/qtmenu.cpp')
-rw-r--r--src/qtdesktop/qtmenu.cpp234
1 files changed, 234 insertions, 0 deletions
diff --git a/src/qtdesktop/qtmenu.cpp b/src/qtdesktop/qtmenu.cpp
new file mode 100644
index 00000000..34710293
--- /dev/null
+++ b/src/qtdesktop/qtmenu.cpp
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Components project.
+**
+** $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$
+**
+****************************************************************************/
+
+#include "qtmenu.h"
+#include "qdebug.h"
+#include <qapplication.h>
+#include <qmenubar.h>
+#include <qabstractitemmodel.h>
+
+QtMenu::QtMenu(QQuickItem *parent)
+ : QtMenuBase(parent),
+ dummy(0),
+ m_selectedIndex(0),
+ m_highlightedIndex(0),
+ m_hasNativeModel(false)
+{
+ m_qmenu = new QMenu(0);
+ connect(m_qmenu, SIGNAL(aboutToHide()), this, SIGNAL(menuClosed()));
+}
+
+QtMenu::~QtMenu()
+{
+ delete m_qmenu;
+}
+
+void QtMenu::setText(const QString &text)
+{
+ m_qmenu->setTitle(text);
+ emit textChanged();
+}
+
+QString QtMenu::text() const
+{
+ return m_qmenu->title();
+}
+
+void QtMenu::setSelectedIndex(int index)
+{
+ m_selectedIndex = index;
+ QList<QAction *> 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)
+{
+ m_highlightedIndex = index;
+ QList<QAction *> actionList = m_qmenu->actions();
+ if (m_highlightedIndex >= 0 && m_highlightedIndex < actionList.size())
+ m_qmenu->setActiveAction(actionList[m_highlightedIndex]);
+ emit hoveredIndexChanged();
+}
+
+QQmlListProperty<QtMenuBase> QtMenu::menuItems()
+{
+ return QQmlListProperty<QtMenuBase>(this, 0, &QtMenu::append_qmenuItem, 0, 0, 0);
+}
+
+void QtMenu::showPopup(qreal x, qreal y, int atActionIndex, QQuickWindow * parentWindow)
+{
+ 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 < m_qmenu->actions().size())
+ atAction = m_qmenu->actions()[atActionIndex];
+
+ QPointF screenPosition(mapToScene(QPoint(x, y)));
+ QWindow *tw = parentWindow ? parentWindow : window();
+ if (tw) {
+ screenPosition = tw->mapToGlobal(QPoint(x, y));
+
+ // calling winId forces a QWindow to be created
+ // since this needs to be a top-level
+ // otherwise windowHandle might return 0
+ m_qmenu->winId();
+ m_qmenu->windowHandle()->setTransientParent(tw);
+ }
+
+ setHoveredIndex(m_selectedIndex);
+ m_qmenu->popup(screenPosition.toPoint(), atAction);
+}
+
+void QtMenu::hidePopup()
+{
+ m_qmenu->close();
+}
+
+QAction* QtMenu::action()
+{
+ return m_qmenu->menuAction();
+}
+
+Q_INVOKABLE void QtMenu::clearMenuItems()
+{
+ m_qmenu->clear();
+ foreach (QtMenuBase *item, m_qmenuItems) {
+ delete item;
+ }
+ m_qmenuItems.clear();
+}
+
+void QtMenu::addMenuItem(const QString &text)
+{
+ QtMenuItem *menuItem = new QtMenuItem(this);
+ menuItem->setText(text);
+ 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 (m_qmenu->actions().size() == 1)
+ // Inform QML that the selected action (0) now has changed contents:
+ emit selectedIndexChanged();
+}
+
+void QtMenu::emitSelected()
+{
+ QAction *act = qobject_cast<QAction *>(sender());
+ if (!act)
+ return;
+ m_selectedIndex = m_qmenu->actions().indexOf(act);
+ emit selectedIndexChanged();
+}
+
+void QtMenu::emitHovered()
+{
+ QAction *act = qobject_cast<QAction *>(sender());
+ if (!act)
+ return;
+ m_highlightedIndex = m_qmenu->actions().indexOf(act);
+ emit hoveredIndexChanged();
+}
+
+QString QtMenu::itemTextAt(int index) const
+{
+ QList<QAction *> 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<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);
+ }
+ return "";
+}
+
+int QtMenu::modelCount() const
+{
+ 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();
+ }
+ return -1;
+}
+
+void QtMenu::append_qmenuItem(QQmlListProperty<QtMenuBase> *list, QtMenuBase *menuItem)
+{
+ QtMenu *menu = qobject_cast<QtMenu *>(list->object);
+ if (menu) {
+ menuItem->setParent(menu);
+ menu->m_qmenuItems.append(menuItem);
+ menu->qmenu()->addAction(menuItem->action());
+ }
+}
+
+void QtMenu::setModel(const QVariant &newModel) {
+ if (m_model != newModel) {
+
+ // Clean up any existing connections
+ if (QAbstractItemModel *oldModel = qobject_cast<QAbstractItemModel*>(m_model.value<QObject*>())) {
+ disconnect(oldModel, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(rebuildMenu()));
+ }
+
+ m_hasNativeModel = false;
+ m_model = newModel;
+
+ if (QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(newModel.value<QObject*>())) {
+ m_hasNativeModel = true;
+ connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SIGNAL(rebuildMenu()));
+ } else if (newModel.canConvert(QVariant::StringList)) {
+ m_hasNativeModel = true;
+ }
+ emit modelChanged(m_model);
+ }
+}