diff options
author | Thomas Hartmann <Thomas.Hartmann@digia.com> | 2012-12-12 11:31:24 +0100 |
---|---|---|
committer | Thomas Hartmann <Thomas.Hartmann@digia.com> | 2012-12-20 17:03:45 +0100 |
commit | 6376b2bb463754e02900e54111a99463edc6a68b (patch) | |
tree | f684ff6e637a7b4cb1a16903eca1fec3c2604895 | |
parent | 9bfe944731408d5f67046fe4b215f4d4220d4322 (diff) | |
download | qt-creator-6376b2bb463754e02900e54111a99463edc6a68b.tar.gz |
QmlDesigner.ContextMenu: refactoring
Instead of a hardcoded context menu we now have
a DesignerActionManager that can be extended
by AbstractDesignerAction.
Change-Id: Ia0c5860e5fffea78fa89b74bda881076e53c059a
Reviewed-by: Marco Bubke <marco.bubke@digia.com>
14 files changed, 2158 insertions, 973 deletions
diff --git a/src/plugins/qmldesigner/components/componentcore/abstractdesigneraction.h b/src/plugins/qmldesigner/components/componentcore/abstractdesigneraction.h new file mode 100644 index 0000000000..2b14355cb5 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/abstractdesigneraction.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#ifndef ABSTRACTDESIGNERACTION_H +#define ABSTRACTDESIGNERACTION_H + +#include "componentcore_constants.h" +#include "selectioncontext.h" + +namespace QmlDesigner { + +class AbstractDesignerAction +{ +public: + enum Type { + Menu, + Action + }; + + enum Priorities { + HighestPriority = ComponentCoreConstants::priorityFirst, + CustomActionsPriority = ComponentCoreConstants::priorityCustomActions, + RefactoringActionsPriority = ComponentCoreConstants::priorityRefactoring, + LowestPriority = ComponentCoreConstants::priorityLast + }; + + virtual QAction *action() const = 0; + virtual QString category() const = 0; + virtual QString menuId() const = 0; + virtual int priority() const = 0; + virtual Type type() const = 0; + virtual void setCurrentContext(const SelectionContext &selectionState) = 0; + +protected: + virtual bool isVisible(const SelectionContext &selectionState) const = 0; + virtual bool isEnabled(const SelectionContext &selectionState) const = 0; +}; + +} //QmlDesigner + +#endif //ABSTRACTDESIGNERACTION_H diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore.pri b/src/plugins/qmldesigner/components/componentcore/componentcore.pri index 9035a629d7..271a585736 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore.pri +++ b/src/plugins/qmldesigner/components/componentcore/componentcore.pri @@ -1,5 +1,15 @@ VPATH += $$PWD INCLUDEPATH += $$PWD SOURCES += modelnodecontextmenu.cpp +SOURCES += modelnodecontextmenu_helper.cpp +SOURCES += selectioncontext.cpp +SOURCES += designeractionmanager.cpp +SOURCES += modelnodeoperations.cpp HEADERS += modelnodecontextmenu.h +HEADERS += modelnodecontextmenu_helper.h +HEADERS += selectioncontext.h +HEADERS += componentcore_constants.h +HEADERS += designeractionmanager.h +HEADERS += modelnodeoperations.h +HEADERS += abstractdesigneraction.h diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h new file mode 100644 index 0000000000..7db98802bc --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#ifndef COMPONENTCORE_CONSTANTS_H +#define COMPONENTCORE_CONSTANTS_H + +namespace QmlDesigner { + +namespace ComponentCoreConstants { + +const char rootCategory[] = ""; + +const char selectionCategory[] = "Selection"; +const char stackCategory[] = "Stack (z)"; +const char editCategory[] = "Edit"; +const char anchorsCategory[] = "Anchors"; +const char layoutCategory[] = "Layout"; + +const char selectionCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Selection"); +const char stackCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Stack (z)"); +const char editCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Edit"); +const char anchorsCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Anchors"); +const char layoutCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout"); + +const char selectParentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1"); +const char selectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1"); +const char deSelectDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "DeSelect: "); + +const char cutSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Cut"); +const char copySelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Copy"); +const char pasteSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Paste"); +const char deleteSelectionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Delete selection"); + +const char toFrontDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "To Front"); +const char toBackDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "To Back"); + +const char raiseDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Raise"); +const char lowerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Lower"); + +const char undoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Undo"); +const char redoDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Redo"); + +const char visibilityDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Visibility"); + +const char resetSizeDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset size"); +const char resetPositionDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset position"); + +const char goIntoComponentDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Go into Component"); + +const char setIdDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Set Id"); + +const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset z property"); + +const char anchorsFillDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill"); +const char anchorsResetDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Reset"); + +const char layoutColumnDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Column"); +const char layoutRowDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Row"); +const char layoutGridDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Grid"); +const char layoutFlowDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Flow"); + +const int priorityFirst = 220; +const int prioritySelectionCategory = 200; +const int priorityStackCategory = 180; +const int priorityEditCategory = 160; +const int priorityAnchorsCategory = 140; +const int priorityLayoutCategory = 120; +const int priorityTopLevelSeperator = 100; +const int priorityCustomActions = 80; +const int priorityRefactoring = 60; +const int priorityGoIntoComponent = 40; +const int priorityLast = 60; + +} //ComponentCoreConstants + +} //QmlDesigner + +#endif //COMPONENTCORE_CONSTANTS_H diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp new file mode 100644 index 0000000000..f032e48edc --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -0,0 +1,408 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "designeractionmanager.h" +#include "modelnodecontextmenu_helper.h" +#include "modelnodeoperations.h" +#include "componentcore_constants.h" +#include <nodeproperty.h> + +#include <QMenu> + +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 &position) +{ + return node.instanceSceneTransform().mapRect(node.instanceBoundingRect()).contains(position); +} + +namespace Internal { + +class DesignerActionManagerView : public QmlModelView +{ +public: + DesignerActionManagerView() : QmlModelView(0), m_isInRewriterTransaction(false), m_setupContextDirty(false) + {} + + void modelAttached(Model *model) + { + QmlModelView::modelAttached(model); + setupContext(); + } + + void modelAboutToBeDetached(Model *model) + { + QmlModelView::modelAboutToBeDetached(model); + setupContext(); + } + + virtual void nodeCreated(const ModelNode &) + { + setupContext(); + } + + virtual void nodeAboutToBeRemoved(const ModelNode &) + {} + + virtual void nodeRemoved(const ModelNode &, const NodeAbstractProperty &, PropertyChangeFlags) + { + setupContext(); + } + + virtual void nodeAboutToBeReparented(const ModelNode &, + const NodeAbstractProperty &, + const NodeAbstractProperty &, + AbstractView::PropertyChangeFlags ) + { + setupContext(); + } + + virtual void nodeReparented(const ModelNode &, const NodeAbstractProperty &, + const NodeAbstractProperty &, + AbstractView::PropertyChangeFlags) + { + setupContext(); + } + + virtual void nodeIdChanged(const ModelNode&, const QString&, const QString&) + {} + + virtual void propertiesAboutToBeRemoved(const QList<AbstractProperty>&) + {} + + virtual void propertiesRemoved(const QList<AbstractProperty>&) + { + setupContext(); + } + + virtual void variantPropertiesChanged(const QList<VariantProperty>&, PropertyChangeFlags) + {} + + virtual void bindingPropertiesChanged(const QList<BindingProperty>&, PropertyChangeFlags) + {} + + virtual void rootNodeTypeChanged(const QString &, int , int ) + { + setupContext(); + } + + virtual void instancePropertyChange(const QList<QPair<ModelNode, QString> > &) + {} + + virtual void instancesCompleted(const QVector<ModelNode> &) + {} + + virtual void instanceInformationsChange(const QMultiHash<ModelNode, InformationName> &) + {} + + virtual void instancesRenderImageChanged(const QVector<ModelNode> &) + {} + + virtual void instancesPreviewImageChanged(const QVector<ModelNode> &) + {} + + virtual void instancesChildrenChanged(const QVector<ModelNode> &) + {} + + virtual void instancesToken(const QString &, int , const QVector<ModelNode> &) + {} + + virtual void nodeSourceChanged(const ModelNode &, const QString &) + {} + + virtual void rewriterBeginTransaction() + { + m_isInRewriterTransaction = true; + } + + virtual void rewriterEndTransaction() + { + m_isInRewriterTransaction = false; + + if (m_setupContextDirty) + setupContext(); + } + + virtual void actualStateChanged(const ModelNode &) + { + setupContext(); + } + + virtual void selectedNodesChanged(const QList<ModelNode> &, + const QList<ModelNode> &) + { + setupContext(); + } + + virtual void nodeOrderChanged(const NodeListProperty &, const ModelNode &, int ) + { + setupContext(); + } + + virtual void importsChanged(const QList<Import> &, const QList<Import> &) + { + setupContext(); + } + + virtual void scriptFunctionsChanged(const ModelNode &, const QStringList &) + {} + + void setDesignerActionList(const QList<AbstractDesignerAction* > &designerActionList) + { + m_designerActionList = designerActionList; + } + +protected: + void setupContext() + { + if (m_isInRewriterTransaction) { + m_setupContextDirty = true; + return; + } + SelectionContext selectionContext(this); + foreach (AbstractDesignerAction* action, m_designerActionList) { + action->setCurrentContext(selectionContext); + } + m_setupContextDirty = false; + } + + QList<AbstractDesignerAction* > m_designerActionList; + bool m_isInRewriterTransaction; + bool m_setupContextDirty; +}; + +} //Internal + +DesignerActionManager *DesignerActionManager::m_instance = 0; + +void DesignerActionManager::addDesignerAction(AbstractDesignerAction *newAction) +{ + instance()->addDesignerActionInternal(newAction); +} + +QList<AbstractDesignerAction* > DesignerActionManager::designerActions() +{ + return instance()->factoriesInternal(); +} + +QmlModelView *DesignerActionManager::view() +{ + return instance()->m_view.data(); +} + +template <class ACTION, + class ENABLED = SelectionContextFunctors::Always, + class VISIBILITY = SelectionContextFunctors::Always> +class VisiblityModelNodeActionFactory : public ModelNodeActionFactory<ACTION, ENABLED, VISIBILITY> +{ +public: + VisiblityModelNodeActionFactory(const QString &description, const QString &category, int priority) : + ModelNodeActionFactory<ACTION, ENABLED, VISIBILITY>(description, category, priority) + {} + virtual void updateContext() + { + m_action->setSelectionContext(m_selectionContext); + if (m_selectionContext.isValid()) { + m_action->setEnabled(isEnabled(m_selectionContext)); + m_action->setVisible(isVisible(m_selectionContext)); + + m_action->setCheckable(true); + QmlItemNode itemNode = QmlItemNode(m_selectionContext.currentSingleSelectedNode()); + if (itemNode.isValid()) + m_action->setChecked(itemNode.instanceValue("visible").toBool()); + else + m_action->setEnabled(false); + } + } +}; + +template <void (*T)(const SelectionContext &)> +struct Functor { + void operator() (const SelectionContext &selectionState) { T(selectionState); } +}; + +class SelectionModelNodeAction : public MenuDesignerAction<SelectionContextFunctors::Always, SelectionContextFunctors::SelectionEnabled> +{ +typedef ActionTemplate<Functor<ModelNodeOperations::select> > SelectionAction; +typedef QSharedPointer<SelectionAction> SelectionActionPtr; + +public: + SelectionModelNodeAction(const QString &displayName, const QString &menuId, int priority) : + MenuDesignerAction(displayName, menuId, priority) + {} + + virtual void updateContext() + { + m_menu->clear(); + if (m_selectionContext.isValid()) { + m_action->setEnabled(isEnabled(m_selectionContext)); + m_action->setVisible(isVisible(m_selectionContext)); + } else { + return; + } + if (m_action->isEnabled()) { + ModelNode parentNode; + if (m_selectionContext.singleSelected() && !m_selectionContext.currentSingleSelectedNode().isRootNode()) { + SelectionAction* selectionAction = new SelectionAction(QString()); + selectionAction->setParent(m_menu.data()); + + parentNode = m_selectionContext.currentSingleSelectedNode().parentProperty().parentModelNode(); + m_selectionContext.setTargetNode(parentNode); + selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg( + captionForModelNode(parentNode))); + selectionAction->setSelectionContext(m_selectionContext); + + m_menu->addAction(selectionAction); + } + foreach (const ModelNode &node, m_selectionContext.view()->allModelNodes()) { + if (node != m_selectionContext.currentSingleSelectedNode() + && node != parentNode + && contains(node, m_selectionContext.scenePos()) + && !node.isRootNode()) { + m_selectionContext.setTargetNode(node); + SelectionAction* selectionAction = + new SelectionAction(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1")).arg(captionForModelNode(node))); + selectionAction->setSelectionContext(m_selectionContext); + + m_menu->addAction(selectionAction); + } + } + } + } +}; + +char xProperty[] = "x"; +char yProperty[] = "y"; +char zProperty[] = "z"; +char widthProperty[] = "width"; +char heightProperty[] = "height"; + +void DesignerActionManager::createDefaultDesignerActions() +{ + typedef Functor<ModelNodeOperations::resetPosition> resetPositionFunctor; + + using namespace SelectionContextFunctors; + using namespace ComponentCoreConstants; + + typedef Not<SingleSelection> MultiSelection; + typedef And<SingleSelection, InBaseState> SingleSelection_And_InBaseState; + typedef And<MultiSelection, InBaseState> MultiSelection_And_InBaseState; + typedef Or<SelectionHasProperty<xProperty>, SelectionHasProperty<yProperty> > + SelectionHasPropertyX_Or_SelectionHasPropertyY; + typedef Or<SelectionHasProperty<widthProperty>, SelectionHasProperty<heightProperty> > + SelectionHasPropertyWidth_Or_SelectionHasPropertyHeight; + typedef And<SelectionHasSameParent, InBaseState> SelectionHasSameParent_And_InBaseState; + typedef And<SelectionHasSameParent_And_InBaseState, MultiSelection> SelectionCanBeLayouted; + + addDesignerAction(new SelectionModelNodeAction(selectionCategoryDisplayName, selectionCategory, prioritySelectionCategory)); + + addDesignerAction(new MenuDesignerAction<Always>(stackCategoryDisplayName, stackCategory, priorityStackCategory)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::toFront>, SingleSelection> + (toFrontDisplayName, stackCategory, 200)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::toBack>, SingleSelection> + (toBackDisplayName, stackCategory, 180)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::raise>, SelectionNotEmpty> + (raiseDisplayName, stackCategory, 160)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::lower>, SelectionNotEmpty> + (lowerDisplayName, stackCategory, 140)); + addDesignerAction(new SeperatorDesignerAction<>(stackCategory, 120)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::resetZ>, + And<SelectionNotEmpty, SelectionHasProperty<zProperty> > > + (resetZDisplayName, stackCategory, 100)); + + addDesignerAction(new MenuDesignerAction<SelectionNotEmpty>(editCategoryDisplayName, editCategory, priorityEditCategory)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::resetPosition>, + And<SelectionNotEmpty, SelectionHasPropertyWidth_Or_SelectionHasPropertyHeight> > + (resetPositionDisplayName, editCategory, 200)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::resetSize>, + And<SelectionNotEmpty, SelectionHasPropertyX_Or_SelectionHasPropertyY> > + (resetSizeDisplayName, editCategory, 180)); + addDesignerAction(new VisiblityModelNodeActionFactory<Functor<ModelNodeOperations::setVisible>, SingleSelectedItem> + (visibilityDisplayName, editCategory, 160)); + + addDesignerAction(new MenuDesignerAction<SingleSelection_And_InBaseState>(anchorsCategoryDisplayName, anchorsCategory, priorityAnchorsCategory)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::anchorsFill>, SingleSelectionItemNotAnchored> + (anchorsFillDisplayName, anchorsCategory, 200)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::anchorsReset>, + SingleSelectionItemIsAnchored>(anchorsResetDisplayName, anchorsCategory, 180)); + + addDesignerAction(new MenuDesignerAction<MultiSelection_And_InBaseState>(layoutCategoryDisplayName, layoutCategory, priorityLayoutCategory)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::layoutRow>, SelectionCanBeLayouted> + (layoutRowDisplayName, layoutCategory, 200)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::layoutColumn>, SelectionCanBeLayouted> + (layoutColumnDisplayName, layoutCategory, 180)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::layoutColumn>, SelectionCanBeLayouted> + (layoutGridDisplayName, layoutCategory, 160)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::layoutFlow>, SelectionCanBeLayouted> + (layoutFlowDisplayName, layoutCategory, 140)); + + addDesignerAction(new SeperatorDesignerAction<>(rootCategory, priorityTopLevelSeperator)); + addDesignerAction(new ModelNodeActionFactory<Functor<ModelNodeOperations::goIntoComponent>, + SelectionIsComponent>(goIntoComponentDisplayName, rootCategory, priorityGoIntoComponent)); +} + +DesignerActionManager *DesignerActionManager::instance() +{ + if (!m_instance) { + m_instance = new DesignerActionManager; + createDefaultDesignerActions(); + } + + return m_instance; +} + +void DesignerActionManager::addDesignerActionInternal(AbstractDesignerAction *newAction) +{ + m_designerActions.append(QSharedPointer<AbstractDesignerAction>(newAction)); + m_view->setDesignerActionList(designerActions()); +} + +QList<AbstractDesignerAction* > DesignerActionManager::factoriesInternal() const +{ + QList<AbstractDesignerAction* > list; + foreach (const QSharedPointer<AbstractDesignerAction> &pointer, m_designerActions) { + list.append(pointer.data()); + } + + return list; +} + +DesignerActionManager::DesignerActionManager() : m_view(new Internal::DesignerActionManagerView) +{ +} + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h new file mode 100644 index 0000000000..87a4c91140 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#ifndef DESIGNERACTIONMANAGER_H +#define DESIGNERACTIONMANAGER_H + +#include "abstractdesigneraction.h" +#include "qmlmodelview.h" + +#include <QScopedPointer> + +namespace QmlDesigner { + +namespace Internal { +class DesignerActionManagerView; +} + +class DesignerActionManager { +public: + static void addDesignerAction(AbstractDesignerAction *newAction); + static QList<AbstractDesignerAction* > designerActions(); + + static void createDefaultDesignerActions(); + static QmlModelView *view(); + +protected: + static DesignerActionManager *instance(); + void addDesignerActionInternal(AbstractDesignerAction *newAction); + QList<AbstractDesignerAction* > factoriesInternal() const; + DesignerActionManager(); + +private: + static DesignerActionManager *m_instance; + QList<QSharedPointer<AbstractDesignerAction> > m_designerActions; + QScopedPointer<Internal::DesignerActionManagerView> m_view; +}; + +} //QmlDesigner + +#endif //DESIGNERACTIONMANAGER_H diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp index 53e67a44c4..51750ac6e6 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.cpp @@ -27,8 +27,11 @@ ** ****************************************************************************/ -#include <cmath> #include "modelnodecontextmenu.h" +#include "modelnodecontextmenu_helper.h" +#include "designeractionmanager.h" + +#include <cmath> #include <QApplication> #include <QMessageBox> #include <coreplugin/editormanager/editormanager.h> @@ -45,935 +48,93 @@ #include <designmodewidget.h> #include <qmlanchors.h> -const QString auxDataString = QLatin1String("anchors_"); +#include <QSet> namespace QmlDesigner { -static inline DesignDocumentController* designDocumentController() -{ - return Internal::DesignModeWidget::instance()->currentDesignDocumentController(); -} - -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 bool isItem(const ModelNode &node) -{ - return node.isValid() && node.metaInfo().isValid() && node.metaInfo().isSubclassOf("QtQuick.Item", -1, -1); -} - -static inline bool itemsHaveSameParent(const QList<ModelNode> &siblingList) +ModelNodeContextMenu::ModelNodeContextMenu(QmlModelView *view) : + m_view(view), + m_selectionContext(view) { - if (siblingList.isEmpty()) - return false; - - - QmlItemNode item(siblingList.first()); - if (!item.isValid()) - return false; - - if (item.isRootModelNode()) - return false; - - QmlItemNode parent = item.instanceParent().toQmlItemNode(); - if (!parent.isValid()) - return false; - - foreach (const ModelNode &node, siblingList) { - QmlItemNode currentItem(node); - if (!currentItem.isValid()) - return false; - QmlItemNode currentParent = currentItem.instanceParent().toQmlItemNode(); - if (!currentParent.isValid()) - return false; - if (currentItem.instanceIsInPositioner()) - return false; - if (currentParent != parent) - return false; - } - return true; } -static inline QList<QmlItemNode> siblingsForNode(const QmlItemNode &itemNode) +static bool sortFunction(AbstractDesignerAction * abstractDesignerAction01, AbstractDesignerAction *abstractDesignerAction02) { - 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; + return abstractDesignerAction01->priority() > abstractDesignerAction02->priority(); } -static signed int getMaxZValue(const QList<QmlItemNode> &siblingList) +static QSet<AbstractDesignerAction* > findMembers(QSet<AbstractDesignerAction* > designerActionSet, + const QString &category) { - signed int maximum = INT_MIN; - foreach (const QmlItemNode &node, siblingList) { - signed int z = node.instanceValue("z").toInt(); - if (z > maximum) - maximum = z; - } - return maximum; -} + QSet<AbstractDesignerAction* > ret; -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; + foreach (AbstractDesignerAction* factory, designerActionSet) { + if (factory->category() == category) + ret.insert(factory); + } + return ret; } -static inline bool modelNodeIsComponent(const ModelNode &node) +void populateMenu(QSet<AbstractDesignerAction* > &abstractDesignerActions, + const QString &category, + QMenu* menu, + const SelectionContext &selectionContext) { - if (!node.isValid() || !node.metaInfo().isValid()) - return false; + QSet<AbstractDesignerAction* > matchingFactories = findMembers(abstractDesignerActions, category); - if (node.metaInfo().isComponent()) - return true; + abstractDesignerActions.subtract(matchingFactories); - if (node.nodeSourceType() == ModelNode::NodeWithComponentSource) - return true; - if (checkIfNodeIsAView(node) && - node.hasNodeProperty("delegate")) { - if (node.nodeProperty("delegate").modelNode().metaInfo().isComponent()) - return true; - if (node.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource) - return true; - } - - return false; -} + QList<AbstractDesignerAction* > matchingFactoriesList = matchingFactories.toList(); + qSort(matchingFactoriesList.begin(), matchingFactoriesList.end(), &sortFunction); -static inline bool isFileComponent(const ModelNode &node) -{ - if (!node.isValid() || !node.metaInfo().isValid()) - return false; + foreach (AbstractDesignerAction* designerAction, matchingFactoriesList) { + if (designerAction->type() == AbstractDesignerAction::Menu) { + designerAction->setCurrentContext(selectionContext); + QMenu *newMenu = designerAction->action()->menu(); + menu->addMenu(newMenu); - if (node.metaInfo().isComponent()) - return true; + //recurse - if (checkIfNodeIsAView(node) && - node.hasNodeProperty("delegate")) { - if (node.nodeProperty("delegate").modelNode().metaInfo().isComponent()) - return true; + populateMenu(abstractDesignerActions, designerAction->menuId(), newMenu, selectionContext); + } else if (designerAction->type() == AbstractDesignerAction::Action) { + QAction* action = designerAction->action(); + designerAction->setCurrentContext(selectionContext); + menu->addAction(action); + } } - - return false; -} - -static inline void getWidthHeight(const ModelNode &node, int &width, int &height) -{ - QmlItemNode itemNode(node); - if (itemNode.isValid()) { - width = itemNode.instanceValue("width").toInt(); - height = itemNode.instanceValue("height").toInt(); - } -} - -static inline void getProperties(const ModelNode node, QHash<QString, QVariant> &propertyHash) -{ - if (QmlObjectNode(node).isValid()) { - foreach (const QString &propertyName, node.propertyNames()) { - if (node.property(propertyName).isVariantProperty() || - (node.property(propertyName).isBindingProperty() && - !propertyName.contains(QLatin1String("anchors.")))) { - propertyHash.insert(propertyName, QmlObjectNode(node).instanceValue(propertyName)); - } - } - } - QmlItemNode itemNode(node); - if (itemNode.isValid()) { - propertyHash.insert(QLatin1String("width"), itemNode.instanceValue(QLatin1String("width"))); - propertyHash.insert(QLatin1String("height"), itemNode.instanceValue(QLatin1String("height"))); - propertyHash.remove(QLatin1String("x")); - propertyHash.remove(QLatin1String("y")); - propertyHash.remove(QLatin1String("rotation")); - propertyHash.remove(QLatin1String("opacity")); - } -} - -static inline void applyProperties(ModelNode &node, const QHash<QString, QVariant> &propertyHash) -{ - QHash<QString, QVariant> auxiliaryData = node.auxiliaryData(); - foreach (const QString propertyName, auxiliaryData.keys()) { - node.setAuxiliaryData(propertyName, QVariant()); - } - - QHashIterator<QString, QVariant> i(propertyHash); - while (i.hasNext()) { - i.next(); - if (i.key() == QLatin1String("width") || i.key() == QLatin1String("height")) { - node.setAuxiliaryData(i.key(), i.value()); - } else if (node.property(i.key()).isDynamic() && - node.property(i.key()).dynamicTypeName() == QLatin1String("alias") && - node.property(i.key()).isBindingProperty()) { - AbstractProperty targetProperty = node.bindingProperty(i.key()).resolveToProperty(); - if (targetProperty.isValid()) { - targetProperty.parentModelNode().setAuxiliaryData(targetProperty.name() + QLatin1String("@NodeInstance"), i.value()); - } - } else { - node.setAuxiliaryData(i.key() + QLatin1String("@NodeInstance"), i.value()); - } - } -} - -static inline void openFileForComponent(const ModelNode &node) -{ - //int width = 0; - //int height = 0; - QHash<QString, QVariant> propertyHash; - if (node.metaInfo().isComponent()) { - //getWidthHeight(node, width, height); - getProperties(node, propertyHash); - designDocumentController()->changeToExternalSubComponent(node.metaInfo().componentFileName()); - } else if (checkIfNodeIsAView(node) && - node.hasNodeProperty("delegate") && - node.nodeProperty("delegate").modelNode().metaInfo().isComponent()) { - //getWidthHeight(node, width, height); - getProperties(node, propertyHash); - designDocumentController()->changeToExternalSubComponent(node.nodeProperty("delegate").modelNode().metaInfo().componentFileName()); - } - ModelNode rootModelNode = designDocumentController()->model()->rewriterView()->rootModelNode(); - applyProperties(rootModelNode, propertyHash); - //rootModelNode.setAuxiliaryData("width", width); - //rootModelNode.setAuxiliaryData("height", height); -} - -static inline void openInlineComponent(const ModelNode &node) -{ - if (!node.isValid() || !node.metaInfo().isValid()) - return; - - if (!designDocumentController()) - return; - - //int width = 0; - //int height = 0; - QHash<QString, QVariant> propertyHash; - - if (node.nodeSourceType() == ModelNode::NodeWithComponentSource) { - //getWidthHeight(node, width, height); - getProperties(node, propertyHash); - designDocumentController()->changeToSubComponent(node); - } else if (checkIfNodeIsAView(node) && - node.hasNodeProperty("delegate")) { - if (node.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource) { - //getWidthHeight(node, width, height); - getProperties(node, propertyHash); - designDocumentController()->changeToSubComponent(node.nodeProperty("delegate").modelNode()); - } - } - - ModelNode rootModelNode = designDocumentController()->model()->rewriterView()->rootModelNode(); - applyProperties(rootModelNode, propertyHash); - //rootModelNode.setAuxiliaryData("width", width); - //rootModelNode.setAuxiliaryData("height", height); -} - -static inline bool modelNodesHaveProperty(const QList<ModelNode> &modelNodeList, const QString &propertyName) -{ - foreach (const ModelNode &modelNode, modelNodeList) - if (modelNode.hasProperty(propertyName)) - return true; - - return false; -} - -ModelNodeContextMenu::ModelNodeContextMenu(QmlModelView *view) : m_view(view) -{ } -void ModelNodeContextMenu::execute(const QPoint &pos, bool selectionMenuBool) +void ModelNodeContextMenu::execute(const QPoint &position, bool selectionMenuBool) { - QMenu* menu = new QMenu(); + QMenu* mainMenu = new QMenu(); - bool singleSelected = false; - bool selectionIsEmpty = m_view->selectedModelNodes().isEmpty(); - ModelNode currentSingleNode; - const bool isInBaseState = m_view->currentState().isBaseState(); - const QList<ModelNode> &selectedModelNodes = m_view->selectedModelNodes(); - if (selectedModelNodes.count()== 1) { - singleSelected = true; - currentSingleNode = selectedModelNodes.first(); - } - - if (selectionMenuBool) { - QMenu *selectionMenu = new QMenu(tr("Selection"), menu); - menu->addMenu(selectionMenu); - ModelNode parentNode; - if (singleSelected) { - //ModelNodeAction *selectionAction; - //selectionAction = createModelNodeAction(tr("DeSelect: ") + captionForModelNode(currentSingleNode), selectionMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::DeSelectModelNode); - //selectionMenu->addAction(selectionAction); - if (!currentSingleNode.isRootNode()) { - parentNode = currentSingleNode.parentProperty().parentModelNode(); - selectionMenu->addAction(createModelNodeAction(tr("Select parent: %1").arg(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(tr("Select: %1").arg(captionForModelNode(node)), selectionMenu, QList<ModelNode>() << node, ModelNodeAction::SelectModelNode)); - } - } - - QMenu *stackMenu = new QMenu(tr("Stack (z)"), menu); - menu->addMenu(stackMenu); - - stackMenu->addAction(createModelNodeAction(tr("To Front"), stackMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::ToFront, singleSelected)); - stackMenu->addAction(createModelNodeAction(tr("To Back"), stackMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::ToBack, singleSelected)); - stackMenu->addAction(createModelNodeAction(tr("Raise"), stackMenu, QList<ModelNode>() << selectedModelNodes, ModelNodeAction::Raise)); - stackMenu->addAction(createModelNodeAction(tr("Lower"), stackMenu, QList<ModelNode>() << selectedModelNodes, ModelNodeAction::Lower)); - stackMenu->addSeparator(); - stackMenu->addAction(createModelNodeAction(tr("Reset z property"), stackMenu, QList<ModelNode>() << selectedModelNodes, ModelNodeAction::ResetZ)); - - QMenu *editMenu = new QMenu(tr("Edit"), menu); - menu->addMenu(editMenu); - if (!selectionIsEmpty) { - //editMenu->addAction(createModelNodeAction(tr("Change Id"), editMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::SetId, singleSelected)); - ModelNodeAction* action = createModelNodeAction(tr("Reset Position"), editMenu, selectedModelNodes, ModelNodeAction::ResetPosition); - if (!modelNodesHaveProperty(selectedModelNodes, QLatin1String("x")) && !modelNodesHaveProperty(selectedModelNodes, QLatin1String("y"))) - action->setEnabled(false); - editMenu->addAction(action); - action = createModelNodeAction(tr("Reset Size"), editMenu, selectedModelNodes, ModelNodeAction::ResetSize); - if (!modelNodesHaveProperty(selectedModelNodes, QLatin1String("width")) && !modelNodesHaveProperty(selectedModelNodes, QLatin1String("height"))) - action->setEnabled(false); - editMenu->addAction(action); - action = createModelNodeAction(tr("Visibility"), editMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::ModelNodeVisibility, singleSelected); - editMenu->addAction(action); - if (singleSelected && !isItem(currentSingleNode)) - action->setEnabled(false); - - } else { - editMenu->setEnabled(false); - } - - QMenu *anchorMenu = new QMenu(tr("Anchors"), menu); - menu->addMenu(anchorMenu); - - - if (singleSelected && isInBaseState) { - QmlItemNode itemNode(currentSingleNode); - - bool anchored = itemNode.instanceHasAnchors(); - bool isRootNode = itemNode.isRootNode(); - - ModelNodeAction *action = createModelNodeAction(tr("Fill"), anchorMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::AnchorFill, !anchored && !isRootNode); - anchorMenu->addAction(action); - action = createModelNodeAction(tr("Reset"), anchorMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::AnchorReset, anchored && !isRootNode); - anchorMenu->addAction(action); - } else { - anchorMenu->setEnabled(false); - } - - QMenu *layoutMenu = new QMenu(tr("Layout"), menu); - menu->addMenu(layoutMenu); - - bool layoutingIsPossible = itemsHaveSameParent(selectedModelNodes) && isInBaseState; - - if (!singleSelected && !selectionIsEmpty && layoutingIsPossible) { + m_selectionContext.setShowSelectionTools(selectionMenuBool); + m_selectionContext.setScenePos(m_scenePos); - ModelNodeAction *action = createModelNodeAction(tr("Layout in Row"), layoutMenu, selectedModelNodes, ModelNodeAction::LayoutRow, true); - layoutMenu->addAction(action); - action = createModelNodeAction(tr("Layout in Column"), layoutMenu, selectedModelNodes, ModelNodeAction::LayoutColumn, true); - layoutMenu->addAction(action); - action = createModelNodeAction(tr("Layout in Grid"), layoutMenu, selectedModelNodes, ModelNodeAction::LayoutGrid, true); - layoutMenu->addAction(action); - action = createModelNodeAction(tr("Layout in Flow"), layoutMenu, selectedModelNodes, ModelNodeAction::LayoutFlow, true); - layoutMenu->addAction(action); - - } else { - layoutMenu->setEnabled(false); - } + QSet<AbstractDesignerAction* > factories = + QSet<AbstractDesignerAction* >::fromList(DesignerActionManager::designerActions()); - menu->addSeparator(); - bool enterComponent = false; - if (singleSelected) { - enterComponent = modelNodeIsComponent(currentSingleNode); - } - menu->addAction(createModelNodeAction(tr("Go into Component"), editMenu, QList<ModelNode>() << currentSingleNode, ModelNodeAction::GoIntoComponent, enterComponent)); + populateMenu(factories, QString(""), mainMenu, m_selectionContext); - menu->exec(pos); - menu->deleteLater(); + mainMenu->exec(position); + mainMenu->deleteLater(); } -void ModelNodeContextMenu::setScenePos(const QPoint &pos) +void ModelNodeContextMenu::setScenePos(const QPoint &position) { - m_scenePos = pos; + m_scenePos = position; } -void ModelNodeContextMenu::showContextMenu(QmlModelView *view, const QPoint &globalPosition, const QPoint &scenePosition, bool showSelection) +void ModelNodeContextMenu::showContextMenu(QmlModelView *view, + const QPoint &globalPosition, + const QPoint &scenePosition, + bool showSelection) { ModelNodeContextMenu contextMenu(view); contextMenu.setScenePos(scenePosition); contextMenu.execute(globalPosition, showSelection); } -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::goIntoComponent(const ModelNode &modelNode) -{ - - if (modelNode.isValid() && modelNodeIsComponent(modelNode)) { - if (isFileComponent(modelNode)) - openFileForComponent(modelNode); - else - openInlineComponent(modelNode); - } -} - -void ModelNodeAction::actionTriggered(bool b) -{ - try { - 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::GoIntoComponent: goIntoComponent(); break; - case ModelNodeAction::SetId: setId(); break; - case ModelNodeAction::ResetZ: resetZ(); break; - case ModelNodeAction::AnchorFill: anchorsFill(); break; - case ModelNodeAction::AnchorReset: anchorsReset(); break; - case ModelNodeAction::LayoutColumn: layoutColumn(); break; - case ModelNodeAction::LayoutRow: layoutRow(); break; - case ModelNodeAction::LayoutGrid: layoutGrid(); break; - case ModelNodeAction::LayoutFlow: layoutFlow(); break; - } - } catch (RewritingException e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - -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; - - try { - QmlItemNode node = m_modelNodeList.first(); - if (node.isValid()) { - signed int maximumZ = getMaxZValue(siblingsForNode(node)); - maximumZ++; - node.setVariantProperty("z", maximumZ); - } - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - - -void ModelNodeAction::toBack() -{ - if (!m_view) - return; - try { - QmlItemNode node = m_modelNodeList.first(); - if (node.isValid()) { - signed int minimumZ = getMinZValue(siblingsForNode(node)); - minimumZ--; - node.setVariantProperty("z", minimumZ); - } - - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - -void ModelNodeAction::raise() -{ - if (!m_view) - return; - - try { - RewriterTransaction transaction(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); - } - } - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - -void ModelNodeAction::lower() -{ - if (!m_view) - return; - try { - RewriterTransaction transaction(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); - } - } - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - -void ModelNodeAction::paste() -{ -} - -void ModelNodeAction::undo() -{ -} - -void ModelNodeAction::redo() -{ -} - -void ModelNodeAction::setVisible(bool b) -{ - if (!m_view) - return; - try { - m_modelNodeList.first().variantProperty("visible") = b; - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - - -void ModelNodeAction::resetSize() -{ - if (!m_view) - return; - try { - RewriterTransaction transaction(m_view); - foreach (ModelNode node, m_modelNodeList) { - node.removeProperty("width"); - node.removeProperty("height"); - } - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - -void ModelNodeAction::resetPosition() -{ - if (!m_view) - return; - try { - RewriterTransaction transaction(m_view); - foreach (ModelNode node, m_modelNodeList) { - node.removeProperty("x"); - node.removeProperty("y"); - } - } catch (RewritingException &e) { //better save then sorry - QMessageBox::warning(0, "Error", e.description()); - } -} - -void ModelNodeAction::goIntoComponent() -{ - goIntoComponent(m_modelNodeList.first()); -} - -void ModelNodeAction::setId() -{ -} - -void ModelNodeAction::resetZ() -{ - if (!m_view) - return; - - RewriterTransaction transaction(m_view); - foreach (ModelNode node, m_modelNodeList) { - node.removeProperty("z"); - } -} - -static inline void backupPropertyAndRemove(ModelNode node, const QString &propertyName) -{ - if (node.hasVariantProperty(propertyName)) { - node.setAuxiliaryData(auxDataString + propertyName, node.variantProperty(propertyName).value()); - node.removeProperty(propertyName); - - } - if (node.hasBindingProperty(propertyName)) { - node.setAuxiliaryData(auxDataString + propertyName, QmlItemNode(node).instanceValue(propertyName)); - node.removeProperty(propertyName); - } -} - - -static inline void restoreProperty(ModelNode node, const QString &propertyName) -{ - if (node.hasAuxiliaryData(auxDataString + propertyName)) - node.variantProperty(propertyName) = node.auxiliaryData(auxDataString + propertyName); -} - -void ModelNodeAction::anchorsFill() -{ - if (!m_view) - return; - - RewriterTransaction transaction(m_view); - - foreach (ModelNode modelNode, m_modelNodeList) { - QmlItemNode node = modelNode; - if (node.isValid()) { - node.anchors().fill(); - backupPropertyAndRemove(modelNode, QLatin1String("x")); - backupPropertyAndRemove(modelNode, QLatin1String("y")); - backupPropertyAndRemove(modelNode, QLatin1String("width")); - backupPropertyAndRemove(modelNode, QLatin1String("height")); - } - } -} - -void ModelNodeAction::anchorsReset() -{ - if (!m_view) - return; - RewriterTransaction transaction(m_view); - - foreach (ModelNode modelNode, m_modelNodeList) { - QmlItemNode node = modelNode; - if (node.isValid()) { - node.anchors().removeAnchors(); - node.anchors().removeMargins(); - restoreProperty(node, "x"); - restoreProperty(node, "y"); - restoreProperty(node, "width"); - restoreProperty(node, "height"); - } - } -} - -static inline void reparentTo(const ModelNode &node, const QmlItemNode &parent) -{ - - if (parent.isValid() && node.isValid()) { - NodeAbstractProperty parentProperty; - - if (parent.hasDefaultProperty()) { - parentProperty = parent.nodeAbstractProperty(parent.defaultProperty()); - } else { - parentProperty = parent.nodeAbstractProperty(QLatin1String("data")); - } - - parentProperty.reparentHere(node); - } -} - - -bool compareByX(const ModelNode &node1, const ModelNode &node2) -{ - QmlItemNode itemNode1 = QmlItemNode(node1); - QmlItemNode itemNode2 = QmlItemNode(node2); - if (itemNode1.isValid() && itemNode2.isValid()) - return itemNode1.instancePosition().x() < itemNode2.instancePosition().x(); - return false; -} - -bool compareByY(const ModelNode &node1, const ModelNode &node2) -{ - QmlItemNode itemNode1 = QmlItemNode(node1); - QmlItemNode itemNode2 = QmlItemNode(node2); - if (itemNode1.isValid() && itemNode2.isValid()) - return itemNode1.instancePosition().y() < itemNode2.instancePosition().y(); - return false; -} - -bool compareByGrid(const ModelNode &node1, const ModelNode &node2) -{ - QmlItemNode itemNode1 = QmlItemNode(node1); - QmlItemNode itemNode2 = QmlItemNode(node2); - if (itemNode1.isValid() && itemNode2.isValid()) { - if ((itemNode1.instancePosition().y() + itemNode1.instanceSize().height()) < itemNode2.instancePosition().y()) - return true; - if ((itemNode2.instancePosition().y() + itemNode2.instanceSize().height()) < itemNode1.instancePosition().y()) - return false; //first sort y (rows) - return itemNode1.instancePosition().x() < itemNode2.instancePosition().x(); - } - return false; -} - -static inline QPoint getUpperLeftPosition(const QList<ModelNode> &modelNodeList) -{ - QPoint p(INT_MAX, INT_MAX); - foreach (ModelNode modelNode, modelNodeList) { - QmlItemNode itemNode = QmlItemNode(modelNode); - if (itemNode.isValid()) { - if (itemNode.instancePosition().x() < p.x()) - p.setX(itemNode.instancePosition().x()); - if (itemNode.instancePosition().y() < p.y()) - p.setY(itemNode.instancePosition().y()); - } - - } - return p; -} - -void ModelNodeAction::layoutRow() -{ - if (!m_view) - return; - - NodeMetaInfo rowMetaInfo = m_view->model()->metaInfo(QLatin1String("QtQuick.Row")); - - if (!rowMetaInfo.isValid()) - return; - - ModelNode row; - { - RewriterTransaction transaction(m_view); - - QmlItemNode parent = QmlItemNode(m_modelNodeList.first()).instanceParent().toQmlItemNode(); - if (!parent.isValid()) - return; - - qDebug() << parent.modelNode().majorQtQuickVersion(); - - row = m_view->createModelNode(QLatin1String("QtQuick.Row"), rowMetaInfo.majorVersion(), rowMetaInfo.minorVersion()); - - reparentTo(row, parent); - } - - { - RewriterTransaction transaction(m_view); - - QPoint pos = getUpperLeftPosition(m_modelNodeList); - row.variantProperty(QLatin1String("x")) = pos.x(); - row.variantProperty(QLatin1String("y")) = pos.y(); - - QList<ModelNode> sortedList = m_modelNodeList; - qSort(sortedList.begin(), sortedList.end(), compareByX); - - foreach (ModelNode modelNode, sortedList) { - reparentTo(modelNode, row); - modelNode.removeProperty(QLatin1String("x")); - modelNode.removeProperty(QLatin1String("y")); - } - } -} - -void ModelNodeAction::layoutColumn() -{ - if (!m_view) - return; - - NodeMetaInfo columnMetaInfo = m_view->model()->metaInfo(QLatin1String("QtQuick.Column")); - - if (!columnMetaInfo.isValid()) - return; - - ModelNode column; - { - RewriterTransaction transaction(m_view); - - QmlItemNode parent = QmlItemNode(m_modelNodeList.first()).instanceParent().toQmlItemNode(); - if (!parent.isValid()) - return; - - column = m_view->createModelNode(QLatin1String("QtQuick.Column"), columnMetaInfo.majorVersion(), columnMetaInfo.minorVersion()); - - reparentTo(column, parent); - } - - { - RewriterTransaction transaction(m_view); - - QPoint pos = getUpperLeftPosition(m_modelNodeList); - column.variantProperty(QLatin1String("x")) = pos.x(); - column.variantProperty(QLatin1String("y")) = pos.y(); - - QList<ModelNode> sortedList = m_modelNodeList; - qSort(sortedList.begin(), sortedList.end(), compareByY); - - foreach (ModelNode modelNode, sortedList) { - reparentTo(modelNode, column); - modelNode.removeProperty(QLatin1String("x")); - modelNode.removeProperty(QLatin1String("y")); - } - } -} - -void ModelNodeAction::layoutGrid() -{ - if (!m_view) - return; - - NodeMetaInfo gridMetaInfo = m_view->model()->metaInfo(QLatin1String("QtQuick.Grid")); - - if (!gridMetaInfo.isValid()) - return; - - ModelNode grid; - { - RewriterTransaction transaction(m_view); - - QmlItemNode parent = QmlItemNode(m_modelNodeList.first()).instanceParent().toQmlItemNode(); - if (!parent.isValid()) - return; - - grid = m_view->createModelNode(QLatin1String("QtQuick.Grid"), gridMetaInfo.majorVersion(), gridMetaInfo.minorVersion()); - grid.variantProperty(QLatin1String("columns")) = int(sqrt(double(m_modelNodeList.count()))); - - reparentTo(grid, parent); - } - - { - RewriterTransaction transaction(m_view); - - QPoint pos = getUpperLeftPosition(m_modelNodeList); - grid.variantProperty(QLatin1String("x")) = pos.x(); - grid.variantProperty(QLatin1String("y")) = pos.y(); - - QList<ModelNode> sortedList = m_modelNodeList; - qSort(sortedList.begin(), sortedList.end(), compareByGrid); - - foreach (ModelNode modelNode, sortedList) { - reparentTo(modelNode, grid); - modelNode.removeProperty(QLatin1String("x")); - modelNode.removeProperty(QLatin1String("y")); - } - } -} - -void ModelNodeAction::layoutFlow() -{ - if (!m_view) - return; - - NodeMetaInfo flowMetaInfo = m_view->model()->metaInfo(QLatin1String("QtQuick.Flow")); - - if (!flowMetaInfo.isValid()) - return; - - ModelNode flow; - { - RewriterTransaction transaction(m_view); - - QmlItemNode parent = QmlItemNode(m_modelNodeList.first()).instanceParent().toQmlItemNode(); - if (!parent.isValid()) - return; - - flow = m_view->createModelNode(QLatin1String("QtQuick.Flow"), flowMetaInfo.majorVersion(), flowMetaInfo.minorVersion()); - - reparentTo(flow, parent); - } - - { - RewriterTransaction transaction(m_view); - - QPoint pos = getUpperLeftPosition(m_modelNodeList); - flow.variantProperty(QLatin1String("x")) = pos.x(); - flow.variantProperty(QLatin1String("y")) = pos.y(); - - QList<ModelNode> sortedList = m_modelNodeList; - qSort(sortedList.begin(), sortedList.end(), compareByGrid); - - foreach (ModelNode modelNode, sortedList) { - reparentTo(modelNode, flow); - modelNode.removeProperty(QLatin1String("x")); - modelNode.removeProperty(QLatin1String("y")); - } - } -} - -} +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.h index 6aa11aa750..869890735c 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu.h @@ -30,85 +30,14 @@ #ifndef MODELNODECONTEXTMENU_H #define MODELNODECONTEXTMENU_H -#include <QObject> #include <QPoint> -#include <QAction> #include <QCoreApplication> -#include <QMenu> + #include <qmlmodelview.h> +#include "selectioncontext.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, - GoIntoComponent, - SetId, - ResetZ, - AnchorReset, - AnchorFill, - LayoutRow, - LayoutColumn, - LayoutGrid, - LayoutFlow - }; - - - ModelNodeAction( const QString & text, QObject *parent, QmlModelView *view, const QList<ModelNode> &modelNodeList, ModelNodeActionType type); - - static void goIntoComponent(const ModelNode &modelNode); - -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 goIntoComponent(); - void setId(); - void resetZ(); - void anchorsFill(); - void anchorsReset(); - void layoutRow(); - void layoutColumn(); - void layoutGrid(); - void layoutFlow(); - - QmlModelView *m_view; - QList<ModelNode> m_modelNodeList; - ModelNodeActionType m_type; -}; - class ModelNodeContextMenu { Q_DECLARE_TR_FUNCTIONS(QmlDesigner::ModelNodeContextMenu) @@ -120,14 +49,11 @@ public: static void showContextMenu(QmlModelView *view, const QPoint &globalPosition, const QPoint &scenePosition, bool showSelection); private: - ModelNodeAction* createModelNodeAction(const QString &description, QMenu *menu, const QList<ModelNode> &modelNodeList, ModelNodeAction::ModelNodeActionType type, bool enabled = true); - QmlModelView *m_view; QPoint m_scenePos; - + SelectionContext m_selectionContext; }; - -}; +}; //QmlDesigner #endif // MODELNODECONTEXTMENU_H diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp new file mode 100644 index 0000000000..cdaaf86900 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.cpp @@ -0,0 +1,266 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "modelnodecontextmenu_helper.h" + +#include <nodemetainfo.h> +#include <modelnode.h> +#include <qmlitemnode.h> +#include <bindingproperty.h> +#include <nodeproperty.h> +#include <designmodewidget.h> + +namespace QmlDesigner { + +static inline DesignDocumentController* designDocumentController() +{ + return Internal::DesignModeWidget::instance()->currentDesignDocumentController(); +} + +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 void getProperties(const ModelNode node, QHash<QString, QVariant> &propertyHash) +{ + if (QmlObjectNode(node).isValid()) { + foreach (const QString &propertyName, node.propertyNames()) { + if (node.property(propertyName).isVariantProperty() || + (node.property(propertyName).isBindingProperty() && + !propertyName.contains(QLatin1String("anchors.")))) { + propertyHash.insert(propertyName, QmlObjectNode(node).instanceValue(propertyName)); + } + } + } + QmlItemNode itemNode(node); + if (itemNode.isValid()) { + propertyHash.insert(QLatin1String("width"), itemNode.instanceValue(QLatin1String("width"))); + propertyHash.insert(QLatin1String("height"), itemNode.instanceValue(QLatin1String("height"))); + propertyHash.remove(QLatin1String("x")); + propertyHash.remove(QLatin1String("y")); + propertyHash.remove(QLatin1String("rotation")); + propertyHash.remove(QLatin1String("opacity")); + } +} + +static inline void applyProperties(ModelNode &node, const QHash<QString, QVariant> &propertyHash) +{ + QHash<QString, QVariant> auxiliaryData = node.auxiliaryData(); + foreach (const QString propertyName, auxiliaryData.keys()) { + node.setAuxiliaryData(propertyName, QVariant()); + } + + QHashIterator<QString, QVariant> propertyIterator(propertyHash); + while (propertyIterator.hasNext()) { + propertyIterator.next(); + const QString propertyName = propertyIterator.key(); + if (propertyName == QLatin1String("width") || propertyName == QLatin1String("height")) { + node.setAuxiliaryData(propertyIterator.key(), propertyIterator.value()); + } else if (node.property(propertyIterator.key()).isDynamic() && + node.property(propertyIterator.key()).dynamicTypeName() == QLatin1String("alias") && + node.property(propertyIterator.key()).isBindingProperty()) { + AbstractProperty targetProperty = node.bindingProperty(propertyIterator.key()).resolveToProperty(); + if (targetProperty.isValid()) { + targetProperty.parentModelNode().setAuxiliaryData(targetProperty.name() + QLatin1String("@NodeInstance"), propertyIterator.value()); + } + } else { + node.setAuxiliaryData(propertyIterator.key() + QLatin1String("@NodeInstance"), propertyIterator.value()); + } + } +} + +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::NodeWithComponentSource) + return true; + if (checkIfNodeIsAView(node) && + node.hasNodeProperty("delegate")) { + if (node.nodeProperty("delegate").modelNode().metaInfo().isComponent()) + return true; + if (node.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource) + return true; + } + + return false; +} + +static inline bool itemsHaveSameParent(const QList<ModelNode> &siblingList) +{ + if (siblingList.isEmpty()) + return false; + + + QmlItemNode item(siblingList.first()); + if (!item.isValid()) + return false; + + if (item.isRootModelNode()) + return false; + + QmlItemNode parent = item.instanceParent().toQmlItemNode(); + if (!parent.isValid()) + return false; + + foreach (const ModelNode &node, siblingList) { + QmlItemNode currentItem(node); + if (!currentItem.isValid()) + return false; + QmlItemNode currentParent = currentItem.instanceParent().toQmlItemNode(); + if (!currentParent.isValid()) + return false; + if (currentItem.instanceIsInPositioner()) + return false; + if (currentParent != parent) + return false; + } + return true; +} + +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) +{ + //int width = 0; + //int height = 0; + QHash<QString, QVariant> propertyHash; + if (node.metaInfo().isComponent()) { + //getWidthHeight(node, width, height); + getProperties(node, propertyHash); + designDocumentController()->changeToExternalSubComponent(node.metaInfo().componentFileName()); + } else if (checkIfNodeIsAView(node) && + node.hasNodeProperty("delegate") && + node.nodeProperty("delegate").modelNode().metaInfo().isComponent()) { + //getWidthHeight(node, width, height); + getProperties(node, propertyHash); + designDocumentController()->changeToExternalSubComponent(node.nodeProperty("delegate").modelNode().metaInfo().componentFileName()); + } + ModelNode rootModelNode = designDocumentController()->model()->rewriterView()->rootModelNode(); + applyProperties(rootModelNode, propertyHash); + //rootModelNode.setAuxiliaryData("width", width); + //rootModelNode.setAuxiliaryData("height", height); +} + +static inline void openInlineComponent(const ModelNode &node) +{ + if (!node.isValid() || !node.metaInfo().isValid()) + return; + + if (!designDocumentController()) + return; + + QHash<QString, QVariant> propertyHash; + + if (node.nodeSourceType() == ModelNode::NodeWithComponentSource) { + //getWidthHeight(node, width, height); + getProperties(node, propertyHash); + designDocumentController()->changeToSubComponent(node); + } else if (checkIfNodeIsAView(node) && + node.hasNodeProperty("delegate")) { + if (node.nodeProperty("delegate").modelNode().nodeSourceType() == ModelNode::NodeWithComponentSource) { + //getWidthHeight(node, width, height); + getProperties(node, propertyHash); + designDocumentController()->changeToSubComponent(node.nodeProperty("delegate").modelNode()); + } + } + + ModelNode rootModelNode = designDocumentController()->model()->rewriterView()->rootModelNode(); + applyProperties(rootModelNode, propertyHash); + //rootModelNode.setAuxiliaryData("width", width); + //rootModelNode.setAuxiliaryData("height", height); +} + +void ComponentUtils::goIntoComponent(const ModelNode &modelNode) +{ + + if (modelNode.isValid() && modelNodeIsComponent(modelNode)) { + if (isFileComponent(modelNode)) + openFileForComponent(modelNode); + else + openInlineComponent(modelNode); + } +} + +namespace SelectionContextFunctors { + +bool SingleSelectionItemIsAnchored::operator() (const SelectionContext &selectionState) { + QmlItemNode itemNode(selectionState.currentSingleSelectedNode()); + if (selectionState.isInBaseState() && itemNode.isValid()) { + bool anchored = itemNode.instanceHasAnchors(); + return anchored; + } + return false; +} + +bool SingleSelectionItemNotAnchored::operator() (const SelectionContext &selectionState) { + QmlItemNode itemNode(selectionState.currentSingleSelectedNode()); + if (selectionState.isInBaseState() && itemNode.isValid()) { + bool anchored = itemNode.instanceHasAnchors(); + return !anchored; + } + return false; +} + +bool SelectionHasSameParent::operator() (const SelectionContext &selectionState) +{ + return !selectionState.selectedModelNodes().isEmpty() && itemsHaveSameParent(selectionState.selectedModelNodes()); +} + +bool SelectionIsComponent::operator() (const SelectionContext &selectionState) +{ + return modelNodeIsComponent(selectionState.currentSingleSelectedNode()); +} + +} //SelectionStateFunctors + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h new file mode 100644 index 0000000000..a8302a81f0 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/modelnodecontextmenu_helper.h @@ -0,0 +1,345 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#ifndef MODELNODECONTEXTMENU_HELPER_H +#define MODELNODECONTEXTMENU_HELPER_H + +#include "modelnodecontextmenu.h" +#include "designeractionmanager.h" +#include <QAction> + +namespace QmlDesigner { + +class ComponentUtils { +public: + static void goIntoComponent(const ModelNode &modelNode); +}; + +class DefaultAction : public QAction { + + Q_OBJECT + +public: + DefaultAction(const QString &description) : QAction(description, 0) + { + connect(this, SIGNAL(triggered(bool)), this, SLOT(actionTriggered(bool))); + } + +public slots: //virtual method instead of slot + virtual void actionTriggered(bool ) + { } + + void setSelectionContext(const SelectionContext &selectionContext) + { + m_selectionContext = selectionContext; + } + +protected: + SelectionContext m_selectionContext; +}; + +class DefaultDesignerAction : public AbstractDesignerAction +{ +public: + DefaultDesignerAction(const QString &description) : m_action(new DefaultAction(description)) + {} + + DefaultDesignerAction(DefaultAction *action) : m_action(action) + {} + + virtual QAction *action() const + { return m_action; } + + virtual void setCurrentContext(const SelectionContext &selectionContext) + { + m_selectionContext = selectionContext; + updateContext(); + } + + virtual void updateContext() + { + m_action->setSelectionContext(m_selectionContext); + if (m_selectionContext.isValid()) { + m_action->setEnabled(isEnabled(m_selectionContext)); + m_action->setVisible(isVisible(m_selectionContext)); + } + } + +protected: + DefaultAction *m_action; + SelectionContext m_selectionContext; +}; + +template <class ENABLED = SelectionContextFunctors::Always, + class VISIBILITY = SelectionContextFunctors::Always> +class MenuDesignerAction : public AbstractDesignerAction +{ +public: + MenuDesignerAction(const QString &displayName, const QString &menuId, int priority) : + m_displayName(displayName), + m_menuId(menuId), + m_priority(priority), + m_menu(new QMenu) + { + m_menu->setTitle(displayName); + m_action = m_menu->menuAction(); + } + + virtual bool isVisible(const SelectionContext &m_selectionState) const + { VISIBILITY visibility; return visibility(m_selectionState); } + + virtual bool isEnabled(const SelectionContext &m_selectionState) const + { ENABLED enabled; return enabled(m_selectionState); } + + virtual QString category() const + { return QString(""); } + + virtual QString menuId() const + { return m_menuId; } + + virtual int priority() const + { return m_priority; } + + virtual AbstractDesignerAction::Type type() const + { return AbstractDesignerAction::Menu; } + + virtual QAction *action() const + { return m_action; } + + virtual void setCurrentContext(const SelectionContext &selectionContext) + { + m_selectionContext = selectionContext; + updateContext(); + } + + virtual void updateContext() + { + if (m_selectionContext.isValid()) { + m_action->setEnabled(isEnabled(m_selectionContext)); + m_action->setVisible(isVisible(m_selectionContext)); + } + } + +protected: + const QString m_displayName; + const QString m_menuId; + const int m_priority; + SelectionContext m_selectionContext; + QScopedPointer<QMenu> m_menu; + QAction *m_action; +}; + +template <class VISIBILITY = SelectionContextFunctors::Always> +class SeperatorDesignerAction : public DefaultDesignerAction +{ +public: + SeperatorDesignerAction(const QString &category, int priority) : + DefaultDesignerAction(QString()), + m_category(category), m_priority(priority) + { m_action->setSeparator(true); } + + virtual bool isVisible(const SelectionContext &m_selectionState) const + { VISIBILITY visibility; return visibility(m_selectionState); } + + virtual bool isEnabled(const SelectionContext &) const + { return true; } + + virtual QString category() const + { return m_category; } + + virtual QString menuId() const + { return QString(); } + + virtual int priority() const + { return m_priority; } + + virtual Type type() const + { return Action; } + + virtual void setCurrentContext(const SelectionContext &) + {} +private: + const QString m_category; + const int m_priority; +}; + +template <class ACTION> +class ActionTemplate : public DefaultAction { + +public: + ActionTemplate(const QString &description) : DefaultAction(description) + { } + +public /*slots*/: + virtual void actionTriggered(bool b) + { + m_selectionContext.setToggled(b); + ACTION action; + return action(m_selectionContext); + } +}; + +template <class ACTION, + class ENABLED = SelectionContextFunctors::Always, + class VISIBILITY = SelectionContextFunctors::Always> +class ModelNodeActionFactory : public DefaultDesignerAction +{ +public: + ModelNodeActionFactory(const QString &description, const QString &category, int priority) : + DefaultDesignerAction(new ActionTemplate<ACTION>(description)), + m_category(category), + m_priority(priority) + {} + + virtual bool isVisible(const SelectionContext &selectionState) const + { VISIBILITY visibility; return visibility(selectionState); } + + virtual bool isEnabled(const SelectionContext &selectionState) const + { ENABLED enabled; return enabled(selectionState); } + + virtual QString category() const + { return m_category; } + + virtual QString menuId() const + { return QString(); } + + virtual int priority() const + { return m_priority; } + + virtual Type type() const + { return Action; } + +private: + const QString m_category; + const int m_priority; +}; + +namespace SelectionContextFunctors { + +struct Always { + bool operator() (const SelectionContext &) { + return true; + } +}; + +struct InBaseState { + bool operator() (const SelectionContext &selectionState) { + return selectionState.isInBaseState(); + } +}; + +struct SingleSelection { + bool operator() (const SelectionContext &selectionState) { + return selectionState.singleSelected(); + } +}; + +struct SelectionEnabled { + bool operator() (const SelectionContext &selectionState) { + return selectionState.showSelectionTools(); + } +}; + +struct SelectionNotEmpty { + bool operator() (const SelectionContext &selectionState) { + return !selectionState.selectedModelNodes().isEmpty(); + } +}; + +struct SingleSelectionNotRoot { + bool operator() (const SelectionContext &selectionState) { + return selectionState.singleSelected() + && !selectionState.currentSingleSelectedNode().isRootNode(); + } +}; + +template <class T1, class T2> +struct And { + bool operator() (const SelectionContext &selectionState) { + T1 t1; + T2 t2; + return t1(selectionState) && t2(selectionState); + } +}; + +template <class T1, class T2> +struct Or { + bool operator() (const SelectionContext &selectionState) { + T1 t1; + T2 t2; + return t1(selectionState) || t2(selectionState); + } +}; + +template <class T1> +struct Not { + bool operator() (const SelectionContext &selectionState) { + T1 t1; + return !t1(selectionState); + } +}; + +template <char* PROPERTYNAME> +struct SelectionHasProperty { + bool operator() (const SelectionContext &selectionState) { + foreach (const ModelNode &modelNode, selectionState.selectedModelNodes()) + if (modelNode.hasProperty(QLatin1String(PROPERTYNAME))) + return true; + return false; + } +}; + +struct SelectionHasSameParent { + bool operator() (const SelectionContext &selectionState); +}; + +struct SelectionIsComponent { + bool operator() (const SelectionContext &selectionState); +}; + +struct SingleSelectionItemIsAnchored { + bool operator() (const SelectionContext &selectionState); +}; + +struct SingleSelectionItemNotAnchored { + bool operator() (const SelectionContext &selectionState); +}; + +struct SingleSelectedItem { + bool operator() (const SelectionContext &selectionState) { + QmlItemNode itemNode(selectionState.currentSingleSelectedNode()); + return itemNode.isValid(); + } +}; + +} //SelectionStateFunctors + +} //QmlDesigner + +#endif // MODELNODECONTEXTMENU_HELPER_H diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp new file mode 100644 index 0000000000..45fad74cab --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -0,0 +1,602 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "modelnodeoperations.h" +#include "modelnodecontextmenu_helper.h" + +#include <cmath> +#include <QApplication> +#include <QMessageBox> +#include <coreplugin/editormanager/editormanager.h> +#include <nodeabstractproperty.h> +#include <nodelistproperty.h> +#include <nodemetainfo.h> +#include <modelnode.h> +#include <qmlitemnode.h> +#include <variantproperty.h> +#include <bindingproperty.h> +#include <nodeproperty.h> +#include <rewritingexception.h> +#include <rewritertransaction.h> +#include <designmodewidget.h> +#include <qmlanchors.h> + +namespace QmlDesigner { + +const QString auxDataString = QLatin1String("anchors_"); + +static inline bool isItem(const ModelNode &node) +{ + return node.isValid() && node.metaInfo().isValid() && node.metaInfo().isSubclassOf("QtQuick.Item", -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 void getWidthHeight(const ModelNode &node, int &width, int &height) +{ + QmlItemNode itemNode(node); + if (itemNode.isValid()) { + width = itemNode.instanceValue("width").toInt(); + height = itemNode.instanceValue("height").toInt(); + } +} + +static inline bool modelNodesHaveProperty(const QList<ModelNode> &modelNodeList, const QString &propertyName) +{ + foreach (const ModelNode &modelNode, modelNodeList) + if (modelNode.hasProperty(propertyName)) + return true; + + return false; +} + +void ModelNodeOperations::goIntoComponent(const ModelNode &modelNode) +{ + ComponentUtils::goIntoComponent(modelNode); +} + +void ModelNodeOperations::select(const SelectionContext &selectionState) +{ + if (selectionState.view()) + selectionState.view()->setSelectedModelNodes(QList<ModelNode>() << selectionState.targetNode()); +} + +void ModelNodeOperations::deSelect(const SelectionContext &selectionState) +{ + if (selectionState.view()) { + QList<ModelNode> selectedNodes = selectionState.view()->selectedModelNodes(); + foreach (const ModelNode &node, selectionState.selectedModelNodes()) { + if (selectedNodes.contains(node)) + selectedNodes.removeAll(node); + } + selectionState.view()->setSelectedModelNodes(selectedNodes); + } +} + +void ModelNodeOperations::cut(const SelectionContext &) +{ +} + + +void ModelNodeOperations::copy(const SelectionContext &) +{ +} + +void ModelNodeOperations::deleteSelection(const SelectionContext &) +{ +} + +void ModelNodeOperations::toFront(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + try { + QmlItemNode node = selectionState.selectedModelNodes().first(); + if (node.isValid()) { + signed int maximumZ = getMaxZValue(siblingsForNode(node)); + maximumZ++; + node.setVariantProperty("z", maximumZ); + } + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + + +void ModelNodeOperations::toBack(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + try { + QmlItemNode node = selectionState.selectedModelNodes().first(); + if (node.isValid()) { + signed int minimumZ = getMinZValue(siblingsForNode(node)); + minimumZ--; + node.setVariantProperty("z", minimumZ); + } + + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + +void ModelNodeOperations::raise(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + try { + RewriterTransaction transaction(selectionState.view()); + foreach (ModelNode modelNode, selectionState.selectedModelNodes()) { + QmlItemNode node = modelNode; + if (node.isValid()) { + signed int z = node.instanceValue("z").toInt(); + z++; + node.setVariantProperty("z", z); + } + } + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + +void ModelNodeOperations::lower(const SelectionContext &selectionState) +{ + + if (!selectionState.view()) + return; + + try { + RewriterTransaction transaction(selectionState.view()); + foreach (ModelNode modelNode, selectionState.selectedModelNodes()) { + QmlItemNode node = modelNode; + if (node.isValid()) { + signed int z = node.instanceValue("z").toInt(); + z--; + node.setVariantProperty("z", z); + } + } + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + +void ModelNodeOperations::paste(const SelectionContext &) +{ +} + +void ModelNodeOperations::undo(const SelectionContext &) +{ +} + +void ModelNodeOperations::redo(const SelectionContext &) +{ +} + +void ModelNodeOperations::setVisible(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + try { + selectionState.selectedModelNodes().first().variantProperty("visible") = selectionState.toggled(); + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + + +void ModelNodeOperations::resetSize(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + try { + RewriterTransaction transaction(selectionState.view()); + foreach (ModelNode node, selectionState.selectedModelNodes()) { + node.removeProperty("width"); + node.removeProperty("height"); + } + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + +void ModelNodeOperations::resetPosition(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + try { + RewriterTransaction transaction(selectionState.view()); + foreach (ModelNode node, selectionState.selectedModelNodes()) { + node.removeProperty("x"); + node.removeProperty("y"); + } + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + +void ModelNodeOperations::goIntoComponent(const SelectionContext &selectionState) +{ + goIntoComponent(selectionState.currentSingleSelectedNode()); +} + +void ModelNodeOperations::setId(const SelectionContext &) +{ +} + +void ModelNodeOperations::resetZ(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + RewriterTransaction transaction(selectionState.view()); + foreach (ModelNode node, selectionState.selectedModelNodes()) { + node.removeProperty("z"); + } +} + +static inline void backupPropertyAndRemove(ModelNode node, const QString &propertyName) +{ + if (node.hasVariantProperty(propertyName)) { + node.setAuxiliaryData(auxDataString + propertyName, node.variantProperty(propertyName).value()); + node.removeProperty(propertyName); + + } + if (node.hasBindingProperty(propertyName)) { + node.setAuxiliaryData(auxDataString + propertyName, QmlItemNode(node).instanceValue(propertyName)); + node.removeProperty(propertyName); + } +} + + +static inline void restoreProperty(ModelNode node, const QString &propertyName) +{ + if (node.hasAuxiliaryData(auxDataString + propertyName)) + node.variantProperty(propertyName) = node.auxiliaryData(auxDataString + propertyName); +} + +void ModelNodeOperations::anchorsFill(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + RewriterTransaction transaction(selectionState.view()); + + ModelNode modelNode = selectionState.currentSingleSelectedNode(); + + QmlItemNode node = modelNode; + if (node.isValid()) { + node.anchors().fill(); + backupPropertyAndRemove(modelNode, QLatin1String("x")); + backupPropertyAndRemove(modelNode, QLatin1String("y")); + backupPropertyAndRemove(modelNode, QLatin1String("width")); + backupPropertyAndRemove(modelNode, QLatin1String("height")); + } +} + +void ModelNodeOperations::anchorsReset(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + RewriterTransaction transaction(selectionState.view()); + + ModelNode modelNode = selectionState.currentSingleSelectedNode(); + + QmlItemNode node = modelNode; + if (node.isValid()) { + node.anchors().removeAnchors(); + node.anchors().removeMargins(); + restoreProperty(node, "x"); + restoreProperty(node, "y"); + restoreProperty(node, "width"); + restoreProperty(node, "height"); + } +} + +static inline void reparentTo(const ModelNode &node, const QmlItemNode &parent) +{ + + if (parent.isValid() && node.isValid()) { + NodeAbstractProperty parentProperty; + + if (parent.hasDefaultProperty()) { + parentProperty = parent.nodeAbstractProperty(parent.defaultProperty()); + } else { + parentProperty = parent.nodeAbstractProperty(QLatin1String("data")); + } + + parentProperty.reparentHere(node); + } +} + + +bool compareByX(const ModelNode &node1, const ModelNode &node2) +{ + QmlItemNode itemNode1 = QmlItemNode(node1); + QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return itemNode1.instancePosition().x() < itemNode2.instancePosition().x(); + return false; +} + +bool compareByY(const ModelNode &node1, const ModelNode &node2) +{ + QmlItemNode itemNode1 = QmlItemNode(node1); + QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return itemNode1.instancePosition().y() < itemNode2.instancePosition().y(); + return false; +} + +bool compareByGrid(const ModelNode &node1, const ModelNode &node2) +{ + QmlItemNode itemNode1 = QmlItemNode(node1); + QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) { + if ((itemNode1.instancePosition().y() + itemNode1.instanceSize().height()) < itemNode2.instancePosition().y()) + return true; + if ((itemNode2.instancePosition().y() + itemNode2.instanceSize().height()) < itemNode1.instancePosition().y()) + return false; //first sort y (rows) + return itemNode1.instancePosition().x() < itemNode2.instancePosition().x(); + } + return false; +} + +static inline QPoint getUpperLeftPosition(const QList<ModelNode> &modelNodeList) +{ + QPoint p(INT_MAX, INT_MAX); + foreach (ModelNode modelNode, modelNodeList) { + QmlItemNode itemNode = QmlItemNode(modelNode); + if (itemNode.isValid()) { + if (itemNode.instancePosition().x() < p.x()) + p.setX(itemNode.instancePosition().x()); + if (itemNode.instancePosition().y() < p.y()) + p.setY(itemNode.instancePosition().y()); + } + } + return p; +} + +void ModelNodeOperations::layoutRow(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + NodeMetaInfo rowMetaInfo = selectionState.view()->model()->metaInfo(QLatin1String("QtQuick.Row")); + + if (!rowMetaInfo.isValid()) + return; + + QList<ModelNode> modelNodeList = selectionState.selectedModelNodes(); + + ModelNode row; + { + RewriterTransaction transaction(selectionState.view()); + + QmlItemNode parent = QmlItemNode(modelNodeList.first()).instanceParent().toQmlItemNode(); + if (!parent.isValid()) + return; + + qDebug() << parent.modelNode().majorQtQuickVersion(); + + row = selectionState.view()->createModelNode(QLatin1String("QtQuick.Row"), rowMetaInfo.majorVersion(), rowMetaInfo.minorVersion()); + + reparentTo(row, parent); + } + + { + RewriterTransaction transaction(selectionState.view()); + + QPoint pos = getUpperLeftPosition(modelNodeList); + row.variantProperty(QLatin1String("x")) = pos.x(); + row.variantProperty(QLatin1String("y")) = pos.y(); + + QList<ModelNode> sortedList = modelNodeList; + qSort(sortedList.begin(), sortedList.end(), compareByX); + + foreach (ModelNode modelNode, sortedList) { + reparentTo(modelNode, row); + modelNode.removeProperty(QLatin1String("x")); + modelNode.removeProperty(QLatin1String("y")); + } + } +} + +void ModelNodeOperations::layoutColumn(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + NodeMetaInfo columnMetaInfo = selectionState.view()->model()->metaInfo(QLatin1String("QtQuick.Column")); + + if (!columnMetaInfo.isValid()) + return; + + QList<ModelNode> modelNodeList = selectionState.selectedModelNodes(); + + ModelNode column; + { + RewriterTransaction transaction(selectionState.view()); + + QmlItemNode parent = QmlItemNode(modelNodeList.first()).instanceParent().toQmlItemNode(); + if (!parent.isValid()) + return; + + column = selectionState.view()->createModelNode(QLatin1String("QtQuick.Column"), columnMetaInfo.majorVersion(), columnMetaInfo.minorVersion()); + + reparentTo(column, parent); + } + + { + RewriterTransaction transaction(selectionState.view()); + + QPoint pos = getUpperLeftPosition(modelNodeList); + column.variantProperty(QLatin1String("x")) = pos.x(); + column.variantProperty(QLatin1String("y")) = pos.y(); + + QList<ModelNode> sortedList = modelNodeList; + qSort(sortedList.begin(), sortedList.end(), compareByY); + + foreach (ModelNode modelNode, sortedList) { + reparentTo(modelNode, column); + modelNode.removeProperty(QLatin1String("x")); + modelNode.removeProperty(QLatin1String("y")); + } + } +} + +void ModelNodeOperations::layoutGrid(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + NodeMetaInfo gridMetaInfo = selectionState.view()->model()->metaInfo(QLatin1String("QtQuick.Grid")); + + if (!gridMetaInfo.isValid()) + return; + + QList<ModelNode> modelNodeList = selectionState.selectedModelNodes(); + + ModelNode grid; + { + RewriterTransaction transaction(selectionState.view()); + + QmlItemNode parent = QmlItemNode(modelNodeList.first()).instanceParent().toQmlItemNode(); + if (!parent.isValid()) + return; + + grid = selectionState.view()->createModelNode(QLatin1String("QtQuick.Grid"), gridMetaInfo.majorVersion(), gridMetaInfo.minorVersion()); + grid.variantProperty(QLatin1String("columns")) = int(sqrt(double(modelNodeList.count()))); + + reparentTo(grid, parent); + } + + { + RewriterTransaction transaction(selectionState.view()); + + QPoint pos = getUpperLeftPosition(modelNodeList); + grid.variantProperty(QLatin1String("x")) = pos.x(); + grid.variantProperty(QLatin1String("y")) = pos.y(); + + QList<ModelNode> sortedList = modelNodeList; + qSort(sortedList.begin(), sortedList.end(), compareByGrid); + + foreach (ModelNode modelNode, sortedList) { + reparentTo(modelNode, grid); + modelNode.removeProperty(QLatin1String("x")); + modelNode.removeProperty(QLatin1String("y")); + } + } +} + +void ModelNodeOperations::layoutFlow(const SelectionContext &selectionState) +{ + if (!selectionState.view()) + return; + + NodeMetaInfo flowMetaInfo = selectionState.view()->model()->metaInfo(QLatin1String("QtQuick.Flow")); + + if (!flowMetaInfo.isValid()) + return; + + QList<ModelNode> modelNodeList = selectionState.selectedModelNodes(); + + ModelNode flow; + { + RewriterTransaction transaction(selectionState.view()); + + QmlItemNode parent = QmlItemNode(modelNodeList.first()).instanceParent().toQmlItemNode(); + if (!parent.isValid()) + return; + + flow = selectionState.view()->createModelNode(QLatin1String("QtQuick.Flow"), flowMetaInfo.majorVersion(), flowMetaInfo.minorVersion()); + + reparentTo(flow, parent); + } + + { + RewriterTransaction transaction(selectionState.view()); + + QPoint pos = getUpperLeftPosition(modelNodeList); + flow.variantProperty(QLatin1String("x")) = pos.x(); + flow.variantProperty(QLatin1String("y")) = pos.y(); + + QList<ModelNode> sortedList = modelNodeList; + qSort(sortedList.begin(), sortedList.end(), compareByGrid); + + foreach (ModelNode modelNode, sortedList) { + reparentTo(modelNode, flow); + modelNode.removeProperty(QLatin1String("x")); + modelNode.removeProperty(QLatin1String("y")); + } + } +} + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h new file mode 100644 index 0000000000..da652ddc40 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#ifndef MODELNODEOPERATIONS_H +#define MODELNODEOPERATIONS_H + +#include "selectioncontext.h" + +namespace QmlDesigner { + +class ModelNodeOperations +{ +public: + static void goIntoComponent(const ModelNode &modelNode); + + static void select(const SelectionContext &selectionState); + static void deSelect(const SelectionContext &selectionState); + static void cut(const SelectionContext &selectionState); + static void copy(const SelectionContext &selectionState); + static void deleteSelection(const SelectionContext &selectionState); + static void toFront(const SelectionContext &selectionState); + static void toBack(const SelectionContext &selectionState); + static void raise(const SelectionContext &selectionState); + static void lower(const SelectionContext &selectionState); + static void paste(const SelectionContext &selectionState); + static void undo(const SelectionContext &selectionState); + static void redo(const SelectionContext &selectionState); + static void setVisible(const SelectionContext &selectionState); + static void resetSize(const SelectionContext &selectionState); + static void resetPosition(const SelectionContext &selectionState); + static void goIntoComponent(const SelectionContext &selectionState); + static void setId(const SelectionContext &selectionState); + static void resetZ(const SelectionContext &selectionState); + static void anchorsFill(const SelectionContext &selectionState); + static void anchorsReset(const SelectionContext &selectionState); + static void layoutRow(const SelectionContext &selectionState); + static void layoutColumn(const SelectionContext &selectionState); + static void layoutGrid(const SelectionContext &selectionState); + static void layoutFlow(const SelectionContext &selectionState); +}; + +} //QmlDesigner + +#endif //MODELNODEOPERATIONS_H diff --git a/src/plugins/qmldesigner/components/componentcore/selectioncontext.cpp b/src/plugins/qmldesigner/components/componentcore/selectioncontext.cpp new file mode 100644 index 0000000000..d321e2dd28 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/selectioncontext.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include "selectioncontext.h" + +namespace QmlDesigner { + + +SelectionContext::SelectionContext() : + m_view(0), + m_isInBaseState(false), + m_toggled(false) +{ + +} + +SelectionContext::SelectionContext(QmlModelView *view) : + m_view(view), + m_isInBaseState(view->currentState().isBaseState()), + m_toggled(false) +{ + if (m_view && m_view->model()) + m_selectedModelNodes = view->selectedModelNodes(); + + if (m_selectedModelNodes.count()== 1) { + m_singleSelected = true; + m_currentSingleSelectedNode = m_selectedModelNodes.first(); + } else { + m_singleSelected = false; + } +} + +} //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/selectioncontext.h b/src/plugins/qmldesigner/components/componentcore/selectioncontext.h new file mode 100644 index 0000000000..f49417d792 --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/selectioncontext.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** 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. +** +****************************************************************************/ + +#include <qmlmodelview.h> + +#ifndef SELECTIONCONTEXT_H +#define SELECTIONCONTEXT_H + +namespace QmlDesigner { + +class SelectionContext { + +public: + SelectionContext(); + SelectionContext(QmlModelView *view); + + void setTargetNode(const ModelNode &modelNode) + { m_targetNode = modelNode; } + + bool singleSelected() const + { return m_singleSelected; } + + bool isInBaseState() const + { return m_isInBaseState; } + + ModelNode targetNode() const + { return m_targetNode; } + + ModelNode currentSingleSelectedNode() const + { return m_currentSingleSelectedNode; } + + QList<ModelNode> selectedModelNodes() const + { return m_selectedModelNodes; } + + QmlModelView *view() const + { return m_view; } + + void setShowSelectionTools(bool show) + { m_showSelectionTools = show; } + + bool showSelectionTools() const + { return m_showSelectionTools; } + + QPoint scenePos() const + { return m_scenePos; } + + void setScenePos(const QPoint &pos) + { m_scenePos = pos; } + + void setToggled(bool b) + { m_toggled = b; } + + bool toggled() const + { return m_toggled; } + + bool isValid() const + { return view() && view()->model() && view()->nodeInstanceView(); } + +private: + QmlModelView *m_view; + bool m_singleSelected; + ModelNode m_currentSingleSelectedNode; + ModelNode m_targetNode; + bool m_isInBaseState; + QList<ModelNode> m_selectedModelNodes; + bool m_showSelectionTools; + QPoint m_scenePos; + bool m_toggled; +}; + +} //QmlDesigner + +#endif //SELECTIONCONTEXT_H diff --git a/src/plugins/qmldesigner/components/integration/designdocumentcontroller.cpp b/src/plugins/qmldesigner/components/integration/designdocumentcontroller.cpp index afb145d567..b298dfb5ba 100644 --- a/src/plugins/qmldesigner/components/integration/designdocumentcontroller.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocumentcontroller.cpp @@ -38,12 +38,13 @@ #include <metainfo.h> #include <invalidargumentexception.h> #include <componentaction.h> +#include <designeractionmanager.h> #include <qmlobjectnode.h> #include <rewritingexception.h> #include <nodelistproperty.h> #include <variantproperty.h> #include <rewritingexception.h> -#include <modelnodecontextmenu.h> +#include <modelnodeoperations.h> #include <designmodewidget.h> #include <projectexplorer/projectexplorer.h> @@ -489,7 +490,7 @@ void DesignDocumentController::goIntoComponent() s_clearCrumblePath = false; if (selectedNodes.count() == 1) - ModelNodeAction::goIntoComponent(selectedNodes.first()); + ModelNodeOperations::goIntoComponent(selectedNodes.first()); s_clearCrumblePath = true; } @@ -518,6 +519,7 @@ void DesignDocumentController::loadCurrentModel() m_model->attachView(m_propertyEditorView.data()); + m_model->attachView(DesignerActionManager::view()); if (s_clearCrumblePath) m_formEditorView->crumblePath()->clear(); |