Commit dde8ef0c authored by Thomas Hartmann's avatar Thomas Hartmann

QmlDesigner.model: adding generic context menu in QmlModelView

Change-Id: I210199ecb26db65416ff147da2f12aa5e775d3fd
Reviewed-on: http://codereview.qt.nokia.com/789Reviewed-by: default avatarQt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: default avatarThomas Hartmann <Thomas.Hartmann@nokia.com>
parent 51d5e232
......@@ -75,7 +75,8 @@ SOURCES += $$PWD/model/abstractview.cpp \
$$PWD/model/rewriteactioncompressor.cpp \
$$PWD/model/qmltextgenerator.cpp \
$$PWD/model/modelmerger.cpp \
$$PWD/exceptions/rewritingexception.cpp
$$PWD/exceptions/rewritingexception.cpp \
$$PWD/model/modelnodecontextmenu.cpp
HEADERS += $$PWD/include/corelib_global.h \
$$PWD/include/abstractview.h \
......@@ -145,7 +146,8 @@ HEADERS += $$PWD/include/corelib_global.h \
$$PWD/include/modelmerger.h \
$$PWD/include/mathutils.h \
$$PWD/include/customnotifications.h \
$$PWD/include/rewritingexception.h
$$PWD/include/rewritingexception.h \
$$PWD//model/modelnodecontextmenu.h
contains(CONFIG, plugin) {
# If core.pri has been included in the qmldesigner plugin
......
......@@ -34,6 +34,7 @@
#define QMLMODELVIEW_H
#include <corelib_global.h>
#include <QPoint>
#include <abstractview.h>
#include "qmlitemnode.h"
#include "qmlstate.h"
......@@ -121,6 +122,8 @@ public:
void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports);
void nodeSourceChanged(const ModelNode &modelNode, const QString &newNodeSource);
void showContextMenu(const QPoint &globalPos, const QPoint &scenePos, bool showSelection);
protected:
NodeInstance instanceForModelNode(const ModelNode &modelNode);
bool hasInstanceForModelNode(const ModelNode &modelNode);
......
#include "modelnodecontextmenu.h"
#include <QApplication>
#include <coreplugin/editormanager/editormanager.h>
#include <nodeabstractproperty.h>
#include <nodelistproperty.h>
#include <nodemetainfo.h>
#include <modelnode.h>
#include <qmlitemnode.h>
#include <variantproperty.h>
#include <nodeproperty.h>
#include <rewritertransaction.h>
#include <designdocumentcontroller.h>
namespace QmlDesigner {
static inline QString captionForModelNode(const ModelNode &modelNode)
{
if (modelNode.id().isEmpty())
return modelNode.simplifiedTypeName();
return modelNode.id();
}
static inline bool contains(const QmlItemNode &node, const QPoint &p)
{
return node.instanceSceneTransform().mapRect(node.instanceBoundingRect()).contains(p);
}
static inline bool checkIfNodeIsAView(const ModelNode &node)
{
return node.metaInfo().isValid() &&
(node.metaInfo().isSubclassOf("QtQuick.ListView", -1, -1) ||
node.metaInfo().isSubclassOf("QtQuick.GridView", -1, -1) ||
node.metaInfo().isSubclassOf("QtQuick.PathView", -1, -1));
}
static inline QList<QmlItemNode> siblingsForNode(const QmlItemNode &itemNode)
{
QList<QmlItemNode> siblingList;
if (itemNode.isValid() && itemNode.modelNode().parentProperty().isValid()) {
QList<ModelNode> modelNodes = itemNode.modelNode().parentProperty().parentModelNode().allDirectSubModelNodes();
foreach (const ModelNode &node, modelNodes) {
QmlItemNode childItemNode = node;
if (childItemNode.isValid())
siblingList.append(childItemNode);
}
}
return siblingList;
}
static signed int getMaxZValue(const QList<QmlItemNode> &siblingList)
{
signed int maximum = INT_MIN;
foreach (const QmlItemNode &node, siblingList) {
signed int z = node.instanceValue("z").toInt();
if (z > maximum)
maximum = z;
}
return maximum;
}
static signed int getMinZValue(const QList<QmlItemNode> &siblingList)
{
signed int minimum = INT_MAX;
foreach (const QmlItemNode &node, siblingList) {
signed int z = node.instanceValue("z").toInt();
if (z < minimum)
minimum = z;
}
return minimum;
}
static inline bool modelNodeIsComponent(const ModelNode &node)
{
if (!node.isValid() || !node.metaInfo().isValid())
return false;
if (node.metaInfo().isComponent())
return true;
if (node.nodeSourceType() == ModelNode::ComponentSource)
return true;
if (checkIfNodeIsAView(node) &&
node.hasNodeProperty("delegate")) {
if (node.nodeProperty("delegate").modelNode().metaInfo().isComponent())
return true;
if (node.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::ComponentSource)
return true;
}
return false;
}
static inline bool isFileComponent(const ModelNode &node)
{
if (!node.isValid() || !node.metaInfo().isValid())
return false;
if (node.metaInfo().isComponent())
return true;
if (checkIfNodeIsAView(node) &&
node.hasNodeProperty("delegate")) {
if (node.nodeProperty("delegate").modelNode().metaInfo().isComponent())
return true;
}
return false;
}
static inline void openFileForComponent(const ModelNode &node)
{
if (node.metaInfo().isComponent()) {
Core::EditorManager::instance()->openEditor(node.metaInfo().componentFileName());
} else if (checkIfNodeIsAView(node) &&
node.hasNodeProperty("delegate") &&
node.nodeProperty("delegate").modelNode().metaInfo().isComponent()) {
Core::EditorManager::instance()->openEditor(node.nodeProperty("delegate").modelNode().metaInfo().componentFileName());
}
}
static inline void openInlineComponent(const ModelNode &node)
{
if (!node.isValid() || !node.metaInfo().isValid())
return;
if (!DesignDocumentController::instance())
return;
if (node.nodeSourceType() == ModelNode::ComponentSource)
DesignDocumentController::instance()->changeCurrentModelTo(node);
if (checkIfNodeIsAView(node) &&
node.hasNodeProperty("delegate")) {
if (node.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::ComponentSource)
DesignDocumentController::instance()->changeCurrentModelTo(node.nodeProperty("delegate").modelNode());
}
}
ModelNodeContextMenu::ModelNodeContextMenu(QmlModelView *view) : m_view(view)
{
}
void ModelNodeContextMenu::execute(const QPoint &pos, bool selectionMenuBool)
{
QMenu* menu = new QMenu();
bool singleSelected = false;
bool selectionIsEmpty = m_view->selectedModelNodes().isEmpty();
ModelNode currentSingleNode;
if (m_view->selectedModelNodes().count()== 1) {
singleSelected = true;
currentSingleNode = m_view->selectedModelNodes().first();
}
if (selectionMenuBool) {
QMenu *selectionMenu = new QMenu(QApplication::translate("ModelNodeContextMenu", "Selecion"), menu);
menu->addMenu(selectionMenu);
ModelNode parentNode;
if (singleSelected) {
//ModelNodeAction *selectionAction;
//selectionAction = createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "DeSelect: ") + captionForModelNode(currentSingleNode), selectionMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::DeSelectModelNode);
//selectionMenu->addAction(selectionAction);
if (!currentSingleNode.isRootNode()) {
parentNode = currentSingleNode.parentProperty().parentModelNode();
selectionMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Select parent: ") + captionForModelNode(parentNode),
selectionMenu, QList<ModelNode>() << parentNode, ModelNodeAction::SelectModelNode));
}
selectionMenu->addSeparator();
}
foreach (const ModelNode &node, m_view->allModelNodes()) {
if (node != currentSingleNode && node != parentNode && contains(node, m_scenePos) && !node.isRootNode())
selectionMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Select: ") + captionForModelNode(node), selectionMenu, QList<ModelNode>() << node, ModelNodeAction::SelectModelNode));
}
}
QMenu *stackMenu = new QMenu(QApplication::translate("ModelNodeContextMenu", "Stack (z)"), menu);
menu->addMenu(stackMenu);
stackMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "To Front"), stackMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::ToFront, singleSelected));
stackMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "To Back"), stackMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::ToBack, singleSelected));
stackMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Raise"), stackMenu, QList<ModelNode>() << m_view->selectedModelNodes(), ModelNodeAction::Raise));
stackMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Lower"), stackMenu, QList<ModelNode>() << m_view->selectedModelNodes(), ModelNodeAction::Lower));
stackMenu->addSeparator();
stackMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Reset z property"), stackMenu, QList<ModelNode>() << m_view->selectedModelNodes(), ModelNodeAction::ResetZ));
QMenu *editMenu = new QMenu(QApplication::translate("ModelNodeContextMenu", "Edit"), menu);
menu->addMenu(editMenu);
if (!selectionIsEmpty) {
//editMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Change Id"), editMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::SetId, singleSelected));
editMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Reset Position"), editMenu, m_view->selectedModelNodes(), ModelNodeAction::ResetPosition));
editMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Reset Size"), editMenu, m_view->selectedModelNodes(), ModelNodeAction::ResetSize));
editMenu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Visibility"), editMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::ModelNodeVisibility, singleSelected));
} else {
editMenu->setEnabled(false);
}
menu->addSeparator();
bool enterComponent = false;
if (singleSelected) {
enterComponent = modelNodeIsComponent(currentSingleNode);
}
menu->addAction(createModelNodeAction(QApplication::translate("ModelNodeContextMenu", "Go into Component"), editMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::EnterComponent, enterComponent));
menu->exec(pos);
menu->deleteLater();
}
void ModelNodeContextMenu::setScenePos(const QPoint &pos)
{
m_scenePos = pos;
}
ModelNodeAction* ModelNodeContextMenu::createModelNodeAction(const QString &description, QMenu *menu, const QList<ModelNode> &modelNodeList, ModelNodeAction::ModelNodeActionType type, bool enabled)
{
ModelNodeAction* action = new ModelNodeAction(description, menu, m_view, modelNodeList, type);
action->setEnabled(enabled);
return action;
}
ModelNodeAction::ModelNodeAction( const QString & text, QObject *parent, QmlModelView *view, const QList<ModelNode> &modelNodeList, ModelNodeActionType type) :
QAction(text, parent), m_view(view), m_modelNodeList(modelNodeList), m_type(type)
{
if (type == ModelNodeVisibility) {
setCheckable(true);
QmlItemNode itemNode = QmlItemNode(m_modelNodeList.first());
if (itemNode.isValid())
setChecked(itemNode.instanceValue("visible").toBool());
else
setEnabled(false);
}
connect(this, SIGNAL(triggered(bool)), this, SLOT(actionTriggered(bool)));
}
void ModelNodeAction::actionTriggered(bool b)
{
switch (m_type) {
case ModelNodeAction::SelectModelNode: select(); break;
case ModelNodeAction::DeSelectModelNode: deSelect(); break;
case ModelNodeAction::CutSelection: cut(); break;
case ModelNodeAction::CopySelection: copy(); break;
case ModelNodeAction::DeleteSelection: deleteSelection(); break;
case ModelNodeAction::ToFront: toFront(); break;
case ModelNodeAction::ToBack: toBack(); break;
case ModelNodeAction::Raise: raise(); break;
case ModelNodeAction::Lower: lower(); break;
case ModelNodeAction::Paste: paste(); break;
case ModelNodeAction::Undo: undo(); break;
case ModelNodeAction::Redo: redo(); break;
case ModelNodeAction::ModelNodeVisibility: setVisible(b); break;
case ModelNodeAction::ResetSize: resetSize(); break;
case ModelNodeAction::ResetPosition: resetPosition(); break;
case ModelNodeAction::EnterComponent: enterComponent(); break;
case ModelNodeAction::SetId: setId(); break;
case ModelNodeAction::ResetZ: resetZ(); break;
}
}
void ModelNodeAction::select()
{
if (m_view)
m_view->setSelectedModelNodes(m_modelNodeList);
}
void ModelNodeAction::deSelect()
{
if (m_view) {
QList<ModelNode> selectedNodes = m_view->selectedModelNodes();
foreach (const ModelNode &node, m_modelNodeList) {
if (selectedNodes.contains(node))
selectedNodes.removeAll(node);
}
m_view->setSelectedModelNodes(selectedNodes);
}
}
void ModelNodeAction::cut()
{
}
void ModelNodeAction::copy()
{
}
void ModelNodeAction::deleteSelection()
{
}
void ModelNodeAction::toFront()
{
if (!m_view)
return;
QmlItemNode node = m_modelNodeList.first();
if (node.isValid()) {
signed int maximumZ = getMaxZValue(siblingsForNode(node));
maximumZ++;
node.setVariantProperty("z", maximumZ);
}
}
void ModelNodeAction::toBack()
{
if (!m_view)
return;
QmlItemNode node = m_modelNodeList.first();
if (node.isValid()) {
signed int minimumZ = getMinZValue(siblingsForNode(node));
minimumZ--;
node.setVariantProperty("z", minimumZ);
}
}
void ModelNodeAction::raise()
{
if (!m_view)
return;
RewriterTransaction(m_view);
foreach (ModelNode modelNode, m_modelNodeList) {
QmlItemNode node = modelNode;
if (node.isValid()) {
signed int z = node.instanceValue("z").toInt();
z++;
node.setVariantProperty("z", z);
}
}
}
void ModelNodeAction::lower()
{
if (!m_view)
return;
RewriterTransaction(m_view);
foreach (ModelNode modelNode, m_modelNodeList) {
QmlItemNode node = modelNode;
if (node.isValid()) {
signed int z = node.instanceValue("z").toInt();
z--;
node.setVariantProperty("z", z);
}
}
}
void ModelNodeAction::paste()
{
}
void ModelNodeAction::undo()
{
}
void ModelNodeAction::redo()
{
}
void ModelNodeAction::setVisible(bool b)
{
m_modelNodeList.first().variantProperty("visible") = b;
}
void ModelNodeAction::resetSize()
{
if (!m_view)
return;
RewriterTransaction(m_view);
foreach (ModelNode node, m_modelNodeList) {
node.removeProperty("width");
node.removeProperty("height");
}
}
void ModelNodeAction::resetPosition()
{
if (!m_view)
return;
RewriterTransaction(m_view);
foreach (ModelNode node, m_modelNodeList) {
node.removeProperty("x");
node.removeProperty("y");
}
}
void ModelNodeAction::enterComponent()
{
const ModelNode node = m_modelNodeList.first();
if (node.isValid()) {
if (isFileComponent(node))
openFileForComponent(node);
else
openInlineComponent(node);
}
}
void ModelNodeAction::setId()
{
}
void ModelNodeAction::resetZ()
{
if (!m_view)
return;
RewriterTransaction(m_view);
foreach (ModelNode node, m_modelNodeList) {
node.removeProperty("z");
}
}
}
#ifndef MODELNODECONTEXTMENU_H
#define MODELNODECONTEXTMENU_H
#include <QObject>
#include <QPoint>
#include <QAction>
#include <QMenu>
#include <qmlmodelview.h>
namespace QmlDesigner {
class ModelNodeAction : public QAction
{
Q_OBJECT
public:
enum ModelNodeActionType {
SelectModelNode,
DeSelectModelNode,
CutSelection,
CopySelection,
DeleteSelection,
ToFront,
ToBack,
Raise,
Lower,
Paste,
Undo,
Redo,
ModelNodeVisibility,
ResetSize,
ResetPosition,
EnterComponent,
SetId,
ResetZ
};
ModelNodeAction( const QString & text, QObject *parent, QmlModelView *view, const QList<ModelNode> &modelNodeList, ModelNodeActionType type);
public slots:
void actionTriggered(bool);
private:
void select();
void deSelect();
void cut();
void copy();
void deleteSelection();
void toFront();
void toBack();
void raise();
void lower();
void paste();
void undo();
void redo();
void setVisible(bool);
void resetSize();
void resetPosition();
void enterComponent();
void setId();
void resetZ();
QmlModelView *m_view;
QList<ModelNode> m_modelNodeList;
ModelNodeActionType m_type;
};
class ModelNodeContextMenu
{
public:
ModelNodeContextMenu(QmlModelView *view);
void execute(const QPoint &pos, bool selecetionMenu);
void setScenePos(const QPoint &pos);
signals:
public slots:
private:
ModelNodeAction* createModelNodeAction(const QString &description, QMenu *menu, const QList<ModelNode> &modelNodeList, ModelNodeAction::ModelNodeActionType type, bool enabled = true);
QmlModelView *m_view;
QPoint m_scenePos;
};
};
#endif // MODELNODECONTEXTMENU_H
......@@ -48,6 +48,7 @@
#include "rewriterview.h"
#include "plaintexteditmodifier.h"
#include "modelmerger.h"
#include "modelnodecontextmenu.h"
namespace QmlDesigner {
......@@ -418,6 +419,13 @@ void QmlModelView::nodeSourceChanged(const ModelNode &, const QString & /*newNod
}
void QmlModelView::showContextMenu(const QPoint &globalPos, const QPoint &scenePos, bool showSelection)
{
ModelNodeContextMenu contextMenu(this);
contextMenu.setScenePos(scenePos);
contextMenu.execute(globalPos, showSelection);
}
void QmlModelView::rewriterBeginTransaction()
{
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment