diff options
author | Thomas Hartmann <Thomas.Hartmann@digia.com> | 2013-07-16 12:23:07 +0200 |
---|---|---|
committer | Thomas Hartmann <Thomas.Hartmann@digia.com> | 2013-07-16 12:29:44 +0200 |
commit | 066b3ab8890475a8a91f7eb2021e631618345ff0 (patch) | |
tree | 4eacfe7af83837e32b81785ab1632036d112e469 | |
parent | bcf9b3a171ad5a9dc478ad392b4e21bfbf0c6403 (diff) | |
download | qt-creator-066b3ab8890475a8a91f7eb2021e631618345ff0.tar.gz |
QmlDesigner.ContextMenu: fix support for Layouts
We have positioner in QtQuick and "real" layouts in
QtQuick.Layouts.
Change-Id: Ie1c5235820ac698048a229af7ede9d8f57926b19
Reviewed-by: Marco Bubke <marco.bubke@digia.com>
4 files changed, 388 insertions, 18 deletions
diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h index 9c67060fb4..289c1e8c87 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h +++ b/src/plugins/qmldesigner/components/componentcore/componentcore_constants.h @@ -82,10 +82,18 @@ const char resetZDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Re 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 char layoutColumnPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Column (Positioner)"); +const char layoutRowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Row (Positioner)"); +const char layoutGridPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Grid (Positioner)"); +const char layoutFlowPositionerDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in Flow (Positioner)"); + +const char layoutColumnLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in ColumnLayout"); +const char layoutRowLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in RowLayout"); +const char layoutGridLayoutDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Layout in GridLayout"); + +const char layoutFillWidthDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill Width"); +const char layoutFillHeightDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Fill Height"); + const int priorityFirst = 220; const int prioritySelectionCategory = 200; diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp index 0facd04494..041bdf5b32 100644 --- a/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanager.cpp @@ -30,6 +30,7 @@ #include "designeractionmanager.h" #include "modelnodecontextmenu_helper.h" #include <nodeproperty.h> +#include <nodemetainfo.h> namespace QmlDesigner { @@ -246,6 +247,65 @@ public: } }; +class FillLayoutModelNodeAction : public ModelNodeAction +{ +public: + FillLayoutModelNodeAction(const QString &description, const QByteArray &category, int priority, + ModelNodeOperations::SelectionAction action, + SelectionContextFunction enabled = &SelectionContextFunctors::always, + SelectionContextFunction visibility = &SelectionContextFunctors::always) : + ModelNodeAction(description, category, priority, action, enabled, visibility) + {} + virtual void updateContext() + { + defaultAction()->setSelectionContext(selectionContext()); + if (selectionContext().isValid()) { + defaultAction()->setEnabled(isEnabled(selectionContext())); + defaultAction()->setVisible(isVisible(selectionContext())); + + defaultAction()->setCheckable(true); + QmlItemNode itemNode = QmlItemNode(selectionContext().currentSingleSelectedNode()); + if (itemNode.isValid()) { + bool flag = false; + if (itemNode.modelNode().hasProperty(m_propertyName) + || itemNode.propertyAffectedByCurrentState(m_propertyName)) + flag = itemNode.modelValue(m_propertyName).toBool(); + defaultAction()->setChecked(flag); + } else { + defaultAction()->setEnabled(false); + } + } + } +protected: + PropertyName m_propertyName; +}; + +class FillWidthModelNodeAction : public FillLayoutModelNodeAction +{ +public: + FillWidthModelNodeAction(const QString &description, const QByteArray &category, int priority, + ModelNodeOperations::SelectionAction action, + SelectionContextFunction enabled = &SelectionContextFunctors::always, + SelectionContextFunction visibility = &SelectionContextFunctors::always) : + FillLayoutModelNodeAction(description, category, priority, action, enabled, visibility) + { + m_propertyName = "Layout.fillWidth"; + } +}; + +class FillHeightModelNodeAction : public FillLayoutModelNodeAction +{ +public: + FillHeightModelNodeAction(const QString &description, const QByteArray &category, int priority, + ModelNodeOperations::SelectionAction action, + SelectionContextFunction enabled = &SelectionContextFunctors::always, + SelectionContextFunction visibility = &SelectionContextFunctors::always) : + FillLayoutModelNodeAction(description, category, priority, action, enabled, visibility) + { + m_propertyName = "Layout.fillHeight"; + } +}; + class SelectionModelNodeAction : public MenuDesignerAction { public: @@ -328,9 +388,42 @@ bool selectionHasSameParentAndInBaseState(const SelectionContext &context) return selectionHasSameParent(context) && inBaseState(context); } +bool isNotInLayout(const SelectionContext &context) +{ + if (selectionNotEmpty(context)) { + ModelNode selectedModelNode = context.selectedModelNodes().first(); + ModelNode parentModelNode; + + if (selectedModelNode.hasParentProperty()) + parentModelNode = selectedModelNode.parentProperty().parentModelNode(); + + if (parentModelNode.isValid() && parentModelNode.metaInfo().isValid()) + return !parentModelNode.metaInfo().isLayoutable(); + } + + return true; +} + bool selectionCanBeLayouted(const SelectionContext &context) { - return selectionHasSameParentAndInBaseState(context) && inBaseState(context); + return selectionHasSameParentAndInBaseState(context) + && inBaseState(context) + && isNotInLayout(context); +} + +bool hasQtQuickLayoutImport(const SelectionContext &context) +{ + if (context.qmlModelView() && context.qmlModelView()->model()) { + Import import = Import::createLibraryImport(QLatin1String("QtQuick.Layouts"), QLatin1String("1.0")); + return context.qmlModelView()->model()->hasImport(import, true, true); + } + + return false; +} + +bool selectionCanBeLayoutedAndasQtQuickLayoutImport(const SelectionContext &context) +{ + return selectionCanBeLayouted(context) && hasQtQuickLayoutImport(context); } bool selectionNotEmptyAndHasZProperty(const SelectionContext &context) @@ -350,6 +443,34 @@ bool selectionNotEmptyAndHasXorYProperty(const SelectionContext &context) && selectionHasProperty1or2(context, xProperty, yProperty); } +bool singleSelectionAndInQtQuickLayout(const SelectionContext &context) +{ + if (!singleSelection(context)) + return false; + + ModelNode currentSelectedNode = context.currentSingleSelectedNode(); + if (!currentSelectedNode.isValid()) + return false; + + if (!currentSelectedNode.hasParentProperty()) + return false; + + ModelNode parentModelNode = currentSelectedNode.parentProperty().parentModelNode(); + + NodeMetaInfo metaInfo = parentModelNode.metaInfo(); + + if (!metaInfo.isValid()) + return false; + + return metaInfo.isSubclassOf("QtQuick.Layouts.Layout", -1, -1); +} + +bool layoutOptionVisible(const SelectionContext &context) +{ + return multiSelectionAndInBaseState(context) + || singleSelectionAndInQtQuickLayout(context); +} + void DesignerActionManager::createDefaultDesignerActions() { using namespace SelectionContextFunctors; @@ -387,15 +508,80 @@ void DesignerActionManager::createDefaultDesignerActions() (anchorsResetDisplayName, anchorsCategory, 180, &anchorsReset, &singleSelectionItemIsAnchored)); addDesignerAction(new MenuDesignerAction(layoutCategoryDisplayName, layoutCategory, - priorityLayoutCategory, &multiSelectionAndInBaseState)); + priorityLayoutCategory, &layoutOptionVisible)); addDesignerAction(new ModelNodeAction - (layoutRowDisplayName, layoutCategory, 200, &layoutRow, &selectionCanBeLayouted)); + (layoutRowPositionerDisplayName, + layoutCategory, + 200, + &layoutRowPositioner, + &selectionCanBeLayouted, + selectionCanBeLayouted)); + addDesignerAction(new ModelNodeAction - (layoutColumnDisplayName, layoutCategory, 180, &layoutColumn, &selectionCanBeLayouted)); + (layoutColumnPositionerDisplayName, + layoutCategory, + 180, + &layoutColumnPositioner, + &selectionCanBeLayouted, + selectionCanBeLayouted)); + + addDesignerAction(new ModelNodeAction + (layoutGridPositionerDisplayName, + layoutCategory, + 160, + &layoutGridPositioner, + &selectionCanBeLayouted, + selectionCanBeLayouted)); + addDesignerAction(new ModelNodeAction - (layoutGridDisplayName, layoutCategory, 160, &layoutGrid, &selectionCanBeLayouted)); + (layoutFlowPositionerDisplayName, + layoutCategory, + 140, + &layoutFlowPositioner, + &selectionCanBeLayouted, + selectionCanBeLayouted)); + + addDesignerAction(new SeperatorDesignerAction(layoutCategory, 120)); + + addDesignerAction(new ModelNodeAction + (layoutRowLayoutDisplayName, + layoutCategory, + 100, + &layoutRowLayout, + &selectionCanBeLayoutedAndasQtQuickLayoutImport, + &selectionCanBeLayoutedAndasQtQuickLayoutImport)); + + addDesignerAction(new ModelNodeAction + (layoutColumnLayoutDisplayName, + layoutCategory, + 80, + &layoutColumnLayout, + &selectionCanBeLayoutedAndasQtQuickLayoutImport, + &selectionCanBeLayoutedAndasQtQuickLayoutImport)); + addDesignerAction(new ModelNodeAction - (layoutFlowDisplayName, layoutCategory, 140, &layoutFlow, &selectionCanBeLayouted)); + (layoutGridLayoutDisplayName, + layoutCategory, + 60, + &layoutGridLayout, + &selectionCanBeLayoutedAndasQtQuickLayoutImport, + &selectionCanBeLayoutedAndasQtQuickLayoutImport)); + + addDesignerAction(new FillWidthModelNodeAction + (layoutFillWidthDisplayName, + layoutCategory, + 40, + &setFillWidth, + singleSelectionAndInQtQuickLayout, + singleSelectionAndInQtQuickLayout)); + + addDesignerAction(new FillHeightModelNodeAction + (layoutFillHeightDisplayName, + layoutCategory, + 20, + &setFillHeight, + singleSelectionAndInQtQuickLayout, + singleSelectionAndInQtQuickLayout)); addDesignerAction(new SeperatorDesignerAction(rootCategory, priorityTopLevelSeperator)); addDesignerAction(new ModelNodeAction diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 182fca25c8..931501b4fd 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -245,6 +245,31 @@ void setVisible(const SelectionContext &selectionState) } } +void setFillWidth(const SelectionContext &selectionState) +{ + if (!selectionState.qmlModelView() + || selectionState.selectedModelNodes().isEmpty()) + return; + + try { + selectionState.selectedModelNodes().first().variantProperty("Layout.fillWidth") = selectionState.toggled(); + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} + +void setFillHeight(const SelectionContext &selectionState) +{ + if (!selectionState.qmlModelView() + || selectionState.selectedModelNodes().isEmpty()) + return; + + try { + selectionState.selectedModelNodes().first().variantProperty("Layout.fillHeight") = selectionState.toggled(); + } catch (RewritingException &e) { //better save then sorry + QMessageBox::warning(0, "Error", e.description()); + } +} void resetSize(const SelectionContext &selectionState) { @@ -420,7 +445,7 @@ static inline QPoint getUpperLeftPosition(const QList<ModelNode> &modelNodeList) return p; } -void layoutRow(const SelectionContext &selectionState) +void layoutRowPositioner(const SelectionContext &selectionState) { if (!selectionState.qmlModelView()) return; @@ -465,7 +490,7 @@ void layoutRow(const SelectionContext &selectionState) } } -void layoutColumn(const SelectionContext &selectionState) +void layoutColumnPositioner(const SelectionContext &selectionState) { if (!selectionState.qmlModelView()) return; @@ -508,7 +533,7 @@ void layoutColumn(const SelectionContext &selectionState) } } -void layoutGrid(const SelectionContext &selectionState) +void layoutGridPositioner(const SelectionContext &selectionState) { if (!selectionState.qmlModelView()) return; @@ -552,7 +577,7 @@ void layoutGrid(const SelectionContext &selectionState) } } -void layoutFlow(const SelectionContext &selectionState) +void layoutFlowPositioner(const SelectionContext &selectionState) { if (!selectionState.qmlModelView()) return; @@ -595,6 +620,151 @@ void layoutFlow(const SelectionContext &selectionState) } } +void layoutRowLayout(const SelectionContext &selectionState) +{ + if (!selectionState.qmlModelView() + || selectionState.selectedModelNodes().isEmpty()) + return; + + static TypeName rowLayoutType = "QtQuick.Layouts.RowLayout"; + + if (!selectionState.qmlModelView()->model()->hasNodeMetaInfo(rowLayoutType)) + return; + + NodeMetaInfo rowMetaInfo = selectionState.qmlModelView()->model()->metaInfo(rowLayoutType); + + QList<ModelNode> selectedNodeList = selectionState.selectedModelNodes(); + QmlItemNode qmlItemNode = QmlItemNode(selectedNodeList.first()); + + if (qmlItemNode.isValid() && qmlItemNode.hasInstanceParentItem()) { + + ModelNode rowNode; + { + RewriterTransaction transaction(selectionState.qmlModelView()); + + QmlItemNode parentNode = qmlItemNode.instanceParentItem(); + + rowNode = selectionState.qmlModelView()->createModelNode(rowLayoutType, rowMetaInfo.majorVersion(), rowMetaInfo.minorVersion()); + + reparentTo(rowNode, parentNode); + } + + { + RewriterTransaction transaction(selectionState.qmlModelView()); + + QPoint upperLeftPosition = getUpperLeftPosition(selectedNodeList); + rowNode.variantProperty("x") = upperLeftPosition.x(); + rowNode.variantProperty("y") = upperLeftPosition.y(); + + QList<ModelNode> sortedSelectedNodes = selectedNodeList; + qSort(sortedSelectedNodes.begin(), sortedSelectedNodes.end(), compareByX); + + foreach (ModelNode selectedNode, sortedSelectedNodes) { + reparentTo(selectedNode, rowNode); + selectedNode.removeProperty("x"); + selectedNode.removeProperty("y"); + } + } + } +} + +void layoutColumnLayout(const SelectionContext &selectionState) +{ + if (!selectionState.qmlModelView() + || selectionState.selectedModelNodes().isEmpty()) + return; + + static TypeName columnLayoutType = "QtQuick.Layouts.ColumnLayout"; + + if (!selectionState.qmlModelView()->model()->hasNodeMetaInfo(columnLayoutType)) + return; + + NodeMetaInfo columnMetaInfo = selectionState.qmlModelView()->model()->metaInfo(columnLayoutType); + + QList<ModelNode> selectedNodeList = selectionState.selectedModelNodes(); + QmlItemNode qmlItemNode = QmlItemNode(selectedNodeList.first()); + + if (qmlItemNode.isValid() && qmlItemNode.hasInstanceParentItem()) { + + ModelNode columnNode; + { + RewriterTransaction transaction(selectionState.qmlModelView()); + + QmlItemNode parentNode = qmlItemNode.instanceParentItem(); + + columnNode = selectionState.qmlModelView()->createModelNode(columnLayoutType, columnMetaInfo.majorVersion(), columnMetaInfo.minorVersion()); + + reparentTo(columnNode, parentNode); + } + + { + RewriterTransaction transaction(selectionState.qmlModelView()); + + QPoint upperLeftPosition = getUpperLeftPosition(selectedNodeList); + columnNode.variantProperty("x") = upperLeftPosition.x(); + columnNode.variantProperty("y") = upperLeftPosition.y(); + + QList<ModelNode> sortedSelectedNodes = selectedNodeList; + qSort(sortedSelectedNodes.begin(), sortedSelectedNodes.end(), compareByY); + + foreach (ModelNode selectedNode, sortedSelectedNodes) { + reparentTo(selectedNode, columnNode); + selectedNode.removeProperty("x"); + selectedNode.removeProperty("y"); + } + } + } +} + +void layoutGridLayout(const SelectionContext &selectionState) +{ + if (!selectionState.qmlModelView() + || selectionState.selectedModelNodes().isEmpty()) + return; + + static TypeName gridLayoutType = "QtQuick.Layouts.GridLayout"; + + if (!selectionState.qmlModelView()->model()->hasNodeMetaInfo(gridLayoutType)) + return; + + NodeMetaInfo gridMetaInfo = selectionState.qmlModelView()->model()->metaInfo(gridLayoutType); + + QList<ModelNode> selectedNodeList = selectionState.selectedModelNodes(); + QmlItemNode qmlItemNode = QmlItemNode(selectedNodeList.first()); + + if (qmlItemNode.isValid() && qmlItemNode.hasInstanceParentItem()) { + + ModelNode gridNode; + { + RewriterTransaction transaction(selectionState.qmlModelView()); + + QmlItemNode parentNode = qmlItemNode.instanceParentItem(); + + gridNode = selectionState.qmlModelView()->createModelNode(gridLayoutType, gridMetaInfo.majorVersion(), gridMetaInfo.minorVersion()); + gridNode.variantProperty("columns") = int(sqrt(double(selectedNodeList.count()))); + + reparentTo(gridNode, parentNode); + } + + { + RewriterTransaction transaction(selectionState.qmlModelView()); + + QPoint upperLeftPosition = getUpperLeftPosition(selectedNodeList); + gridNode.variantProperty("x") = upperLeftPosition.x(); + gridNode.variantProperty("y") = upperLeftPosition.y(); + + QList<ModelNode> sortedSelectedNodes = selectedNodeList; + qSort(sortedSelectedNodes.begin(), sortedSelectedNodes.end(), compareByGrid); + + foreach (ModelNode selectedNode, sortedSelectedNodes) { + reparentTo(selectedNode, gridNode); + selectedNode.removeProperty("x"); + selectedNode.removeProperty("y"); + } + } + } +} + } // namespace Mode } //QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 7905961230..a94421a8a8 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -52,6 +52,8 @@ void paste(const SelectionContext &selectionState); void undo(const SelectionContext &selectionState); void redo(const SelectionContext &selectionState); void setVisible(const SelectionContext &selectionState); +void setFillWidth(const SelectionContext &selectionState); +void setFillHeight(const SelectionContext &selectionState); void resetSize(const SelectionContext &selectionState); void resetPosition(const SelectionContext &selectionState); void goIntoComponent(const SelectionContext &selectionState); @@ -59,10 +61,14 @@ void setId(const SelectionContext &selectionState); void resetZ(const SelectionContext &selectionState); void anchorsFill(const SelectionContext &selectionState); void anchorsReset(const SelectionContext &selectionState); -void layoutRow(const SelectionContext &selectionState); -void layoutColumn(const SelectionContext &selectionState); -void layoutGrid(const SelectionContext &selectionState); -void layoutFlow(const SelectionContext &selectionState); +void layoutRowPositioner(const SelectionContext &selectionState); +void layoutColumnPositioner(const SelectionContext &selectionState); +void layoutGridPositioner(const SelectionContext &selectionState); +void layoutFlowPositioner(const SelectionContext &selectionState); +void layoutRowLayout(const SelectionContext &selectionState); +void layoutColumnLayout(const SelectionContext &selectionState); +void layoutGridLayout(const SelectionContext &selectionState); + } // namespace ModelNodeOperationso } //QmlDesigner |