summaryrefslogtreecommitdiff
path: root/src/plugins/qmldesigner/components/formeditor
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmldesigner/components/formeditor')
-rw-r--r--src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp190
-rw-r--r--src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h103
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchor.pngbin0 -> 415 bytes
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp537
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorcontroller.h117
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp212
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h91
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp116
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorindicator.h64
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp236
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h93
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp148
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h86
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp131
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h69
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp144
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchormanipulator.h71
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchortool.cpp226
-rw-r--r--src/plugins/qmldesigner/components/formeditor/anchortool.h88
-rw-r--r--src/plugins/qmldesigner/components/formeditor/controlelement.cpp66
-rw-r--r--src/plugins/qmldesigner/components/formeditor/controlelement.h57
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp315
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.h105
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditor.pri84
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditor.qrc12
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp88
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h51
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp323
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditoritem.h131
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp401
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditormainview.h123
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp156
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h74
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp48
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h50
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp364
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorscene.h133
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp38
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h45
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.cpp531
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.h141
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp221
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorwidget.h91
-rw-r--r--src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp191
-rw-r--r--src/plugins/qmldesigner/components/formeditor/itemcreatortool.h82
-rw-r--r--src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp78
-rw-r--r--src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h48
-rw-r--r--src/plugins/qmldesigner/components/formeditor/layeritem.cpp73
-rw-r--r--src/plugins/qmldesigner/components/formeditor/layeritem.h66
-rw-r--r--src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h39
-rw-r--r--src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp363
-rw-r--r--src/plugins/qmldesigner/components/formeditor/movemanipulator.h114
-rw-r--r--src/plugins/qmldesigner/components/formeditor/movetool.cpp345
-rw-r--r--src/plugins/qmldesigner/components/formeditor/movetool.h97
-rw-r--r--src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp88
-rw-r--r--src/plugins/qmldesigner/components/formeditor/numberseriesaction.h66
-rw-r--r--src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp146
-rw-r--r--src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h70
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resize_handle.pngbin0 -> 160 bytes
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp273
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizecontroller.h104
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp118
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizehandleitem.h84
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp91
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizeindicator.h81
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp504
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizemanipulator.h91
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizetool.cpp177
-rw-r--r--src/plugins/qmldesigner/components/formeditor/resizetool.h76
-rw-r--r--src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp153
-rw-r--r--src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h83
-rw-r--r--src/plugins/qmldesigner/components/formeditor/scaleitem.cpp49
-rw-r--r--src/plugins/qmldesigner/components/formeditor/scaleitem.h53
-rw-r--r--src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp45
-rw-r--r--src/plugins/qmldesigner/components/formeditor/scalemanipulator.h63
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp118
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionindicator.h65
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp87
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectionrectangle.h63
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectiontool.cpp280
-rw-r--r--src/plugins/qmldesigner/components/formeditor/selectiontool.h93
-rw-r--r--src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp132
-rw-r--r--src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h72
-rw-r--r--src/plugins/qmldesigner/components/formeditor/snapper.cpp626
-rw-r--r--src/plugins/qmldesigner/components/formeditor/snapper.h112
-rw-r--r--src/plugins/qmldesigner/components/formeditor/snapping.pngbin0 -> 359 bytes
-rw-r--r--src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp190
-rw-r--r--src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h102
-rw-r--r--src/plugins/qmldesigner/components/formeditor/toolbox.cpp81
-rw-r--r--src/plugins/qmldesigner/components/formeditor/toolbox.h52
-rw-r--r--src/plugins/qmldesigner/components/formeditor/transform.pngbin0 -> 17296 bytes
-rw-r--r--src/plugins/qmldesigner/components/formeditor/zoomaction.cpp116
-rw-r--r--src/plugins/qmldesigner/components/formeditor/zoomaction.h68
93 files changed, 12538 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp
new file mode 100644
index 0000000000..884ba4c351
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.cpp
@@ -0,0 +1,190 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "abstractformeditortool.h"
+#include "formeditorview.h"
+#include "formeditorview.h"
+
+#include <QtDebug>
+#include <QGraphicsSceneDragDropEvent>
+#include <nodemetainfo.h>
+
+namespace QmlDesigner {
+
+AbstractFormEditorTool::AbstractFormEditorTool(FormEditorView *editorView) : m_view(editorView)
+{
+}
+
+
+AbstractFormEditorTool::~AbstractFormEditorTool()
+{
+
+}
+
+FormEditorView* AbstractFormEditorTool::view() const
+{
+ return m_view;
+}
+
+FormEditorScene* AbstractFormEditorTool::scene() const
+{
+ return view()->scene();
+}
+
+void AbstractFormEditorTool::setItems(const QList<FormEditorItem*> &itemList)
+{
+ m_itemList = itemList;
+ selectedItemsChanged(m_itemList);
+}
+
+QList<FormEditorItem*> AbstractFormEditorTool::items() const
+{
+ return m_itemList;
+}
+
+bool AbstractFormEditorTool::topItemIsMovable(const QList<QGraphicsItem*> & itemList)
+{
+ QGraphicsItem *firstSelectableItem = topMovableGraphicsItem(itemList);
+ if (firstSelectableItem == 0)
+ return false;
+
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(firstSelectableItem);
+ QList<QmlItemNode> selectedNodes = view()->selectedQmlItemNodes();
+
+ if (formEditorItem != 0
+ && selectedNodes.contains(formEditorItem->qmlItemNode()))
+ return true;
+
+ return false;
+
+}
+
+bool AbstractFormEditorTool::topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList)
+{
+ QList<QmlItemNode> selectedNodes = view()->selectedQmlItemNodes();
+
+ foreach (QGraphicsItem *item, itemList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem
+ && selectedNodes.contains(formEditorItem->qmlItemNode())
+ && !formEditorItem->qmlItemNode().isRootNode()
+ && (formEditorItem->qmlItemNode().hasShowContent()))
+ return true;
+ }
+
+ foreach (QGraphicsItem *item, itemList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem
+ && !formEditorItem->qmlItemNode().isRootNode()
+ && selectedNodes.contains(formEditorItem->qmlItemNode()))
+ return true;
+ }
+
+ return false;
+
+}
+
+
+bool AbstractFormEditorTool::topItemIsResizeHandle(const QList<QGraphicsItem*> &/*itemList*/)
+{
+ return false;
+}
+
+QGraphicsItem *AbstractFormEditorTool::topMovableGraphicsItem(const QList<QGraphicsItem*> &itemList)
+{
+ foreach (QGraphicsItem *item, itemList) {
+ if (item->flags().testFlag(QGraphicsItem::ItemIsMovable))
+ return item;
+ }
+
+ return 0;
+}
+FormEditorItem *AbstractFormEditorTool::topMovableFormEditorItem(const QList<QGraphicsItem*> &itemList)
+{
+ foreach (QGraphicsItem *item, itemList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem
+ && (formEditorItem->qmlItemNode().hasShowContent()))
+ return formEditorItem;
+ }
+
+ return 0;
+}
+
+FormEditorItem* AbstractFormEditorTool::topFormEditorItem(const QList<QGraphicsItem*> & itemList)
+{
+ foreach (QGraphicsItem *item, itemList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem && !formEditorItem->qmlItemNode().isRootNode())
+ return formEditorItem;
+ }
+
+ return 0;
+}
+
+FormEditorItem* AbstractFormEditorTool::topFormEditorItemWithRootItem(const QList<QGraphicsItem*> & itemList)
+{
+ foreach (QGraphicsItem *item, itemList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem)
+ return formEditorItem;
+ }
+
+ return 0;
+}
+
+void AbstractFormEditorTool::dropEvent(QGraphicsSceneDragDropEvent * /* event */)
+{
+ Q_ASSERT(false);
+}
+
+void AbstractFormEditorTool::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
+{
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
+ event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ event->accept();
+ view()->changeToDragTool();
+ view()->currentTool()->dragEnterEvent(event);
+ } else {
+ event->ignore();
+ }
+}
+
+void AbstractFormEditorTool::dragLeaveEvent(QGraphicsSceneDragDropEvent * /* event */)
+{
+ Q_ASSERT(false);
+}
+
+void AbstractFormEditorTool::dragMoveEvent(QGraphicsSceneDragDropEvent * /* event */)
+{
+ Q_ASSERT(false);
+}
+
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h
new file mode 100644
index 0000000000..c2e387c696
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/abstractformeditortool.h
@@ -0,0 +1,103 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ABSTRACTFORMEDITORTOOL_H
+#define ABSTRACTFORMEDITORTOOL_H
+
+#include "formeditoritem.h"
+
+class QGraphicsItem;
+
+namespace QmlDesigner {
+
+class FormEditorView;
+
+class AbstractFormEditorTool
+{
+
+public:
+ AbstractFormEditorTool(FormEditorView* view);
+
+ virtual ~AbstractFormEditorTool();
+
+ virtual void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) = 0;
+ virtual void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) = 0;
+ virtual void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) = 0;
+ virtual void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) = 0;
+
+ virtual void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event) = 0;
+
+ virtual void dropEvent(QGraphicsSceneDragDropEvent * event);
+ virtual void dragEnterEvent(QGraphicsSceneDragDropEvent * event);
+ virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent * event);
+ virtual void dragMoveEvent(QGraphicsSceneDragDropEvent * event);
+
+ virtual void keyPressEvent(QKeyEvent *event) = 0;
+ virtual void keyReleaseEvent(QKeyEvent *keyEvent) = 0;
+
+ virtual void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList) = 0;
+ // virtual QVariant itemChange(QList<QGraphicsItem*> itemList,
+// QGraphicsItem::GraphicsItemChange change,
+// const QVariant &value ) = 0;
+// virtual void update() = 0;
+ virtual void clear() = 0;
+
+ virtual void formEditorItemsChanged(const QList<FormEditorItem*> &itemList) = 0;
+
+ void setItems(const QList<FormEditorItem*> &itemList);
+ QList<FormEditorItem*> items() const;
+
+ static QGraphicsItem* topMovableGraphicsItem(const QList<QGraphicsItem*> &itemList);
+ static FormEditorItem* topMovableFormEditorItem(const QList<QGraphicsItem*> &itemList);
+ bool topItemIsMovable(const QList<QGraphicsItem*> &itemList);
+ bool topSelectedItemIsMovable(const QList<QGraphicsItem*> &itemList);
+ bool topItemIsResizeHandle(const QList<QGraphicsItem*> &itemList);
+
+ static FormEditorItem* topFormEditorItem(const QList<QGraphicsItem*> &itemList);
+ static FormEditorItem* topFormEditorItemWithRootItem(const QList<QGraphicsItem*> &itemList);
+protected:
+
+ virtual void selectedItemsChanged(const QList<FormEditorItem*> &itemList) = 0;
+
+
+ FormEditorView *view() const;
+ FormEditorScene* scene() const;
+private:
+ FormEditorView *m_view;
+ QList<FormEditorItem*> m_itemList;
+};
+
+}
+
+#endif // ABSTRACTFORMEDITORTOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchor.png b/src/plugins/qmldesigner/components/formeditor/anchor.png
new file mode 100644
index 0000000000..fa59038318
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchor.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp
new file mode 100644
index 0000000000..e59712216c
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.cpp
@@ -0,0 +1,537 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchorcontroller.h"
+
+#include "formeditoritem.h"
+#include "layeritem.h"
+#include "formeditorscene.h"
+#include "anchorhandleitem.h"
+#include <QtDebug>
+#include <cmath>
+namespace QmlDesigner {
+
+AnchorControllerData::AnchorControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : layerItem(layerItem),
+ formEditorItem(formEditorItem),
+ topItem(0),
+ leftItem(0),
+ rightItem(0),
+ bottomItem(0)
+{
+}
+
+AnchorControllerData::AnchorControllerData(const AnchorControllerData &other)
+ : layerItem(other.layerItem),
+ formEditorItem(other.formEditorItem),
+ topItem(other.topItem),
+ leftItem(other.leftItem),
+ rightItem(other.rightItem),
+ bottomItem(other.bottomItem)
+{
+}
+
+AnchorControllerData::~AnchorControllerData()
+{
+ if (layerItem) {
+ layerItem->scene()->removeItem(topItem);
+ layerItem->scene()->removeItem(leftItem);
+ layerItem->scene()->removeItem(rightItem);
+ layerItem->scene()->removeItem(bottomItem);
+ }
+}
+
+
+AnchorController::AnchorController()
+ : m_data(new AnchorControllerData(0, 0))
+{
+
+}
+
+AnchorController::AnchorController(const QSharedPointer<AnchorControllerData> &data)
+ : m_data(data)
+{
+
+}
+
+AnchorController::AnchorController(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : m_data(new AnchorControllerData(layerItem, formEditorItem))
+{
+ m_data->topItem = new AnchorHandleItem(layerItem, *this);
+ m_data->topItem->setZValue(400);
+ m_data->topItem->setToolTip(m_data->topItem->toolTipString());
+
+ m_data->leftItem = new AnchorHandleItem(layerItem, *this);
+ m_data->leftItem->setZValue(400);
+ m_data->leftItem->setToolTip(m_data->leftItem->toolTipString());
+
+ m_data->rightItem = new AnchorHandleItem(layerItem, *this);
+ m_data->rightItem->setZValue(400);
+ m_data->rightItem->setToolTip(m_data->rightItem->toolTipString());
+
+ m_data->bottomItem = new AnchorHandleItem(layerItem, *this);
+ m_data->bottomItem->setZValue(400);
+ m_data->bottomItem->setToolTip(m_data->bottomItem->toolTipString());
+
+ m_data->sceneTransform = formEditorItem->sceneTransform();
+
+ updatePosition();
+}
+
+
+bool AnchorController::isValid() const
+{
+ return m_data->formEditorItem != 0;
+}
+
+void AnchorController::show()
+{
+ m_data->topItem->show();
+ m_data->leftItem->show();
+ m_data->rightItem->show();
+ m_data->bottomItem->show();
+}
+
+
+
+void AnchorController::hide()
+{
+ m_data->topItem->hide();
+ m_data->leftItem->hide();
+ m_data->rightItem->hide();
+ m_data->bottomItem->hide();
+}
+
+
+static QPointF topCenter(const QRectF &rect)
+{
+ return QPointF(rect.center().x(), rect.top());
+}
+
+static QPointF leftCenter(const QRectF &rect)
+{
+ return QPointF(rect.left(), rect.center().y());
+}
+
+static QPointF rightCenter(const QRectF &rect)
+{
+ return QPointF(rect.right(), rect.center().y());
+}
+
+static QPointF bottomCenter(const QRectF &rect)
+{
+ return QPointF(rect.center().x(), rect.bottom());
+}
+
+static QPainterPath curveToPath(const QPointF &firstPoint,
+ const QPointF &secondPoint,
+ const QPointF &thirdPoint,
+ const QPointF &fourthPoint)
+{
+ QPainterPath path;
+ path.moveTo(firstPoint);
+ path.cubicTo(secondPoint, thirdPoint, fourthPoint);
+
+ return path;
+}
+
+static QPointF anchorPoint(const QRectF &boundingRect, AnchorLine::Type anchorLine, double baseOffset, double innerOffset = 0.0)
+{
+ switch(anchorLine) {
+ case AnchorLine::Top : return topCenter(boundingRect) + QPointF(baseOffset, innerOffset);
+ case AnchorLine::Bottom : return bottomCenter(boundingRect) - QPointF(baseOffset, innerOffset);
+ case AnchorLine::Left : return leftCenter(boundingRect) + QPointF(innerOffset, baseOffset);
+ case AnchorLine::Right : return rightCenter(boundingRect) - QPointF(innerOffset, baseOffset);
+ default: return QPointF();
+ }
+
+ return QPointF();
+}
+
+
+static QPainterPath createArrowPath(QPointF arrowCenter, double arrowDegrees)
+{
+ QRectF arrowRect(0.0, 0.0, 16., 16.);
+ arrowRect.moveCenter(arrowCenter);
+ QPainterPath arrowPath;
+
+
+ arrowPath.moveTo(arrowCenter);
+
+ arrowPath.arcTo(arrowRect, arrowDegrees + 180 - 20, 40.);
+
+ return arrowPath;
+}
+
+AnchorHandlePathData AnchorController::createPainterPathForAnchor(const QRectF &boundingRect,
+ AnchorLine::Type anchorLine,
+ const QPointF &targetPoint) const
+{
+
+
+ QPointF firstPointInLayerSpace(m_data->sceneTransform.map(anchorPoint(boundingRect, anchorLine, 0.0, 5.0)));
+
+ QPointF topLeftBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.topLeft()));
+ QPointF bottomLeftBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.bottomLeft()));
+ QPointF topRightBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.topRight()));
+ QPointF bottomRightBoundingBoxInLayerSpace(m_data->sceneTransform.map(boundingRect.bottomRight()));
+
+ AnchorLine::Type secondAnchorLine(AnchorLine::Invalid);
+
+ QPointF secondPointInLayerSpace(targetPoint);
+ if (targetPoint.isNull()) {
+ AnchorLine targetAnchorLine(m_data->formEditorItem->qmlItemNode().anchors().instanceAnchor(anchorLine));
+ secondAnchorLine = targetAnchorLine.type();
+ FormEditorItem *targetItem = m_data->formEditorItem->scene()->itemForQmlItemNode(targetAnchorLine.qmlItemNode());;
+ bool secondItemIsParent = m_data->formEditorItem->parentItem() == targetItem;
+
+ if (secondItemIsParent)
+ secondPointInLayerSpace = (targetItem->mapToItem(m_data->layerItem.data(),
+ anchorPoint(targetItem->qmlItemNode().instanceBoundingRect(), targetAnchorLine.type(), 0.0)));
+ else
+
+ secondPointInLayerSpace = (targetItem->mapToItem(m_data->layerItem.data(),
+ anchorPoint(targetItem->qmlItemNode().instanceBoundingRect(), targetAnchorLine.type(), 0.0)));
+ }
+
+ QPointF firstControlPointInLayerSpace = (3. * firstPointInLayerSpace + 3 * secondPointInLayerSpace) / 6.;
+ QPointF secondControlPointInLayerSpace = (3 * firstPointInLayerSpace + 3. * secondPointInLayerSpace) / 6.;
+
+ bool showAnchorLine(true);
+ switch (anchorLine) {
+ case AnchorLine::Top :
+ case AnchorLine::Bottom :
+ firstControlPointInLayerSpace.rx() = firstPointInLayerSpace.x();
+ if (qAbs(secondPointInLayerSpace.y() - firstPointInLayerSpace.y()) < 18.0)
+ showAnchorLine = false;
+ if (qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) < 20.0 &&
+ qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) > 20.0) {
+ firstControlPointInLayerSpace.ry() = firstPointInLayerSpace.y() + ((firstControlPointInLayerSpace.y() - firstPointInLayerSpace.y() > 0) ? 20 : -20);
+ }
+ break;
+ case AnchorLine::Left :
+ case AnchorLine::Right :
+ firstControlPointInLayerSpace.ry() = firstPointInLayerSpace.y();
+ if (qAbs(secondPointInLayerSpace.x() - firstPointInLayerSpace.x()) < 18.0)
+ showAnchorLine = false;
+ if (qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) < 20.0 &&
+ qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) > 20.0) {
+ firstControlPointInLayerSpace.rx() = firstPointInLayerSpace.x() + ((firstControlPointInLayerSpace.x() - firstPointInLayerSpace.x() > 0) ? 20 : -20);
+ }
+ break;
+ default: break;
+ }
+
+ switch(secondAnchorLine) {
+ case AnchorLine::Top :
+ case AnchorLine::Bottom :
+ secondControlPointInLayerSpace.rx() = secondPointInLayerSpace.x();
+ if (qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) < 20.0 &&
+ qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) > 20.0) {
+ secondControlPointInLayerSpace.ry() = secondPointInLayerSpace.y() + ((secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y() < 0) ? 20 : -20);
+ }
+ break;
+ case AnchorLine::Left :
+ case AnchorLine::Right :
+ secondControlPointInLayerSpace.ry() = secondPointInLayerSpace.y();
+ if (qAbs(secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x()) < 20.0 &&
+ qAbs(secondControlPointInLayerSpace.y() - secondPointInLayerSpace.y()) > 20.0) {
+ secondControlPointInLayerSpace.rx() = secondPointInLayerSpace.x() + ((secondControlPointInLayerSpace.x() - secondPointInLayerSpace.x() < 0) ? 20 : -20);
+ }
+ break;
+ default: break;
+ }
+
+ QPainterPath anchorLinePath;
+ anchorLinePath.setFillRule(Qt::WindingFill);
+
+ QRectF baseRect(0.0, 0.0, 5., 5.);
+ baseRect.moveCenter(firstPointInLayerSpace);
+ QPainterPath basePath;
+ basePath.addRoundedRect(baseRect, 6., 6.);
+ anchorLinePath = anchorLinePath.united(basePath);
+
+ QRectF baseLineRect;
+ switch (anchorLine) {
+ case AnchorLine::Left : {
+ baseLineRect = QRectF(topLeftBoundingBoxInLayerSpace, bottomLeftBoundingBoxInLayerSpace);
+ baseLineRect.setWidth(3);
+ }
+ break;
+ case AnchorLine::Top : {
+ baseLineRect = QRectF(topLeftBoundingBoxInLayerSpace, topRightBoundingBoxInLayerSpace);
+ baseLineRect.setHeight(3);
+ }
+ break;
+ case AnchorLine::Right : {
+ baseLineRect = QRectF(topRightBoundingBoxInLayerSpace, bottomRightBoundingBoxInLayerSpace);
+ baseLineRect.adjust(-3, 0, 0, 0);
+ }
+ break;
+ case AnchorLine::Bottom : {
+ baseLineRect = QRectF(bottomLeftBoundingBoxInLayerSpace, bottomRightBoundingBoxInLayerSpace);
+ baseLineRect.adjust(0, -3, 0, 0);
+ }
+ break;
+ default: break;
+ }
+
+ if (!baseLineRect.isEmpty()) {
+
+ QPainterPath baseLinePath;
+ baseLinePath.addRoundedRect(baseLineRect, 1., 1.);
+ anchorLinePath = anchorLinePath.united(baseLinePath);
+ }
+
+ QPainterPath arrowPath;
+ arrowPath.setFillRule(Qt::WindingFill);
+
+
+
+ if (showAnchorLine) {
+ QPainterPath curvePath(curveToPath(firstPointInLayerSpace,
+ firstControlPointInLayerSpace,
+ secondControlPointInLayerSpace,
+ secondPointInLayerSpace));
+
+ double arrowDegrees = curvePath.angleAtPercent(curvePath.percentAtLength(curvePath.length() - 2.5));
+
+
+
+ QPainterPathStroker arrowPathStroker;
+ arrowPathStroker.setWidth(2.0);
+ arrowPathStroker.setCapStyle(Qt::RoundCap);
+
+ arrowPath = arrowPath.united(arrowPathStroker.createStroke(curvePath));
+
+
+
+
+
+ QRectF arrowCutRect(0.0, 0.0, 8., 8.);
+ arrowCutRect.moveCenter(secondPointInLayerSpace);
+ QPainterPath arrowCutPath;
+ arrowCutPath.addRect(arrowCutRect);
+ arrowPath = arrowPath.subtracted(arrowCutPath);
+
+ arrowPath = arrowPath.united(createArrowPath(secondPointInLayerSpace, arrowDegrees));
+ }
+
+ AnchorHandlePathData pathData;
+ pathData.arrowPath = arrowPath;
+ pathData.sourceAnchorLinePath = anchorLinePath;
+ pathData.beginArrowPoint = firstPointInLayerSpace;
+ pathData.endArrowPoint = secondPointInLayerSpace;
+
+ pathData.targetAnchorLinePath = createTargetAnchorLinePath(anchorLine);
+ pathData.targetNamePath = createTargetNamePathPath(anchorLine);
+
+ return pathData;
+}
+
+QPainterPath AnchorController::createTargetNamePathPath(AnchorLine::Type anchorLine) const
+{
+ QPainterPath path;
+ QmlAnchors anchors(formEditorItem()->qmlItemNode().anchors());
+ if (anchors.instanceHasAnchor(anchorLine)) {
+ AnchorLine targetAnchorLine(anchors.instanceAnchor(anchorLine));
+
+ FormEditorItem *targetItem = formEditorItem()->scene()->itemForQmlItemNode(targetAnchorLine.qmlItemNode());
+ QRectF boundingRect(targetItem->qmlItemNode().instanceBoundingRect());
+
+ QTransform sceneTransform(targetItem->qmlItemNode().instanceSceneTransform());
+
+ QPointF centerBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.center()));
+
+ QFont font;
+ font.setPixelSize(24);
+ QString nameString(QString("%1 (%2)").arg(targetAnchorLine.qmlItemNode().simplfiedTypeName()).arg(targetAnchorLine.qmlItemNode().id()));
+ path.addText(0., -4., font, nameString);
+ //path.translate(centerBoundingBoxInLayerSpace - path.qmlItemNode().instanceBoundingRect().center());
+
+ }
+
+ return path;
+}
+
+QPainterPath AnchorController::createTargetAnchorLinePath(AnchorLine::Type anchorLine) const
+{
+ QPainterPath path;
+ QmlAnchors anchors(formEditorItem()->qmlItemNode().anchors());
+ if (anchors.instanceHasAnchor(anchorLine)) {
+ AnchorLine targetAnchorLine(anchors.instanceAnchor(anchorLine));
+
+ FormEditorItem *targetItem = formEditorItem()->scene()->itemForQmlItemNode(targetAnchorLine.qmlItemNode());
+ QRectF boundingRect(targetItem->qmlItemNode().instanceBoundingRect());
+
+ QTransform sceneTransform(targetItem->qmlItemNode().instanceSceneTransform());
+
+ QPointF topLeftBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.topLeft()));
+ QPointF bottomLeftBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.bottomLeft()));
+ QPointF topRightBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.topRight()));
+ QPointF bottomRightBoundingBoxInLayerSpace(sceneTransform.map(boundingRect.bottomRight()));
+
+
+ switch(targetAnchorLine.type()) {
+ case AnchorLine::Top : {
+ path.moveTo(topLeftBoundingBoxInLayerSpace);
+ path.lineTo(topRightBoundingBoxInLayerSpace);
+ }
+ break;
+ case AnchorLine::Bottom : {
+ path.moveTo(bottomLeftBoundingBoxInLayerSpace);
+ path.lineTo(bottomRightBoundingBoxInLayerSpace);
+ }
+ break;
+ case AnchorLine::Left : {
+ path.moveTo(topLeftBoundingBoxInLayerSpace);
+ path.lineTo(bottomLeftBoundingBoxInLayerSpace);
+ }
+ break;
+ case AnchorLine::Right : {
+ path.moveTo(topRightBoundingBoxInLayerSpace);
+ path.lineTo(bottomRightBoundingBoxInLayerSpace);
+ }
+ break;
+ default: break;
+ }
+
+ QPainterPathStroker pathStroker;
+ pathStroker.setWidth(20.0);
+ pathStroker.setCapStyle(Qt::RoundCap);
+ path = pathStroker.createStroke(path);
+
+
+ }
+
+ return path;
+}
+
+void AnchorController::updatePosition()
+{
+ QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect();
+ QPointF beginPoint;
+ QPointF endPoint;
+ QmlAnchors anchors(m_data->formEditorItem->qmlItemNode().anchors());
+ m_data->sceneTransform = m_data->formEditorItem->sceneTransform();
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top))
+ m_data->topItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Top));
+ else
+ m_data->topItem->setHandlePath(AnchorHandlePathData());
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom))
+ m_data->bottomItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Bottom));
+ else
+ m_data->bottomItem->setHandlePath(AnchorHandlePathData());
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right))
+ m_data->rightItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Right));
+ else
+ m_data->rightItem->setHandlePath(AnchorHandlePathData());
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left))
+ m_data->leftItem->setHandlePath(createPainterPathForAnchor(boundingRect, AnchorLine::Left));
+ else
+ m_data->leftItem->setHandlePath(AnchorHandlePathData());
+}
+
+
+FormEditorItem* AnchorController::formEditorItem() const
+{
+ return m_data->formEditorItem;
+}
+
+QWeakPointer<AnchorControllerData> AnchorController::weakPointer() const
+{
+ return m_data;
+}
+
+
+bool AnchorController::isTopHandle(const AnchorHandleItem *handle) const
+{
+ return handle == m_data->topItem;
+}
+
+bool AnchorController::isLeftHandle(const AnchorHandleItem *handle) const
+{
+ return handle == m_data->leftItem;
+}
+
+bool AnchorController::isRightHandle(const AnchorHandleItem *handle) const
+{
+ return handle == m_data->rightItem;
+}
+
+bool AnchorController::isBottomHandle(const AnchorHandleItem *handle) const
+{
+ return handle == m_data->bottomItem;
+}
+
+void AnchorController::updateTargetPoint(AnchorLine::Type anchorLine, const QPointF &targetPoint)
+{
+ QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect();
+
+ switch(anchorLine) {
+ case AnchorLine::Top :
+ m_data->topItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break;
+ case AnchorLine::Bottom :
+ m_data->bottomItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break;
+ case AnchorLine::Left :
+ m_data->leftItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break;
+ case AnchorLine::Right :
+ m_data->rightItem->setHandlePath(createPainterPathForAnchor(boundingRect, anchorLine, targetPoint)); break;
+ default: break;
+ }
+}
+
+void AnchorController::highlight(AnchorLine::Type anchorLine)
+{
+ switch(anchorLine) {
+ case AnchorLine::Top :
+ m_data->topItem->setHighlighted(true); break;
+ case AnchorLine::Bottom :
+ m_data->bottomItem->setHighlighted(true); break;
+ case AnchorLine::Left :
+ m_data->leftItem->setHighlighted(true); break;
+ case AnchorLine::Right :
+ m_data->rightItem->setHighlighted(true); break;
+ default: break;
+ }
+}
+
+void AnchorController::clearHighlight()
+{
+ m_data->topItem->setHighlighted(false);
+ m_data->leftItem->setHighlighted(false);
+ m_data->rightItem->setHighlighted(false);
+ m_data->bottomItem->setHighlighted(false);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorcontroller.h b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.h
new file mode 100644
index 0000000000..4d693dd4b0
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorcontroller.h
@@ -0,0 +1,117 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORCONTROLLER_H
+#define ANCHORCONTROLLER_H
+
+#include <QSharedPointer>
+#include <QPainterPath>
+#include <QPair>
+#include <QTransform>
+#include <qmlanchors.h>
+
+namespace QmlDesigner {
+
+struct AnchorHandlePathData
+{
+ QPainterPath sourceAnchorLinePath;
+ QPainterPath targetAnchorLinePath;
+ QPainterPath arrowPath;
+ QPainterPath targetNamePath;
+ QPointF beginArrowPoint;
+ QPointF endArrowPoint;
+};
+
+class FormEditorItem;
+class LayerItem;
+class AnchorHandleItem;
+
+class AnchorControllerData
+{
+public:
+ AnchorControllerData(LayerItem *layerItem,
+ FormEditorItem *formEditorItem);
+ AnchorControllerData(const AnchorControllerData &other);
+ ~AnchorControllerData();
+
+ QWeakPointer<LayerItem> layerItem;
+ FormEditorItem *formEditorItem;
+
+ AnchorHandleItem *topItem;
+ AnchorHandleItem *leftItem;
+ AnchorHandleItem *rightItem;
+ AnchorHandleItem *bottomItem;
+
+ QTransform sceneTransform;
+};
+
+
+class AnchorController
+{
+ public:
+ AnchorController();
+ AnchorController(LayerItem *layerItem, FormEditorItem *formEditorItem);
+ AnchorController(const QSharedPointer<AnchorControllerData> &data);
+
+
+ void show();
+ void hide();
+
+ void updatePosition();
+
+ bool isValid() const;
+
+ QWeakPointer<AnchorControllerData> weakPointer() const;
+
+
+ FormEditorItem *formEditorItem() const;
+
+ bool isTopHandle(const AnchorHandleItem *handle) const;
+ bool isLeftHandle(const AnchorHandleItem *handle) const;
+ bool isRightHandle(const AnchorHandleItem *handle) const;
+ bool isBottomHandle(const AnchorHandleItem *handle) const;
+
+ void updateTargetPoint(AnchorLine::Type anchorLine, const QPointF &targetPoint);
+
+ void clearHighlight();
+ void highlight(AnchorLine::Type anchorLine);
+
+private: //functions
+ AnchorHandlePathData createPainterPathForAnchor(const QRectF &boundingRect,
+ AnchorLine::Type anchorLine,
+ const QPointF &targetPoint = QPointF()) const;
+ QPainterPath createTargetAnchorLinePath(AnchorLine::Type anchorLine) const;
+ QPainterPath createTargetNamePathPath(AnchorLine::Type anchorLine) const;
+private:
+ QSharedPointer<AnchorControllerData> m_data;
+};
+
+} // namespace QmlDesigner
+
+#endif // ANCHORCONTROLLER_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp
new file mode 100644
index 0000000000..95939c6e0f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.cpp
@@ -0,0 +1,212 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchorhandleitem.h"
+
+#include <formeditoritem.h>
+#include <QPen>
+#include <QPainterPathStroker>
+#include <cmath>
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+AnchorHandleItem::AnchorHandleItem(QGraphicsItem *parent, const AnchorController &anchorController)
+ : QGraphicsItemGroup(parent),
+ m_anchorControllerData(anchorController.weakPointer()),
+ m_sourceAnchorLinePathItem(new QGraphicsPathItem(this)),
+ m_arrowPathItem(new QGraphicsPathItem(this)),
+ m_targetAnchorLinePathItem(new QGraphicsPathItem(this)),
+ m_targetNamePathItem(new QGraphicsPathItem(this))
+{
+ addToGroup(m_sourceAnchorLinePathItem);
+ addToGroup(m_arrowPathItem);
+ addToGroup(m_targetAnchorLinePathItem);
+ addToGroup(m_targetNamePathItem);
+
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+}
+
+AnchorLine::Type AnchorHandleItem::sourceAnchorLine() const
+{
+ if (isTopHandle())
+ return AnchorLine::Top;
+ if (isBottomHandle())
+ return AnchorLine::Bottom;
+ if (isLeftHandle())
+ return AnchorLine::Left;
+ if (isRightHandle())
+ return AnchorLine::Right;
+
+ return AnchorLine::Invalid;
+}
+
+AnchorLine AnchorHandleItem::targetAnchorLine() const
+{
+ QmlAnchors anchors(anchorController().formEditorItem()->qmlItemNode().anchors());
+
+ if (isTopHandle())
+ return anchors.instanceAnchor(AnchorLine::Top);
+ if (isBottomHandle())
+ return anchors.instanceAnchor(AnchorLine::Bottom);
+ if (isLeftHandle())
+ return anchors.instanceAnchor(AnchorLine::Left);
+ if (isRightHandle())
+ return anchors.instanceAnchor(AnchorLine::Right);
+
+ return AnchorLine();
+}
+
+static QString anchorLineToString(AnchorLine::Type anchorLineType)
+{
+ switch(anchorLineType) {
+ case AnchorLine::Top: return "Top";
+ case AnchorLine::Bottom: return "Bottom";
+ case AnchorLine::Left: return "Left";
+ case AnchorLine::Right: return "Right";
+ default: break;
+ }
+
+ return QString();
+
+}
+
+QString AnchorHandleItem::toolTipString() const
+{
+ QString templateString("<p>Anchor Handle</p><p>%1</p><p>%2</p>");
+ QmlItemNode fromNode(anchorController().formEditorItem()->qmlItemNode());
+ QString fromString(QString("%3: %1(%2)").arg(fromNode.simplfiedTypeName(), fromNode.id(), anchorLineToString(sourceAnchorLine())));
+
+ AnchorLine toAnchorLine(targetAnchorLine());
+ QmlItemNode toNode(toAnchorLine.qmlItemNode());
+ QString toString;
+ if (toNode.isValid())
+ toString = QString("%3: %1(%2)").arg(toNode.simplfiedTypeName(), toNode.id(), anchorLineToString(toAnchorLine.type()));
+
+ return templateString.arg(fromString).arg(toString);
+}
+
+void AnchorHandleItem::setHandlePath(const AnchorHandlePathData &pathData)
+{
+ m_beginArrowPoint = pathData.beginArrowPoint;
+ m_endArrowPoint = pathData.endArrowPoint;
+ m_arrowPathItem->setPath(pathData.arrowPath);
+ m_sourceAnchorLinePathItem->setPath(pathData.sourceAnchorLinePath);
+ m_targetAnchorLinePathItem->setPath(pathData.targetAnchorLinePath);
+ m_targetNamePathItem->setPath(pathData.targetNamePath);
+
+ setHighlighted(false);
+}
+
+AnchorController AnchorHandleItem::anchorController() const
+{
+ Q_ASSERT(!m_anchorControllerData.isNull());
+ return AnchorController(m_anchorControllerData.toStrongRef());
+}
+
+AnchorHandleItem* AnchorHandleItem::fromGraphicsItem(QGraphicsItem *item)
+{
+ return qgraphicsitem_cast<AnchorHandleItem*>(item);
+}
+
+bool AnchorHandleItem::isTopHandle() const
+{
+ return anchorController().isTopHandle(this);
+}
+
+bool AnchorHandleItem::isLeftHandle() const
+{
+ return anchorController().isLeftHandle(this);
+}
+
+bool AnchorHandleItem::isRightHandle() const
+{
+ return anchorController().isRightHandle(this);
+}
+
+bool AnchorHandleItem::isBottomHandle() const
+{
+ return anchorController().isBottomHandle(this);
+}
+
+AnchorLine::Type AnchorHandleItem::anchorType() const
+{
+ if (isTopHandle())
+ return AnchorLine::Top;
+
+ if (isBottomHandle())
+ return AnchorLine::Bottom;
+
+ if (isLeftHandle())
+ return AnchorLine::Left;
+
+ if (isRightHandle())
+ return AnchorLine::Right;
+
+
+ return AnchorLine::Invalid;
+}
+
+void AnchorHandleItem::setHighlighted(bool highlight)
+{
+ QLinearGradient gradient(m_beginArrowPoint, m_endArrowPoint);
+ gradient.setCoordinateMode(QGradient::LogicalMode);
+ m_arrowPathItem->setPen(QPen(QBrush(Qt::gray), 1.0, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
+ m_targetAnchorLinePathItem->setPen(QColor(70, 0, 0, 90));
+ m_targetAnchorLinePathItem->setBrush(QColor(255, 0, 0, 50));
+ m_arrowPathItem->setPen(QPen(QBrush(Qt::gray), 1.0, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
+ m_targetNamePathItem->setPen(QColor(0, 0, 255, 90));
+ m_targetNamePathItem->setBrush(QColor(0, 0, 255, 50));
+
+ if (highlight) {
+ gradient.setColorAt(0.0, QColor(0, 0, 120, 255));
+ gradient.setColorAt(1.0, QColor(120, 0, 0, 255));
+ m_arrowPathItem->setBrush(gradient);
+ m_sourceAnchorLinePathItem->setPen(QColor(0, 0, 70, 255));
+ m_sourceAnchorLinePathItem->setBrush(QColor(0, 0, 70, 255));
+ m_targetAnchorLinePathItem->show();
+ m_targetNamePathItem->show();
+
+ } else {
+ gradient.setColorAt(0.0, QColor(0, 0, 255, 255));
+ gradient.setColorAt(1.0, QColor(255, 0, 0, 255));
+ m_arrowPathItem->setBrush(gradient);
+ m_sourceAnchorLinePathItem->setPen(QColor(0, 0, 100, 255));
+ m_sourceAnchorLinePathItem->setBrush(QColor(0, 0, 100, 255));
+ m_targetAnchorLinePathItem->hide();
+ m_targetNamePathItem->hide();
+ }
+}
+
+QPointF AnchorHandleItem::itemSpacePosition() const
+{
+ return parentItem()->mapToItem(anchorController().formEditorItem(), pos());
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h
new file mode 100644
index 0000000000..6d6bd057f7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorhandleitem.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORHANDLEITEM_H
+#define ANCHORHANDLEITEM_H
+
+#include <QGraphicsItemGroup>
+
+#include "anchorcontroller.h"
+
+namespace QmlDesigner {
+
+class AnchorHandleItem : public QGraphicsItemGroup
+{
+public:
+ enum
+ {
+ Type = 0xEAEC
+ };
+
+
+ AnchorHandleItem(QGraphicsItem *parent, const AnchorController &anchorController);
+
+ void setHandlePath(const AnchorHandlePathData &pathData);
+
+ int type() const;
+
+ AnchorController anchorController() const;
+
+ static AnchorHandleItem* fromGraphicsItem(QGraphicsItem *item);
+
+
+ bool isTopHandle() const;
+ bool isLeftHandle() const;
+ bool isRightHandle() const;
+ bool isBottomHandle() const;
+
+ QPointF itemSpacePosition() const;
+
+ AnchorLine::Type anchorType() const;
+
+ QString toolTipString() const;
+ AnchorLine targetAnchorLine() const;
+ AnchorLine::Type sourceAnchorLine() const;
+
+ void setHighlighted(bool highlight);
+
+private:
+ QWeakPointer<AnchorControllerData> m_anchorControllerData;
+ QGraphicsPathItem *m_sourceAnchorLinePathItem;
+ QGraphicsPathItem *m_arrowPathItem;
+ QGraphicsPathItem *m_targetAnchorLinePathItem;
+ QGraphicsPathItem *m_targetNamePathItem;
+ QPointF m_beginArrowPoint;
+ QPointF m_endArrowPoint;
+};
+
+inline int AnchorHandleItem::type() const
+{
+ return Type;
+}
+
+} // namespace QmlDesigner
+
+#endif // ANCHORHANDLEITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp b/src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp
new file mode 100644
index 0000000000..78762c23f7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorindicator.cpp
@@ -0,0 +1,116 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchorindicator.h"
+
+#include <QSet>
+
+namespace QmlDesigner {
+
+AnchorIndicator::AnchorIndicator(LayerItem *layerItem)
+ : m_layerItem(layerItem)
+{
+ Q_ASSERT(layerItem);
+}
+
+AnchorIndicator::~AnchorIndicator()
+{
+ m_itemControllerHash.clear();
+}
+
+void AnchorIndicator::show()
+{
+ QHashIterator<FormEditorItem*, AnchorController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ AnchorController controller = itemControllerIterator.next().value();
+ controller.show();
+ }
+}
+
+
+void AnchorIndicator::hide()
+{
+ QHashIterator<FormEditorItem*, AnchorController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ AnchorController controller = itemControllerIterator.next().value();
+ controller.hide();
+ }
+}
+
+void AnchorIndicator::clear()
+{
+ m_itemControllerHash.clear();
+}
+
+void AnchorIndicator::setItems(const QList<FormEditorItem*> &itemList)
+{
+ clear();
+
+ foreach (FormEditorItem *item, itemList) {
+ AnchorController controller(m_layerItem, item);
+ m_itemControllerHash.insert(item, controller);
+ }
+
+ updateItems(itemList);
+}
+
+void AnchorIndicator::updateItems(const QList<FormEditorItem*> &itemList)
+{
+ foreach (FormEditorItem *item, itemList) {
+ if (m_itemControllerHash.contains(item)) {
+ AnchorController controller(m_itemControllerHash.value(item));
+ controller.updatePosition();
+ }
+ }
+}
+
+void AnchorIndicator::updateTargetPoint(FormEditorItem *item, AnchorLine::Type anchorLine, const QPointF &targetPoint)
+{
+ AnchorController controller(m_itemControllerHash.value(item));
+ controller.updateTargetPoint(anchorLine, targetPoint);
+}
+
+void AnchorIndicator::clearHighlight()
+{
+ QHashIterator<FormEditorItem*, AnchorController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ AnchorController controller = itemControllerIterator.next().value();
+ controller.clearHighlight();
+ }
+}
+
+void AnchorIndicator::highlight(FormEditorItem *item, AnchorLine::Type anchorLine)
+{
+ if (m_itemControllerHash.contains(item)) {
+ AnchorController controller(m_itemControllerHash.value(item));
+ controller.highlight(anchorLine);
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorindicator.h b/src/plugins/qmldesigner/components/formeditor/anchorindicator.h
new file mode 100644
index 0000000000..c36ed04be8
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorindicator.h
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORINDICATOR_H
+#define ANCHORINDICATOR_H
+
+#include "anchorcontroller.h"
+#include <QList>
+#include <QHash>
+
+namespace QmlDesigner {
+
+class AnchorIndicator
+{
+public:
+ AnchorIndicator(LayerItem *layerItem);
+ ~AnchorIndicator();
+
+ void show();
+ void hide();
+ void clear();
+
+ void setItems(const QList<FormEditorItem*> &itemList);
+
+ void updateItems(const QList<FormEditorItem*> &itemList);
+ void updateTargetPoint(FormEditorItem *item, AnchorLine::Type anchorLine, const QPointF &targetPoint);
+
+ void clearHighlight();
+ void highlight(FormEditorItem *item, AnchorLine::Type anchorLine);
+
+private:
+ QHash<FormEditorItem*, AnchorController> m_itemControllerHash;
+ LayerItem *m_layerItem;
+};
+
+} // namespace QmlDesigner
+
+#endif // ANCHORINDICATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp
new file mode 100644
index 0000000000..6877ad1b0f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.cpp
@@ -0,0 +1,236 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchorlinecontroller.h"
+
+#include "formeditoritem.h"
+#include "layeritem.h"
+#include <QGraphicsScene>
+
+#include "anchorlinehandleitem.h"
+
+namespace QmlDesigner {
+
+
+AnchorLineControllerData::AnchorLineControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : layerItem(layerItem),
+ formEditorItem(formEditorItem),
+ topItem(0),
+ leftItem(0),
+ rightItem(0),
+ bottomItem(0)
+{
+}
+
+AnchorLineControllerData::AnchorLineControllerData(const AnchorLineControllerData &other)
+ : layerItem(other.layerItem),
+ formEditorItem(other.formEditorItem),
+ topItem(other.topItem),
+ leftItem(other.leftItem),
+ rightItem(other.rightItem),
+ bottomItem(other.bottomItem)
+{}
+
+AnchorLineControllerData::~AnchorLineControllerData()
+{
+ if (layerItem) {
+ layerItem->scene()->removeItem(topItem);
+ layerItem->scene()->removeItem(leftItem);
+ layerItem->scene()->removeItem(rightItem);
+ layerItem->scene()->removeItem(bottomItem);
+ }
+}
+
+
+AnchorLineController::AnchorLineController()
+ : m_data(new AnchorLineControllerData(0, 0))
+{
+
+}
+
+AnchorLineController::AnchorLineController(const QSharedPointer<AnchorLineControllerData> &data)
+ : m_data(data)
+{
+
+}
+
+AnchorLineController::AnchorLineController(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : m_data(new AnchorLineControllerData(layerItem, formEditorItem))
+{
+ m_data->topItem = new AnchorLineHandleItem(layerItem, *this);
+ m_data->topItem->setZValue(300);
+
+ m_data->leftItem = new AnchorLineHandleItem(layerItem, *this);
+ m_data->leftItem->setZValue(300);
+
+ m_data->rightItem = new AnchorLineHandleItem(layerItem, *this);
+ m_data->rightItem->setZValue(300);
+
+ m_data->bottomItem = new AnchorLineHandleItem(layerItem, *this);
+ m_data->bottomItem->setZValue(300);
+
+ updatePosition();
+}
+
+
+bool AnchorLineController::isValid() const
+{
+ return m_data->formEditorItem != 0;
+}
+
+void AnchorLineController::show(AnchorLine::Type anchorLineMask)
+{
+ if (anchorLineMask & AnchorLine::Top)
+ m_data->topItem->show();
+ else
+ m_data->topItem->hide();
+
+ if (anchorLineMask & AnchorLine::Left)
+ m_data->leftItem->show();
+ else
+ m_data->leftItem->hide();
+
+ if (anchorLineMask & AnchorLine::Right)
+ m_data->rightItem->show();
+ else
+ m_data->rightItem->hide();
+
+ if (anchorLineMask & AnchorLine::Bottom)
+ m_data->bottomItem->show();
+ else
+ m_data->bottomItem->hide();
+}
+
+void AnchorLineController::hide()
+{
+ m_data->topItem->hide();
+ m_data->leftItem->hide();
+ m_data->rightItem->hide();
+ m_data->bottomItem->hide();
+}
+
+static QPainterPath rectToPath(const QRectF &rect)
+{
+ QPainterPath path;
+ path.addRoundedRect(rect, 4, 4);
+
+ return path;
+}
+
+void AnchorLineController::updatePosition()
+{
+ QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect();
+
+ QRectF topBoundingRect(boundingRect);
+ QRectF leftBoundingRect(boundingRect);
+ QRectF bottomBoundingRect(boundingRect);
+ QRectF rightBoundingRect(boundingRect);
+
+
+ if (formEditorItem()->isContainer()) {
+ topBoundingRect.setBottom(boundingRect.top() + 6);
+ topBoundingRect.adjust(7, -5, -7, 0);
+
+ leftBoundingRect.setRight(boundingRect.left() + 6);
+ leftBoundingRect.adjust(-5, 7, 0, -7);
+
+ bottomBoundingRect.setTop(boundingRect.bottom() - 6);
+ bottomBoundingRect.adjust(7, 0, -7, 5);
+
+ rightBoundingRect.setLeft(boundingRect.right() - 6);
+ rightBoundingRect.adjust(0, 7, 5, -7);
+
+ } else {
+ double height = qMin(boundingRect.height() / 4., 10.);
+ double width = qMin(boundingRect.width() / 4., 10.);
+
+ topBoundingRect.setHeight(height);
+ topBoundingRect.adjust(width, -4, -width, -1);
+
+ leftBoundingRect.setWidth(width);
+ leftBoundingRect.adjust(-4, height, -1, -height);
+
+ bottomBoundingRect.setTop(boundingRect.bottom() - height);
+ bottomBoundingRect.adjust(width, 1, -width, 4);
+
+ rightBoundingRect.setLeft(boundingRect.right() - width);
+ rightBoundingRect.adjust(1, height, 4, -height);
+ }
+
+ m_data->topItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ rectToPath(topBoundingRect)));
+ m_data->leftItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ rectToPath(leftBoundingRect)));
+ m_data->bottomItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ rectToPath(bottomBoundingRect)));
+ m_data->rightItem->setHandlePath(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ rectToPath(rightBoundingRect)));
+}
+
+
+FormEditorItem* AnchorLineController::formEditorItem() const
+{
+ return m_data->formEditorItem;
+}
+
+QWeakPointer<AnchorLineControllerData> AnchorLineController::weakPointer() const
+{
+ return m_data;
+}
+
+
+bool AnchorLineController::isTopHandle(const AnchorLineHandleItem *handle) const
+{
+ return handle == m_data->topItem;
+}
+
+bool AnchorLineController::isLeftHandle(const AnchorLineHandleItem *handle) const
+{
+ return handle == m_data->leftItem;
+}
+
+bool AnchorLineController::isRightHandle(const AnchorLineHandleItem *handle) const
+{
+ return handle == m_data->rightItem;
+}
+
+bool AnchorLineController::isBottomHandle(const AnchorLineHandleItem *handle) const
+{
+ return handle == m_data->bottomItem;
+}
+
+void AnchorLineController::clearHighlight()
+{
+ m_data->topItem->setHiglighted(false);
+ m_data->leftItem->setHiglighted(false);
+ m_data->rightItem->setHiglighted(false);
+ m_data->bottomItem->setHiglighted(false);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h
new file mode 100644
index 0000000000..98701705e0
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorlinecontroller.h
@@ -0,0 +1,93 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORLINECONTROLLER_H
+#define ANCHORLINECONTROLLER_H
+
+#include <QWeakPointer>
+#include <QSharedPointer>
+#include <qmlanchors.h>
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+class LayerItem;
+class AnchorLineHandleItem;
+
+class AnchorLineControllerData
+{
+public:
+ AnchorLineControllerData(LayerItem *layerItem,
+ FormEditorItem *formEditorItem);
+ AnchorLineControllerData(const AnchorLineControllerData &other);
+ ~AnchorLineControllerData();
+
+ QWeakPointer<LayerItem> layerItem;
+ FormEditorItem *formEditorItem;
+
+ AnchorLineHandleItem *topItem;
+ AnchorLineHandleItem *leftItem;
+ AnchorLineHandleItem *rightItem;
+ AnchorLineHandleItem *bottomItem;
+};
+
+
+class AnchorLineController
+{
+ public:
+ AnchorLineController();
+ AnchorLineController(LayerItem *layerItem, FormEditorItem *formEditorItem);
+ AnchorLineController(const QSharedPointer<AnchorLineControllerData> &data);
+
+ void show(AnchorLine::Type anchorLineMask);
+ void hide();
+
+ void updatePosition();
+
+ bool isValid() const;
+
+ QWeakPointer<AnchorLineControllerData> weakPointer() const;
+
+
+ FormEditorItem *formEditorItem() const;
+
+ bool isTopHandle(const AnchorLineHandleItem *handle) const;
+ bool isLeftHandle(const AnchorLineHandleItem *handle) const;
+ bool isRightHandle(const AnchorLineHandleItem *handle) const;
+ bool isBottomHandle(const AnchorLineHandleItem *handle) const;
+
+ void clearHighlight();
+
+private:
+ QSharedPointer<AnchorLineControllerData> m_data;
+};
+
+} // namespace QmlDesigner
+
+#endif // ANCHORLINECONTROLLER_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp
new file mode 100644
index 0000000000..e2aa10b67f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.cpp
@@ -0,0 +1,148 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchorlinehandleitem.h"
+
+#include <formeditoritem.h>
+#include <QPen>
+#include <cmath>
+
+namespace QmlDesigner {
+
+AnchorLineHandleItem::AnchorLineHandleItem(QGraphicsItem *parent, const AnchorLineController &anchorLineController)
+ : QGraphicsPathItem(parent),
+ m_anchorLineControllerData(anchorLineController.weakPointer())
+{
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ setHiglighted(false);
+}
+
+void AnchorLineHandleItem::setHandlePath(const QPainterPath & path)
+{
+ setPath(path);
+ update();
+}
+
+QRectF AnchorLineHandleItem::boundingRect() const
+{
+ return QGraphicsPathItem::boundingRect();
+}
+
+QPainterPath AnchorLineHandleItem::shape() const
+{
+ return QGraphicsPathItem::shape();
+}
+
+AnchorLineController AnchorLineHandleItem::anchorLineController() const
+{
+ Q_ASSERT(!m_anchorLineControllerData.isNull());
+ return AnchorLineController(m_anchorLineControllerData.toStrongRef());
+}
+
+AnchorLine::Type AnchorLineHandleItem::anchorLine() const
+{
+ if (isTopHandle())
+ return AnchorLine::Top;
+
+ if (isLeftHandle())
+ return AnchorLine::Left;
+
+ if (isRightHandle())
+ return AnchorLine::Right;
+
+ if (isBottomHandle())
+ return AnchorLine::Bottom;
+
+ return AnchorLine::Invalid;
+}
+
+AnchorLineHandleItem* AnchorLineHandleItem::fromGraphicsItem(QGraphicsItem *item)
+{
+ return qgraphicsitem_cast<AnchorLineHandleItem*>(item);
+}
+
+bool AnchorLineHandleItem::isTopHandle() const
+{
+ return anchorLineController().isTopHandle(this);
+}
+
+bool AnchorLineHandleItem::isLeftHandle() const
+{
+ return anchorLineController().isLeftHandle(this);
+}
+
+bool AnchorLineHandleItem::isRightHandle() const
+{
+ return anchorLineController().isRightHandle(this);
+}
+
+bool AnchorLineHandleItem::isBottomHandle() const
+{
+ return anchorLineController().isBottomHandle(this);
+}
+
+AnchorLine::Type AnchorLineHandleItem::anchorLineType() const
+{
+ if (isTopHandle())
+ return AnchorLine::Top;
+
+ if (isBottomHandle())
+ return AnchorLine::Bottom;
+
+ if (isLeftHandle())
+ return AnchorLine::Left;
+
+ if (isRightHandle())
+ return AnchorLine::Right;
+
+
+ return AnchorLine::Invalid;
+}
+
+QPointF AnchorLineHandleItem::itemSpacePosition() const
+{
+ return parentItem()->mapToItem(anchorLineController().formEditorItem(), pos());
+}
+
+void AnchorLineHandleItem::setHiglighted(bool highlight)
+{
+ if (highlight) {
+ QPen pen;
+ pen.setColor(QColor(108, 141, 221));
+ setPen(pen);
+ setBrush(QColor(108, 141, 221, 140));
+ } else {
+ QPen pen;
+ pen.setColor(QColor(108, 141, 221));
+ setPen(pen);
+ setBrush(QColor(108, 141, 221, 60));
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h
new file mode 100644
index 0000000000..b35ec346ac
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorlinehandleitem.h
@@ -0,0 +1,86 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORLINEHANDLEITEM_H
+#define ANCHORLINEHANDLEITEM_H
+
+#include <QGraphicsPathItem>
+
+#include "anchorlinecontroller.h"
+
+namespace QmlDesigner {
+
+class AnchorLineHandleItem : public QGraphicsPathItem
+{
+public:
+ enum
+ {
+ Type = 0xEAEB
+ };
+
+
+ AnchorLineHandleItem(QGraphicsItem *parent, const AnchorLineController &AnchorLineController);
+
+ void setHandlePath(const QPainterPath & path);
+
+ int type() const;
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+
+ AnchorLineController anchorLineController() const;
+ AnchorLine::Type anchorLine() const;
+
+
+ static AnchorLineHandleItem* fromGraphicsItem(QGraphicsItem *item);
+
+
+ bool isTopHandle() const;
+ bool isLeftHandle() const;
+ bool isRightHandle() const;
+ bool isBottomHandle() const;
+
+ QPointF itemSpacePosition() const;
+
+ AnchorLine::Type anchorLineType() const;
+
+ void setHiglighted(bool highlight);
+
+
+private:
+ QWeakPointer<AnchorLineControllerData> m_anchorLineControllerData;
+};
+
+inline int AnchorLineHandleItem::type() const
+{
+ return Type;
+}
+
+} // namespace QmlDesigner
+
+#endif // ANCHORLINEHANDLEITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp
new file mode 100644
index 0000000000..a521faf216
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.cpp
@@ -0,0 +1,131 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchorlineindicator.h"
+
+#include <QSet>
+
+namespace QmlDesigner {
+
+AnchorLineIndicator::AnchorLineIndicator(LayerItem *layerItem)
+ : m_layerItem(layerItem)
+{
+ Q_ASSERT(layerItem);
+}
+
+AnchorLineIndicator::~AnchorLineIndicator()
+{
+ m_itemControllerHash.clear();
+}
+
+void AnchorLineIndicator::show(AnchorLine::Type anchorLineMask)
+{
+ QHashIterator<FormEditorItem*, AnchorLineController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ AnchorLineController controller = itemControllerIterator.next().value();
+ controller.show(anchorLineMask);
+ }
+}
+
+void AnchorLineIndicator::hide()
+{
+ QHashIterator<FormEditorItem*, AnchorLineController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ AnchorLineController controller = itemControllerIterator.next().value();
+ controller.hide();
+ }
+}
+
+void AnchorLineIndicator::clear()
+{
+ m_itemControllerHash.clear();
+}
+
+void AnchorLineIndicator::setItem(FormEditorItem* item)
+{
+ if (!item)
+ return;
+
+ QList<FormEditorItem*> itemList;
+ itemList.append(item);
+
+ setItems(itemList);
+}
+
+static bool equalLists(const QList<FormEditorItem*> &firstList, const QList<FormEditorItem*> &secondList)
+{
+ return firstList.toSet() == secondList.toSet();
+}
+
+void AnchorLineIndicator::setItems(const QList<FormEditorItem*> &itemList)
+{
+ if (equalLists(itemList, m_itemControllerHash.keys()))
+ return;
+
+ clear();
+
+ foreach (FormEditorItem *item, itemList) {
+ AnchorLineController controller(m_layerItem, item);
+ m_itemControllerHash.insert(item, controller);
+ }
+
+ show(AnchorLine::AllMask);
+}
+
+void AnchorLineIndicator::updateItems(const QList<FormEditorItem*> &itemList)
+{
+ foreach (FormEditorItem *item, itemList) {
+ if (m_itemControllerHash.contains(item)) {
+ AnchorLineController controller(m_itemControllerHash.value(item));
+ controller.updatePosition();
+ }
+ }
+}
+
+void AnchorLineIndicator::update()
+{
+ foreach (FormEditorItem *item, m_itemControllerHash.keys()) {
+ if (m_itemControllerHash.contains(item)) {
+ AnchorLineController controller(m_itemControllerHash.value(item));
+ controller.updatePosition();
+ }
+ }
+}
+
+void AnchorLineIndicator::clearHighlight()
+{
+ foreach (FormEditorItem *item, m_itemControllerHash.keys()) {
+ if (m_itemControllerHash.contains(item)) {
+ AnchorLineController controller(m_itemControllerHash.value(item));
+ controller.clearHighlight();
+ }
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h
new file mode 100644
index 0000000000..2a4c9966fc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchorlineindicator.h
@@ -0,0 +1,69 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORLINEINDICATOR_H
+#define ANCHORLINEINDICATOR_H
+
+#include "layeritem.h"
+#include "anchorlinecontroller.h"
+#include <QHash>
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+
+class AnchorLineIndicator
+{
+public:
+ AnchorLineIndicator(LayerItem *layerItem);
+ ~AnchorLineIndicator();
+
+ void show(AnchorLine::Type anchorLineMask);
+
+ void hide();
+
+ void clear();
+
+ void update();
+
+ void setItems(const QList<FormEditorItem*> &itemList);
+ void setItem(FormEditorItem* item);
+ void updateItems(const QList<FormEditorItem*> &itemList);
+
+ void clearHighlight();
+
+private:
+ QHash<FormEditorItem*, AnchorLineController> m_itemControllerHash;
+
+ LayerItem *m_layerItem;
+};
+
+} // namespace QmlDesigner
+
+#endif // ANCHORLINEINDICATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp
new file mode 100644
index 0000000000..1468ae1e5f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.cpp
@@ -0,0 +1,144 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchormanipulator.h"
+
+#include "formeditoritem.h"
+#include "formeditorscene.h"
+#include "formeditorview.h"
+#include <model.h>
+#include <rewritertransaction.h>
+
+namespace QmlDesigner {
+
+AnchorManipulator::AnchorManipulator(FormEditorView *view)
+ : m_beginFormEditorItem(0),
+ m_beginAnchorLine(AnchorLine::Invalid),
+ m_view(view)
+{
+}
+
+AnchorManipulator::~AnchorManipulator()
+{
+ clear();
+}
+
+void AnchorManipulator::begin(FormEditorItem *beginItem, AnchorLine::Type anchorLine)
+{
+ m_beginFormEditorItem = beginItem;
+ m_beginAnchorLine = anchorLine;
+}
+
+static double offset(const QPointF &topLeft, const QPointF &bottomRight, AnchorLine::Type anchorLine)
+{
+ switch(anchorLine) {
+ case AnchorLine::Top : return topLeft.y();
+ case AnchorLine::Left : return topLeft.x();
+ case AnchorLine::Bottom : return bottomRight.y();
+ case AnchorLine::Right : return bottomRight.x();
+ default: break;
+ }
+
+ return 0.0;
+}
+
+void AnchorManipulator::setMargin(FormEditorItem *endItem, AnchorLine::Type endAnchorLine)
+{
+ QPointF beginItemTopLeft(m_beginFormEditorItem->mapToParent(m_beginFormEditorItem->qmlItemNode().instanceBoundingRect().topLeft()));
+ QPointF endItemTopLeft(m_beginFormEditorItem->parentItem()->mapFromItem(endItem, endItem->qmlItemNode().instanceBoundingRect().topLeft()));
+
+ QPointF beginItemBottomRight(m_beginFormEditorItem->mapToParent(m_beginFormEditorItem->qmlItemNode().instanceBoundingRect().bottomRight()));
+ QPointF endItemBottomRight(m_beginFormEditorItem->parentItem()->mapFromItem(endItem, endItem->qmlItemNode().instanceBoundingRect().bottomRight()));
+
+ QPointF topLeftAnchorOffset = beginItemTopLeft - endItemTopLeft;
+ QPointF bottomRightAnchorOffset = endItemBottomRight - beginItemBottomRight;
+
+
+ double anchorOffset = 0.0;
+ if (m_beginAnchorLine & (AnchorLine::Bottom | AnchorLine::Right)) {
+ anchorOffset = offset(endItemTopLeft, endItemBottomRight, endAnchorLine) -
+ offset(beginItemTopLeft, beginItemBottomRight, m_beginAnchorLine);
+ } else {
+ anchorOffset = offset(beginItemTopLeft, beginItemBottomRight, m_beginAnchorLine) -
+ offset(endItemTopLeft, endItemBottomRight, endAnchorLine);
+ }
+
+ m_beginFormEditorItem->qmlItemNode().anchors().setMargin(m_beginAnchorLine, anchorOffset);
+}
+void AnchorManipulator::addAnchor(FormEditorItem *endItem, AnchorLine::Type endAnchorLine)
+{
+ RewriterTransaction m_rewriterTransaction = m_view->beginRewriterTransaction();
+ setMargin(endItem, endAnchorLine);
+
+ m_beginFormEditorItem->qmlItemNode().anchors().setAnchor(m_beginAnchorLine,
+ endItem->qmlItemNode(),
+ endAnchorLine);
+}
+
+void AnchorManipulator::removeAnchor()
+{
+ RewriterTransaction transaction = m_view->beginRewriterTransaction();
+ QmlAnchors anchors(m_beginFormEditorItem->qmlItemNode().anchors());
+ if (anchors.instanceHasAnchor(m_beginAnchorLine)) {
+ anchors.removeAnchor(m_beginAnchorLine);
+ anchors.removeMargin(m_beginAnchorLine);
+ }
+}
+
+void AnchorManipulator::clear()
+{
+ m_beginFormEditorItem = 0;
+ m_beginAnchorLine = AnchorLine::Invalid;
+}
+
+bool AnchorManipulator::isActive() const
+{
+ return m_beginFormEditorItem && m_beginAnchorLine != AnchorLine::Invalid;
+}
+
+AnchorLine::Type AnchorManipulator::beginAnchorLine() const
+{
+ return m_beginAnchorLine;
+}
+
+bool AnchorManipulator::beginAnchorLineIsHorizontal() const
+{
+ return beginAnchorLine() & AnchorLine::HorizontalMask;
+}
+bool AnchorManipulator::beginAnchorLineIsVertical() const
+{
+ return beginAnchorLine() & AnchorLine::HorizontalMask;
+}
+
+FormEditorItem *AnchorManipulator::beginFormEditorItem() const
+{
+ return m_beginFormEditorItem;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/anchormanipulator.h b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.h
new file mode 100644
index 0000000000..b44238a4e1
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchormanipulator.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORMANIPULATOR_H
+#define ANCHORMANIPULATOR_H
+
+#include <qmlanchors.h>
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+class FormEditorView;
+
+class AnchorManipulator
+{
+public:
+ AnchorManipulator(FormEditorView *view);
+ ~AnchorManipulator();
+ void begin(FormEditorItem *beginItem, AnchorLine::Type anchorLine);
+ void addAnchor(FormEditorItem *endItem, AnchorLine::Type anchorLine);
+ void removeAnchor();
+
+ void clear();
+
+ bool isActive() const;
+
+ bool beginAnchorLineIsHorizontal() const;
+ bool beginAnchorLineIsVertical() const;
+
+ AnchorLine::Type beginAnchorLine() const;
+
+ FormEditorItem *beginFormEditorItem() const;
+
+private: // fucntions
+ void setMargin(FormEditorItem *endItem, AnchorLine::Type endAnchorLine);
+
+private: // variables
+ FormEditorItem *m_beginFormEditorItem;
+ AnchorLine::Type m_beginAnchorLine;
+ QWeakPointer<FormEditorView> m_view;
+};
+
+} // namespace QmlDesigner
+
+#endif // ANCHORMANIPULATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/anchortool.cpp b/src/plugins/qmldesigner/components/formeditor/anchortool.cpp
new file mode 100644
index 0000000000..524352819d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchortool.cpp
@@ -0,0 +1,226 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "anchortool.h"
+
+#include "formeditorscene.h"
+#include "formeditorview.h"
+#include <qmlitemnode.h>
+#include <qmlanchors.h>
+#include "anchorlinehandleitem.h"
+
+#include <QGraphicsSceneMouseEvent>
+
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+AnchorTool::AnchorTool(FormEditorView* editorView)
+ : AbstractFormEditorTool(editorView),
+ m_anchorLineIndicator(editorView->scene()->manipulatorLayerItem()),
+ m_anchorIndicator(editorView->scene()->manipulatorLayerItem()),
+ m_anchorManipulator(editorView),
+ m_lastAnchorLineHandleItem(0)
+{
+ m_hoverTimeLine.setDuration(200);
+ connect(&m_hoverTimeLine, SIGNAL(finished()), SLOT(checkIfStillHovering()));
+}
+
+AnchorTool::~AnchorTool()
+{
+
+}
+
+void AnchorTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *)
+{
+ AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList);
+ if (anchorLineHandleItem) {
+ m_anchorManipulator.begin(anchorLineHandleItem->anchorLineController().formEditorItem(),
+ anchorLineHandleItem->anchorLineType());
+ }
+
+ m_anchorLineIndicator.clear();
+
+}
+
+bool areAchorable(FormEditorItem *firstItem, FormEditorItem *secondItem)
+{
+ return firstItem->qmlItemNode().anchors().canAnchor(secondItem->qmlItemNode());
+}
+
+void AnchorTool::mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_anchorManipulator.isActive()) {
+ FormEditorItem *targetItem = 0;
+ AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList);
+ if (anchorLineHandleItem && areAchorable(m_anchorManipulator.beginFormEditorItem(), anchorLineHandleItem->anchorLineController().formEditorItem())) {
+ targetItem = anchorLineHandleItem->anchorLineController().formEditorItem();
+ } else {
+ FormEditorItem *topFormEditItem = topFormEditorItemWithRootItem(itemList);
+ if (topFormEditItem && areAchorable(m_anchorManipulator.beginFormEditorItem(), topFormEditItem)) {
+ targetItem = topFormEditItem;
+ } else {
+ m_anchorLineIndicator.hide();
+ m_anchorIndicator.updateTargetPoint(m_anchorManipulator.beginFormEditorItem(), m_anchorManipulator.beginAnchorLine(), event->scenePos());
+ }
+ }
+
+ if (targetItem) {
+ targetItem->qmlItemNode().selectNode();
+ m_anchorLineIndicator.setItem(targetItem);
+ m_anchorLineIndicator.show(m_anchorManipulator.beginFormEditorItem()->qmlItemNode().anchors().possibleAnchorLines(m_anchorManipulator.beginAnchorLine(), targetItem->qmlItemNode()));
+ m_anchorIndicator.updateTargetPoint(m_anchorManipulator.beginFormEditorItem(), m_anchorManipulator.beginAnchorLine(), event->scenePos());
+ targetItem->qmlItemNode().selectNode();
+ }
+ }
+
+}
+
+void AnchorTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *)
+{
+ if (m_anchorManipulator.isActive()) {
+ AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList);
+ if (anchorLineHandleItem) {
+ m_anchorManipulator.addAnchor(anchorLineHandleItem->anchorLineController().formEditorItem(),
+ anchorLineHandleItem->anchorLineType());
+ } else {
+ m_anchorManipulator.removeAnchor();
+ }
+
+
+ }
+
+ FormEditorItem *topFormEditItem = topFormEditorItem(itemList);
+ if (topFormEditItem)
+ topFormEditItem->qmlItemNode().selectNode();
+
+ m_anchorManipulator.clear();
+ m_anchorLineIndicator.clear();
+}
+
+void AnchorTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+}
+
+void AnchorTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ m_anchorLineIndicator.clearHighlight();
+ m_anchorIndicator.clearHighlight();
+ m_lastMousePosition = event->scenePos();
+ FormEditorItem *topFormEditItem = 0;
+ AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(itemList);
+
+ if (anchorLineHandleItem) {
+ anchorLineHandleItem->setHiglighted(true);
+ m_anchorIndicator.highlight(anchorLineHandleItem->anchorLineController().formEditorItem(),
+ anchorLineHandleItem->anchorLineType());
+ topFormEditItem = anchorLineHandleItem->anchorLineController().formEditorItem();
+ if (m_hoverTimeLine.state() == QTimeLine::NotRunning) {
+ m_lastAnchorLineHandleItem = anchorLineHandleItem;
+ m_hoverTimeLine.start();
+ }
+ } else {
+ topFormEditItem = topFormEditorItem(itemList);
+ }
+
+ if (topFormEditItem) {
+ m_anchorLineIndicator.setItem(topFormEditItem);
+ m_anchorLineIndicator.show(AnchorLine::AllMask);
+ topFormEditItem->qmlItemNode().selectNode();
+ } else {
+
+ m_anchorLineIndicator.clear();
+ }
+}
+
+void AnchorTool::checkIfStillHovering()
+{
+ AnchorLineHandleItem *anchorLineHandleItem = topAnchorLineHandleItem(scene()->items(m_lastMousePosition));
+
+ if (anchorLineHandleItem && anchorLineHandleItem == m_lastAnchorLineHandleItem) {
+ FormEditorItem *sourceFormEditItem = anchorLineHandleItem->anchorLineController().formEditorItem();
+ QmlAnchors anchors(sourceFormEditItem->qmlItemNode().anchors());
+ if (anchors.instanceHasAnchor(anchorLineHandleItem->anchorLine())) {
+ QmlItemNode targetNode(anchors.instanceAnchor(anchorLineHandleItem->anchorLine()).qmlItemNode());
+ FormEditorItem *targetFormEditorItem = scene()->itemForQmlItemNode(targetNode);
+ targetFormEditorItem->showAttention();
+ }
+ }
+}
+
+void AnchorTool::keyPressEvent(QKeyEvent *)
+{
+}
+
+void AnchorTool::keyReleaseEvent(QKeyEvent *)
+{
+}
+
+void AnchorTool::itemsAboutToRemoved(const QList<FormEditorItem*> &removedItems)
+{
+ QList<FormEditorItem*> newItemList = items().toSet().subtract(removedItems.toSet()).toList();
+ setItems(newItemList);
+ m_anchorIndicator.setItems(newItemList);
+ m_anchorLineIndicator.clear();
+}
+
+void AnchorTool::selectedItemsChanged(const QList<FormEditorItem*> &/*itemList*/)
+{
+ m_anchorIndicator.setItems(view()->scene()->allFormEditorItems());
+ m_anchorIndicator.show();
+}
+
+void AnchorTool::clear()
+{
+ m_anchorLineIndicator.clear();
+ m_anchorIndicator.clear();
+}
+
+void AnchorTool::formEditorItemsChanged(const QList<FormEditorItem*> &)
+{
+ m_anchorLineIndicator.updateItems(view()->scene()->allFormEditorItems());
+ m_anchorIndicator.updateItems(view()->scene()->allFormEditorItems());
+}
+
+AnchorLineHandleItem* AnchorTool::topAnchorLineHandleItem(const QList<QGraphicsItem*> & itemList)
+{
+ foreach (QGraphicsItem *item, itemList) {
+ AnchorLineHandleItem *anchorLineItem = AnchorLineHandleItem::fromGraphicsItem(item);
+ if (anchorLineItem)
+ return anchorLineItem;
+ }
+
+ return 0;
+}
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/anchortool.h b/src/plugins/qmldesigner/components/formeditor/anchortool.h
new file mode 100644
index 0000000000..d11dd1818e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/anchortool.h
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ANCHORTOOL_H
+#define ANCHORTOOL_H
+
+#include <QTimeLine>
+
+#include "abstractformeditortool.h"
+
+#include "anchorlineindicator.h"
+#include "anchorindicator.h"
+#include "anchormanipulator.h"
+
+namespace QmlDesigner {
+
+class AnchorLineHandleItem;
+
+class AnchorTool : public QObject, public AbstractFormEditorTool
+{
+ Q_OBJECT
+public:
+ AnchorTool(FormEditorView* editorView);
+ ~AnchorTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList);
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void clear();
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ static AnchorLineHandleItem* topAnchorLineHandleItem(const QList<QGraphicsItem*> & itemList);
+
+private slots:
+ void checkIfStillHovering();
+
+private: //variables
+ AnchorLineIndicator m_anchorLineIndicator;
+ AnchorIndicator m_anchorIndicator;
+ AnchorManipulator m_anchorManipulator;
+ QTimeLine m_hoverTimeLine;
+ QPointF m_lastMousePosition;
+ AnchorLineHandleItem *m_lastAnchorLineHandleItem;
+};
+
+}
+#endif // ANCHORTOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/controlelement.cpp b/src/plugins/qmldesigner/components/formeditor/controlelement.cpp
new file mode 100644
index 0000000000..5894fe5c45
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/controlelement.cpp
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "controlelement.h"
+
+#include <QGraphicsScene>
+#include <QGraphicsRectItem>
+#include <QBrush>
+#include "layeritem.h"
+#include <QtDebug>
+
+
+namespace QmlDesigner {
+
+ControlElement::ControlElement(LayerItem *layerItem)
+ : m_controlShape(new QGraphicsRectItem(layerItem))
+{
+ QPen pen;
+ pen.setStyle(Qt::DashLine);
+ pen.setColor(Qt::blue);
+ m_controlShape->setPen(pen);
+}
+
+ControlElement::~ControlElement()
+{
+ delete m_controlShape;
+}
+
+void ControlElement::hide()
+{
+ m_controlShape->hide();
+}
+
+void ControlElement::setBoundingRect(const QRectF &rect)
+{
+ m_controlShape->show();
+ m_controlShape->setRect(m_controlShape->mapFromScene(rect).boundingRect());
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/controlelement.h b/src/plugins/qmldesigner/components/formeditor/controlelement.h
new file mode 100644
index 0000000000..1ec1f3a864
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/controlelement.h
@@ -0,0 +1,57 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef CONTROLELEMENT_H
+#define CONTROLELEMENT_H
+
+
+#include <QGraphicsRectItem>
+
+
+namespace QmlDesigner {
+
+class LayerItem;
+
+class ControlElement
+{
+public:
+ ControlElement(LayerItem *layerItem);
+ ~ControlElement();
+
+ void hide();
+
+ void setBoundingRect(const QRectF &rect);
+
+private:
+ QGraphicsRectItem *m_controlShape;
+};
+
+}
+
+#endif // CONTROLELEMENT_H
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
new file mode 100644
index 0000000000..7878cf86a3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
@@ -0,0 +1,315 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "dragtool.h"
+
+#include "formeditorscene.h"
+#include "formeditorview.h"
+#include "modelutilities.h"
+#include "itemutilfunctions.h"
+#include <customdraganddrop.h>
+#include <metainfo.h>
+
+#include "resizehandleitem.h"
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+DragTool::DragTool(FormEditorView *editorView)
+ : AbstractFormEditorTool(editorView),
+ m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
+ m_selectionIndicator(editorView->scene()->manipulatorLayerItem())
+{
+// view()->setCursor(Qt::SizeAllCursor);
+}
+
+
+DragTool::~DragTool()
+{
+
+}
+
+void DragTool::clear()
+{
+ m_moveManipulator.clear();
+ m_selectionIndicator.clear();
+ m_movingItem.clear();
+}
+
+void DragTool::mousePressEvent(const QList<QGraphicsItem*> &,
+ QGraphicsSceneMouseEvent *)
+{
+
+}
+
+void DragTool::mouseMoveEvent(const QList<QGraphicsItem*> &,
+ QGraphicsSceneMouseEvent *)
+{
+
+}
+
+void DragTool::hoverMoveEvent(const QList<QGraphicsItem*> &,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+
+}
+
+void DragTool::keyPressEvent(QKeyEvent *)
+{
+
+}
+
+void DragTool::keyReleaseEvent(QKeyEvent *)
+{
+
+}
+
+
+void DragTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *)
+{
+
+}
+
+void DragTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+
+}
+
+void DragTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /* removedItemList */)
+{
+
+}
+
+void DragTool::selectedItemsChanged(const QList<FormEditorItem*> &)
+{
+
+}
+
+
+
+void DragTool::updateMoveManipulator()
+{
+ if (m_moveManipulator.isActive())
+ return;
+}
+
+void DragTool::beginWithPoint(const QPointF &beginPoint)
+{
+ m_movingItem = scene()->itemForQmlItemNode(m_dragNode);
+
+ m_moveManipulator.setItem(m_movingItem.data());
+ m_moveManipulator.begin(beginPoint);
+
+}
+
+void DragTool::createQmlItemNode(const ItemLibraryInfo &itemLibraryRepresentation, QmlItemNode parentNode, QPointF scenePos)
+{
+ QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide();
+
+ MetaInfo metaInfo = MetaInfo::global();
+
+ FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
+ QPointF pos = parentItem->mapFromScene(scenePos);
+
+ m_dragNode = view()->createQmlItemNode(itemLibraryRepresentation, pos, parentNode);
+
+ Q_ASSERT(m_dragNode.modelNode().isValid());
+ Q_ASSERT(m_dragNode.isValid());
+
+ QList<QmlItemNode> nodeList;
+ nodeList.append(m_dragNode);
+ view()->setSelectedQmlItemNodes(nodeList);
+ m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
+}
+
+void DragTool::createQmlItemNodeFromImage(const QString &imageName, QmlItemNode parentNode, QPointF scenePos)
+{
+ QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::hide();
+
+ MetaInfo metaInfo = MetaInfo::global();
+
+ FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
+ QPointF pos = parentItem->mapFromScene(scenePos);
+
+ m_dragNode = view()->createQmlItemNodeFromImage(imageName, pos, parentNode);
+
+ QList<QmlItemNode> nodeList;
+ nodeList.append(m_dragNode);
+ view()->setSelectedQmlItemNodes(nodeList);
+ m_selectionIndicator.setItems(scene()->itemsForQmlItemNodes(nodeList));
+}
+
+FormEditorItem* DragTool::calculateContainer(const QPointF &point, FormEditorItem * currentItem)
+{
+ QList<QGraphicsItem *> list = scene()->items(point);
+ foreach (QGraphicsItem *item, list) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem && formEditorItem != currentItem && formEditorItem->isContainer())
+ return formEditorItem;
+ }
+ return 0;
+}
+
+
+void DragTool::formEditorItemsChanged(const QList<FormEditorItem*> & itemList)
+{
+ if (m_movingItem && itemList.contains(m_movingItem.data())) {
+ QList<FormEditorItem*> updateItemList;
+ updateItemList.append(m_movingItem.data());
+ m_selectionIndicator.updateItems(updateItemList);
+ }
+}
+
+
+void DragTool::dropEvent(QGraphicsSceneDragDropEvent * event)
+{
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
+ event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ event->accept();
+ end(event->scenePos());
+ //Q_ASSERT(m_token.isValid());
+ m_rewriterTransaction.commit();
+ m_dragNode = ModelNode();
+ view()->changeToSelectionTool();
+ }
+}
+
+void DragTool::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
+{
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
+ event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ if (!m_rewriterTransaction.isValid()) {
+ m_rewriterTransaction = view()->beginRewriterTransaction();
+ }
+ }
+}
+
+void DragTool::dragLeaveEvent(QGraphicsSceneDragDropEvent * event)
+{
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
+ event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ event->accept();
+ if (m_dragNode.isValid())
+ m_dragNode.destroy();
+ end(event->scenePos());
+ m_rewriterTransaction.commit();
+ QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show();
+ QList<QmlItemNode> nodeList;
+ view()->setSelectedQmlItemNodes(nodeList);
+ view()->changeToSelectionTool();
+ }
+}
+
+static ItemLibraryInfo ItemLibraryInfoFromData(const QByteArray &data)
+{
+ QDataStream stream(data);
+
+ ItemLibraryInfo itemLibraryInfo;
+ stream >> itemLibraryInfo;
+
+ return itemLibraryInfo;
+}
+
+void DragTool::dragMoveEvent(QGraphicsSceneDragDropEvent * event)
+{
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo") ||
+ event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ event->accept();
+ QPointF scenePos = event->scenePos();
+ if (m_dragNode.isValid()) {
+
+ FormEditorItem *parentItem = calculateContainer(event->scenePos() - QPoint(2, 2));
+ if (!parentItem) { //if there is no parent any more - the use left the scene
+ end(event->scenePos());
+ m_dragNode.destroy(); //delete the node then
+ QmlDesignerItemLibraryDragAndDrop::CustomDragAndDrop::show();
+ return;
+ }
+ //move
+ move(event->scenePos());
+ } else {
+ //create new node if container
+
+ FormEditorItem *parentItem = calculateContainer(event->scenePos());
+ if (!parentItem)
+ return;
+ QmlItemNode parentNode; //get possible container parentNode
+ if (parentItem)
+ parentNode = parentItem->qmlItemNode();
+
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.itemlibraryinfo")) {
+ Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo").isEmpty());
+ ItemLibraryInfo ItemLibraryInfo = ItemLibraryInfoFromData(event->mimeData()->data("application/vnd.bauhaus.itemlibraryinfo"));
+ createQmlItemNode(ItemLibraryInfo, parentNode, event->scenePos());
+ } else if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ Q_ASSERT(!event->mimeData()->data("application/vnd.bauhaus.libraryresource").isEmpty());
+ QString imageName = QString::fromLatin1((event->mimeData()->data("application/vnd.bauhaus.libraryresource")));
+ createQmlItemNodeFromImage(imageName, parentNode, event->scenePos());
+ } else Q_ASSERT(false);
+ beginWithPoint(event->scenePos());
+ }
+ }
+ if (event->mimeData()->hasFormat("application/vnd.bauhaus.libraryresource")) {
+ }
+}
+
+void DragTool::end(QPointF scenePos)
+{
+ m_moveManipulator.end(scenePos);
+ clear();
+}
+
+void DragTool::move(QPointF scenePos)
+{
+ if (!m_movingItem)
+ return;
+
+ FormEditorItem *containerItem = calculateContainer(scenePos - QPoint(2, 2), m_movingItem.data());
+ if (containerItem &&
+ containerItem != m_movingItem->parentItem() &&
+ view()->currentState().isBaseState()) {
+
+ m_moveManipulator.reparentTo(containerItem);
+ }
+
+ //MoveManipulator::Snapping useSnapping = MoveManipulator::NoSnapping;
+ MoveManipulator::Snapping useSnapping = MoveManipulator::UseSnapping;
+ /* if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked())
+ useSnapping = MoveManipulator::UseSnapping;*/
+
+ m_moveManipulator.update(scenePos, useSnapping);
+}
+
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.h b/src/plugins/qmldesigner/components/formeditor/dragtool.h
new file mode 100644
index 0000000000..97f676482b
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.h
@@ -0,0 +1,105 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef DRAGTOOL_H
+#define DRAGTOOL_H
+
+#include "abstractformeditortool.h"
+#include "movemanipulator.h"
+#include "selectionindicator.h"
+#include "resizeindicator.h"
+
+#include <QHash>
+
+
+namespace QmlDesigner {
+
+
+class DragTool : public AbstractFormEditorTool
+{
+public:
+ DragTool(FormEditorView* editorView);
+ ~DragTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList);
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void updateMoveManipulator();
+
+ void beginWithPoint(const QPointF &beginPoint);
+
+
+ virtual void dropEvent(QGraphicsSceneDragDropEvent * event);
+ virtual void dragEnterEvent(QGraphicsSceneDragDropEvent * event);
+ virtual void dragLeaveEvent(QGraphicsSceneDragDropEvent * event);
+ virtual void dragMoveEvent(QGraphicsSceneDragDropEvent * event);
+
+ //void beginWithPoint(const QPointF &beginPoint);
+
+ void clear();
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList);
+
+protected:
+
+
+private:
+
+ void createQmlItemNode(const ItemLibraryInfo &ItemLibraryRepresentation, QmlItemNode parentNode, QPointF scenePos);
+ void createQmlItemNodeFromImage(const QString &imageName, QmlItemNode parentNode, QPointF scenePos);
+ FormEditorItem* calculateContainer(const QPointF &point, FormEditorItem * currentItem = 0);
+
+ void begin(QPointF scenePos);
+ void end(QPointF scenePos);
+ void move(QPointF scenePos);
+
+ MoveManipulator m_moveManipulator;
+ SelectionIndicator m_selectionIndicator;
+ QWeakPointer<FormEditorItem> m_movingItem;
+ RewriterTransaction m_rewriterTransaction;
+ QmlItemNode m_dragNode;
+};
+
+}
+#endif // DRAGTOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.pri b/src/plugins/qmldesigner/components/formeditor/formeditor.pri
new file mode 100644
index 0000000000..1c3bd78988
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditor.pri
@@ -0,0 +1,84 @@
+VPATH += $$PWD
+QT += opengl
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD/../navigator
+DEPENDPATH += $$PWD
+SOURCES += formeditoritem.cpp \
+ formeditorview.cpp \
+ formeditorscene.cpp \
+ formeditorwidget.cpp \
+ selectiontool.cpp \
+ abstractformeditortool.cpp \
+ controlelement.cpp \
+ resizemanipulator.cpp \
+ movemanipulator.cpp \
+ layeritem.cpp \
+ itemutilfunctions.cpp \
+ selectionrectangle.cpp \
+ rubberbandselectionmanipulator.cpp \
+ movetool.cpp \
+ selectionindicator.cpp \
+ snappinglinecreator.cpp \
+ snapper.cpp \
+ onedimensionalcluster.cpp \
+ singleselectionmanipulator.cpp \
+ scalemanipulator.cpp \
+ resizetool.cpp \
+ resizeindicator.cpp \
+ scaleitem.cpp \
+ resizecontroller.cpp \
+ resizehandleitem.cpp \
+ anchortool.cpp \
+ anchorlineindicator.cpp \
+ anchorlinecontroller.cpp \
+ anchorlinehandleitem.cpp \
+ anchormanipulator.cpp \
+ anchorindicator.cpp \
+ anchorcontroller.cpp \
+ anchorhandleitem.cpp \
+ dragtool.cpp \
+ itemcreatortool.cpp \
+ toolbox.cpp \
+ zoomaction.cpp \
+ formeditorgraphicsview.cpp \
+ numberseriesaction.cpp
+HEADERS += formeditorscene.h \
+ formeditorwidget.h \
+ formeditoritem.h \
+ formeditorview.h \
+ selectiontool.h \
+ abstractformeditortool.h \
+ controlelement.h \
+ resizemanipulator.h \
+ movemanipulator.h \
+ layeritem.h \
+ itemutilfunctions.h \
+ selectionrectangle.h \
+ rubberbandselectionmanipulator.h \
+ movetool.h \
+ selectionindicator.h \
+ snappinglinecreator.h \
+ snapper.h \
+ onedimensionalcluster.h \
+ singleselectionmanipulator.h \
+ scalemanipulator.h \
+ resizetool.h \
+ resizeindicator.h \
+ scaleitem.h \
+ resizecontroller.h \
+ resizehandleitem.h \
+ anchortool.h \
+ anchorlineindicator.h \
+ anchorlinecontroller.h \
+ anchorlinehandleitem.h \
+ anchormanipulator.h \
+ anchorindicator.h \
+ anchorcontroller.h \
+ anchorhandleitem.h \
+ dragtool.h \
+ itemcreatortool.cpp \
+ toolbox.h \
+ zoomaction.h \
+ formeditorgraphicsview.h \
+ numberseriesaction.h
+RESOURCES += formeditor.qrc
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditor.qrc b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc
new file mode 100644
index 0000000000..14e0dbd0fb
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditor.qrc
@@ -0,0 +1,12 @@
+<RCC>
+ <qresource prefix="/icon/handle">
+ <file>resize_handle.png</file>
+ </qresource>
+ <qresource prefix="/icon/tool">
+ <file>anchor.png</file>
+ <file>transform.png</file>
+ </qresource>
+ <qresource prefix="/icon/layout">
+ <file>snapping.png</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
new file mode 100644
index 0000000000..fb2e905eda
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.cpp
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditorgraphicsview.h"
+
+#include <QWheelEvent>
+
+namespace QmlDesigner {
+
+FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent) :
+ QGraphicsView(parent)
+{
+ setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
+ setResizeAnchor(QGraphicsView::AnchorViewCenter);
+// setCacheMode(QGraphicsView::CacheNone);
+ setCacheMode(QGraphicsView::CacheBackground);
+ setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
+// setViewportUpdateMode(QGraphicsView::NoViewportUpdate);
+ setRenderHint(QPainter::Antialiasing, false);
+
+ setFrameShape(QFrame::NoFrame);
+
+ setAutoFillBackground(true);
+ setBackgroundRole(QPalette::Window);
+
+ const int checkerbordSize= 20;
+ QPixmap tilePixmap(checkerbordSize * 2, checkerbordSize * 2);
+ tilePixmap.fill(Qt::white);
+ QPainter tilePainter(&tilePixmap);
+ QColor color(220, 220, 220);
+ tilePainter.fillRect(0, 0, checkerbordSize, checkerbordSize, color);
+ tilePainter.fillRect(checkerbordSize, checkerbordSize, checkerbordSize, checkerbordSize, color);
+ tilePainter.end();
+
+ setBackgroundBrush(tilePixmap);
+
+ viewport()->setMouseTracking(true);
+}
+
+void FormEditorGraphicsView::wheelEvent(QWheelEvent *event)
+{
+ if (event->modifiers().testFlag(Qt::ControlModifier)) {
+ event->ignore();
+ } else {
+ QGraphicsView::wheelEvent(event);
+ }
+
+}
+
+void FormEditorGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
+{
+ painter->save();
+ painter->setBrushOrigin(0, 0);
+ painter->fillRect(rect.intersected(sceneRect()), backgroundBrush());
+ // paint rect around editable area
+ painter->setPen(Qt::darkGray);
+ QRectF frameRect = sceneRect().adjusted(-1, -1, 0, 0);
+ painter->drawRect(frameRect);
+ painter->restore();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h
new file mode 100644
index 0000000000..2e79f656a4
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorgraphicsview.h
@@ -0,0 +1,51 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORGRAPHICSVIEW_H
+#define FORMEDITORGRAPHICSVIEW_H
+
+#include <QGraphicsView>
+
+namespace QmlDesigner {
+
+class FormEditorGraphicsView : public QGraphicsView
+{
+Q_OBJECT
+public:
+ explicit FormEditorGraphicsView(QWidget *parent = 0);
+
+
+protected:
+ void drawBackground(QPainter *painter, const QRectF &rect);
+ void wheelEvent(QWheelEvent *event);
+};
+
+} // namespace QmlDesigner
+
+#endif // FORMEDITORGRAPHICSVIEW_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
new file mode 100644
index 0000000000..91652fc37c
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.cpp
@@ -0,0 +1,323 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditoritem.h"
+#include "formeditorscene.h"
+#include "formeditornodeinstanceview.h"
+#include "selectiontool.h"
+
+#include <modelnode.h>
+#include <nodemetainfo.h>
+#include <widgetqueryview.h>
+
+#include <QGraphicsSceneMouseEvent>
+#include <QDebug>
+#include <QPainter>
+#include <QStyleOptionGraphicsItem>
+#include <QGraphicsView>
+#include <QTimeLine>
+
+#include <cmath>
+
+#include <invalidmodelnodeexception.h>
+#include <invalidnodestateexception.h>
+
+namespace QmlDesigner {
+
+
+
+FormEditorScene *FormEditorItem::scene() const {
+ return qobject_cast<FormEditorScene*>(QGraphicsItem::scene());
+}
+
+FormEditorItem::FormEditorItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene)
+ : QGraphicsObject(scene->formLayerItem()),
+ m_snappingLineCreator(this),
+ m_qmlItemNode(qmlItemNode),
+ m_borderWidth(1.0),
+ m_opacity(0.6)
+{
+ setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ setup();
+}
+
+void FormEditorItem::setup()
+{
+ if (qmlItemNode().hasInstanceParent())
+ setParentItem(scene()->itemForQmlItemNode(qmlItemNode().instanceParent().toQmlItemNode()));
+
+ if (QGraphicsItem::parentItem() == scene()->formLayerItem())
+ m_borderWidth = 0.0;
+
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ updateGeometry();
+ updateVisibilty();
+}
+
+QRectF FormEditorItem::boundingRect() const
+{
+ return m_boundingRect;
+}
+
+void FormEditorItem::updateGeometry()
+{
+ prepareGeometryChange();
+ m_boundingRect = qmlItemNode().instanceBoundingRect();
+ setTransform(qmlItemNode().instanceTransform());
+ setTransform(m_attentionTransform, true);
+ //the property for zValue is called z in QGraphicsObject
+ Q_ASSERT(qmlItemNode().instanceValue("z").isValid());
+ setZValue(qmlItemNode().instanceValue("z").toDouble());
+}
+
+void FormEditorItem::updateVisibilty()
+{
+// setVisible(nodeInstance().isVisible());
+// setOpacity(nodeInstance().opacity());
+}
+
+void FormEditorItem::showAttention()
+{
+ if (m_attentionTimeLine.isNull()) {
+ m_attentionTimeLine = new QTimeLine(500, this);
+ m_attentionTimeLine->setCurveShape(QTimeLine::SineCurve);
+ connect(m_attentionTimeLine.data(), SIGNAL(valueChanged(qreal)), SLOT(changeAttention(qreal)));
+ connect(m_attentionTimeLine.data(), SIGNAL(finished()), m_attentionTimeLine.data(), SLOT(deleteLater()));
+
+ m_attentionTimeLine->start();
+ }
+}
+
+void FormEditorItem::changeAttention(qreal value)
+{
+ if (QGraphicsItem::parentItem() == scene()->formLayerItem()) {
+ setAttentionHighlight(value);
+ } else {
+ setAttentionHighlight(value);
+ setAttentionScale(value);
+ }
+}
+
+FormEditorView *FormEditorItem::formEditorView() const
+{
+ return scene()->editorView();
+}
+
+void FormEditorItem::setAttentionScale(double sinusScale)
+{
+ if (!qFuzzyIsNull(sinusScale)) {
+ double scale = std::sqrt(sinusScale);
+ m_attentionTransform.reset();
+ QPointF centerPoint(qmlItemNode().instanceBoundingRect().center());
+ m_attentionTransform.translate(centerPoint.x(), centerPoint.y());
+ m_attentionTransform.scale(scale * 0.15 + 1.0, scale * 0.15 + 1.0);
+ m_attentionTransform.translate(-centerPoint.x(), -centerPoint.y());
+ m_inverseAttentionTransform = m_attentionTransform.inverted();
+ prepareGeometryChange();
+ setTransform(qmlItemNode().instanceTransform());
+ setTransform(m_attentionTransform, true);
+ } else {
+ m_attentionTransform.reset();
+ prepareGeometryChange();
+ setTransform(qmlItemNode().instanceTransform());
+ }
+}
+
+void FormEditorItem::setAttentionHighlight(double value)
+{
+ m_opacity = 0.6 + value;
+ if (QGraphicsItem::parentItem() == scene()->formLayerItem())
+ m_borderWidth = value * 4;
+ else
+ m_borderWidth = 1. + value * 3;
+
+ update();
+}
+
+FormEditorItem::~FormEditorItem()
+{
+ scene()->removeItemFromHash(this);
+}
+
+/* \brief returns the parent item skipping all proxyItem*/
+FormEditorItem *FormEditorItem::parentItem() const
+{
+ return qgraphicsitem_cast<FormEditorItem*> (QGraphicsItem::parentItem());
+}
+
+FormEditorItem* FormEditorItem::fromQGraphicsItem(QGraphicsItem *graphicsItem)
+{
+ return qgraphicsitem_cast<FormEditorItem*>(graphicsItem);
+}
+
+static QRectF alignedRect(const QRectF &rect)
+{
+ QRectF alignedRect(rect);
+ alignedRect.setTop(std::floor(rect.top()) + 0.5);
+ alignedRect.setBottom(std::floor(rect.bottom()) + 0.5);
+ alignedRect.setLeft(std::floor(rect.left()) + 0.5);
+ alignedRect.setRight(std::floor(rect.right()) + 0.5);
+
+ return alignedRect;
+}
+
+void FormEditorItem::paintBoundingRect(QPainter *painter) const
+{
+ if (QGraphicsItem::parentItem() == scene()->formLayerItem() && qFuzzyIsNull(m_borderWidth))
+ return;
+
+ QPen pen;
+ pen.setJoinStyle(Qt::MiterJoin);
+
+ switch(scene()->paintMode()) {
+ case FormEditorScene::AnchorMode: {
+ pen.setColor(Qt::black);
+ pen.setWidth(m_borderWidth);
+ }
+ break;
+ case FormEditorScene::NormalMode: {
+ pen.setColor(Qt::gray);
+ }
+ break;
+ }
+
+ painter->setPen(pen);
+ int offset = m_borderWidth / 2;
+ painter->drawRect(alignedRect(boundingRect().adjusted(offset, offset, -offset, -offset)));
+}
+
+void FormEditorItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ switch(scene()->paintMode()) {
+ case FormEditorScene::AnchorMode:
+ painter->setOpacity(m_opacity);
+ break;
+ case FormEditorScene::NormalMode:
+ painter->setOpacity(qmlItemNode().instanceValue("opacity").toDouble());
+ break;
+ }
+
+ qmlItemNode().paintInstance(painter);
+
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ paintBoundingRect(painter);
+
+ painter->restore();
+}
+
+AbstractFormEditorTool* FormEditorItem::tool() const
+{
+ return static_cast<FormEditorScene*>(scene())->currentTool();
+}
+
+SnapLineMap FormEditorItem::topSnappingLines() const
+{
+ return m_snappingLineCreator.topLines();
+}
+
+SnapLineMap FormEditorItem::bottomSnappingLines() const
+{
+ return m_snappingLineCreator.bottomLines();
+}
+
+SnapLineMap FormEditorItem::leftSnappingLines() const
+{
+ return m_snappingLineCreator.leftLines();
+}
+
+SnapLineMap FormEditorItem::rightSnappingLines() const
+{
+ return m_snappingLineCreator.rightLines();
+}
+
+SnapLineMap FormEditorItem::horizontalCenterSnappingLines() const
+{
+ return m_snappingLineCreator.horizontalCenterLines();
+}
+
+SnapLineMap FormEditorItem::verticalCenterSnappingLines() const
+{
+ return m_snappingLineCreator.verticalCenterLines();
+}
+
+SnapLineMap FormEditorItem::topSnappingOffsets() const
+{
+ return m_snappingLineCreator.topOffsets();
+}
+
+SnapLineMap FormEditorItem::bottomSnappingOffsets() const
+{
+ return m_snappingLineCreator.bottomOffsets();
+}
+
+SnapLineMap FormEditorItem::leftSnappingOffsets() const
+{
+ return m_snappingLineCreator.leftOffsets();
+}
+
+SnapLineMap FormEditorItem::rightSnappingOffsets() const
+{
+ return m_snappingLineCreator.rightOffsets();
+}
+
+
+void FormEditorItem::updateSnappingLines(const QList<FormEditorItem*> &exceptionList,
+ FormEditorItem *transformationSpaceItem)
+{
+ m_snappingLineCreator.update(exceptionList, transformationSpaceItem);
+}
+
+
+QList<FormEditorItem*> FormEditorItem::childFormEditorItems() const
+{
+ QList<FormEditorItem*> formEditorItemList;
+
+ foreach (QGraphicsItem *item, childItems()) {
+ FormEditorItem *formEditorItem = fromQGraphicsItem(item);
+ if (formEditorItem)
+ formEditorItemList.append(formEditorItem);
+ }
+
+ return formEditorItemList;
+}
+
+bool FormEditorItem::isContainer() const
+{
+ return qmlItemNode().modelNode().metaInfo().isContainer();
+}
+
+QmlItemNode FormEditorItem::qmlItemNode() const
+{
+ return m_qmlItemNode;
+}
+
+}
+
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditoritem.h b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
new file mode 100644
index 0000000000..b5ffc76992
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditoritem.h
@@ -0,0 +1,131 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORITEM_H
+#define FORMEDITORITEM_H
+
+#include <QWeakPointer>
+#include <QGraphicsWidget>
+#include <qmlitemnode.h>
+#include "snappinglinecreator.h"
+
+class QTimeLine;
+
+namespace QmlDesigner {
+
+class FormEditorScene;
+class FormEditorView;
+class AbstractFormEditorTool;
+
+namespace Internal {
+ class GraphicItemResizer;
+ class MoveController;
+}
+
+class FormEditorItem : public QGraphicsObject
+{
+ Q_OBJECT
+
+ friend class QmlDesigner::FormEditorScene;
+public:
+ ~FormEditorItem();
+
+ void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 );
+
+ bool isContainer() const;
+ QmlItemNode qmlItemNode() const;
+
+
+ enum { Type = UserType + 0xfffa };
+
+ int type() const;
+
+ static FormEditorItem* fromQGraphicsItem(QGraphicsItem *graphicsItem);
+
+ void updateSnappingLines(const QList<FormEditorItem*> &exceptionList,
+ FormEditorItem *transformationSpaceItem);
+
+ SnapLineMap topSnappingLines() const;
+ SnapLineMap bottomSnappingLines() const;
+ SnapLineMap leftSnappingLines() const;
+ SnapLineMap rightSnappingLines() const;
+ SnapLineMap horizontalCenterSnappingLines() const;
+ SnapLineMap verticalCenterSnappingLines() const;
+
+ SnapLineMap topSnappingOffsets() const;
+ SnapLineMap bottomSnappingOffsets() const;
+ SnapLineMap leftSnappingOffsets() const;
+ SnapLineMap rightSnappingOffsets() const;
+
+ QList<FormEditorItem*> childFormEditorItems() const;
+ FormEditorScene *scene() const;
+ FormEditorItem *parentItem() const;
+
+ QRectF boundingRect() const;
+
+ void updateGeometry();
+ void updateVisibilty();
+
+ void showAttention();
+
+ FormEditorView *formEditorView() const;
+
+protected:
+ AbstractFormEditorTool* tool() const;
+ void paintBoundingRect(QPainter *painter) const;
+
+private slots:
+ void changeAttention(qreal value);
+
+private: // functions
+ FormEditorItem(const QmlItemNode &qmlItemNode, FormEditorScene* scene);
+ void setup();
+ void setAttentionScale(double scale);
+ void setAttentionHighlight(double value);
+
+private: // variables
+ SnappingLineCreator m_snappingLineCreator;
+ QmlItemNode m_qmlItemNode;
+ QWeakPointer<QTimeLine> m_attentionTimeLine;
+ QTransform m_attentionTransform; // make item larger in anchor mode
+ QTransform m_inverseAttentionTransform;
+ QRectF m_boundingRect;
+ double m_borderWidth;
+ double m_opacity;
+};
+
+
+inline int FormEditorItem::type() const
+{
+ return UserType + 0xfffa;
+}
+
+}
+
+#endif // FORMEDITORITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp
new file mode 100644
index 0000000000..d1da63fafc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditormainview.cpp
@@ -0,0 +1,401 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditormainview.h"
+
+#include "formeditorview.h"
+#include "formeditorwidget.h"
+#include <QPixmapCache>
+#include <QtDebug>
+
+#include "zoomaction.h"
+
+namespace QmlDesigner {
+
+
+FormEditorMainView::FormEditorMainView()
+ : m_formMainEditorWidget(new FormEditorMainWidget(this))
+{
+ QPixmapCache::setCacheLimit(1024 * 100);
+}
+
+FormEditorMainView::~FormEditorMainView()
+{
+ resetViews();
+
+ if (m_formMainEditorWidget)
+ m_formMainEditorWidget->deleteLater();
+}
+
+void FormEditorMainView::modelAttached(Model *model)
+{
+ AbstractView::modelAttached(model);
+
+ setupSubViews();
+
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->modelAttached(model);
+ }
+
+ m_formMainEditorWidget->setModel(model);
+}
+
+void FormEditorMainView::createSubView(const QmlModelState &state)
+{
+ FormEditorView *subView = new FormEditorView(this);
+ subView->setCurrentState(state);
+ m_formEditorViewList.append(subView);
+
+ m_formMainEditorWidget->addWidget(subView->widget());
+ m_subWindowMap.insert(state, subView->widget());
+
+ subView->setZoomLevel(zoomAction()->zoomLevel());
+ connect(zoomAction(), SIGNAL(zoomLevelChanged(double)), subView, SLOT(setZoomLevel(double)));
+}
+
+void FormEditorMainView::removeSubView(const ModelState &state)
+{
+ QWidget *subWindow = m_subWindowMap.take(state).data();
+ Q_ASSERT(subWindow);
+ if (subWindow == m_formMainEditorWidget->currentWidget())
+ setCurrentState();
+ delete subWindow;
+
+ FormEditorView *editorView = 0;
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view->modelState() == state) {
+ editorView = view.data();
+ break;
+ }
+ }
+ Q_ASSERT(editorView);
+ m_formEditorViewList.removeOne(editorView);
+ delete editorView;
+}
+
+static bool modelStateLessThan(const ModelState &firstState, const ModelState &secondState)
+ {
+ if (firstState.isBaseState())
+ return false;
+
+ return firstState.name().toLower() > secondState.name().toLower();
+ }
+
+void FormEditorMainView::setupSubViews()
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ delete view.data();
+ m_formEditorViewList.clear();
+
+ foreach(const QWeakPointer<QWidget> &view, m_subWindowMap.values())
+ delete view.data();
+ m_subWindowMap.clear();
+
+ QList<ModelState> invertedStates(model()->modelStates());
+ qSort(invertedStates.begin(), invertedStates.end(), modelStateLessThan);
+ foreach(const ModelState &state, invertedStates)
+ createSubView(state);
+}
+
+void FormEditorMainView::resetViews()
+{
+ m_subWindowMap.clear();
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ delete view.data();
+ m_formEditorViewList.clear();
+}
+
+void FormEditorMainView::nodeCreated(const ModelNode &createdNode)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeCreated(createdNode);
+ }
+}
+
+void FormEditorMainView::modelAboutToBeDetached(Model *model)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->modelAboutToBeDetached(model);
+ }
+
+ resetViews();
+
+ m_formMainEditorWidget->setModel(0);
+
+ AbstractView::modelAboutToBeDetached(model);
+}
+
+void FormEditorMainView::nodeAboutToBeRemoved(const ModelNode &removedNode)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeAboutToBeRemoved(removedNode);
+ }
+}
+
+void FormEditorMainView::propertiesAdded(const NodeState &state, const QList<NodeProperty>& propertyList)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->propertiesAdded(state, propertyList);
+ }
+}
+
+void FormEditorMainView::propertiesAboutToBeRemoved(const NodeState &state, const QList<NodeProperty>& propertyList)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->propertiesAboutToBeRemoved(state, propertyList);
+ }
+}
+
+void FormEditorMainView::propertyValuesChanged(const NodeState &state, const QList<NodeProperty>& propertyList)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->propertyValuesChanged(state, propertyList);
+ }
+}
+
+void FormEditorMainView::nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeIdChanged(node, newId, oldId);
+ }
+}
+
+void FormEditorMainView::nodeReparented(const ModelNode &node, const ModelNode &oldParent, const ModelNode &newParent)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeReparented(node, oldParent, newParent);
+ }
+}
+
+FormEditorMainWidget *FormEditorMainView::widget() const
+{
+ return m_formMainEditorWidget.data();
+}
+
+NodeInstanceView *FormEditorMainView::nodeInstanceView(const ModelState &modelState) const
+{
+ foreach (const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view->modelState() == modelState)
+ return view->nodeInstanceView();
+ }
+
+ return 0;
+}
+
+void FormEditorMainView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
+ const QList<ModelNode> &lastSelectedNodeList)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->selectedNodesChanged(selectedNodeList, lastSelectedNodeList);
+ }
+}
+
+void FormEditorMainView::modelStateAboutToBeRemoved(const ModelState &modelState)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->modelStateAboutToBeRemoved(modelState);
+ }
+
+ removeSubView(modelState);
+}
+
+void FormEditorMainView::modelStateAdded(const ModelState &modelState)
+{
+ createSubView(modelState);
+ m_formEditorViewList.last()->modelAttached(model());
+
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->modelStateAdded(modelState);
+ }
+}
+
+void FormEditorMainView::nodeStatesAboutToBeRemoved(const QList<NodeState> &nodeStateList)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeStatesAboutToBeRemoved(nodeStateList);
+ }
+}
+
+void FormEditorMainView::nodeStatesAdded(const QList<NodeState> &nodeStateList)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeStatesAdded(nodeStateList);
+ }
+}
+
+void FormEditorMainView::setCurrentState(const QmlModelState &state)
+{
+ Q_ASSERT(m_subWindowMap.contains(state));
+ m_formMainEditorWidget->setCurrentWidget(m_subWindowMap.value(state).data());
+ emit stateChanged(state);
+}
+
+ModelState FormEditorMainView::currentState() const
+{
+ QWidget *currentWidget = m_formMainEditorWidget->currentWidget();
+ QMapIterator<ModelState, QWeakPointer<QWidget> > iter(m_subWindowMap);
+ while (iter.hasNext()) {
+ iter.next();
+ if (iter.value().data() == currentWidget) {
+ return iter.key();
+ }
+ }
+ Q_ASSERT_X(0, Q_FUNC_INFO, "cannot find current state");
+ return ModelState();
+}
+
+FormEditorMainView::EditorTool FormEditorMainView::currentTool() const
+{
+ return m_currentTool;
+}
+
+void FormEditorMainView::setCurrentTool(FormEditorMainView::EditorTool tool)
+{
+ if (m_currentTool == tool)
+ return;
+ m_currentTool = tool;
+ switch (tool) {
+ case MoveTool: {
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ view->changeToMoveTool();
+ break;
+ }
+ case DragTool: {
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ view->changeToDragTool();
+ break;
+ }
+ case SelectTool: {
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ view->changeToSelectionTool();
+ break;
+ }
+ case ResizeTool: {
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ view->changeToResizeTool();
+ break;
+ }
+ case AnchorTool: {
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ view->changeToAnchorTool();
+ break;
+ }
+ default: Q_ASSERT(0);
+ }
+ emit toolChanged(m_currentTool);
+}
+
+void FormEditorMainView::changeToDragTool()
+{
+ setCurrentTool(DragTool);
+}
+
+
+void FormEditorMainView::changeToMoveTool()
+{
+ setCurrentTool(MoveTool);
+}
+
+void FormEditorMainView::changeToMoveTool(const QPointF &/*beginPoint*/)
+{
+ setCurrentTool(MoveTool);
+}
+
+void FormEditorMainView::changeToSelectionTool()
+{
+ setCurrentTool(SelectTool);
+}
+
+void FormEditorMainView::changeToResizeTool()
+{
+ setCurrentTool(ResizeTool);
+}
+
+void FormEditorMainView::changeToAnchorTool()
+{
+ setCurrentTool(AnchorTool);
+}
+
+void FormEditorMainView::changeToTransformTools()
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList)
+ if (view)
+ view->changeToTransformTools();
+}
+
+void FormEditorMainView::anchorsChanged(const NodeState &nodeState)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->anchorsChanged(nodeState);
+ }
+}
+
+
+void FormEditorMainView::auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->auxiliaryDataChanged(node, name, data);
+ }
+}
+
+void FormEditorMainView::nodeSlidedToIndex(const ModelNode &node, int newIndex, int oldIndex)
+{
+ foreach(const QWeakPointer<FormEditorView> &view, m_formEditorViewList) {
+ if (view)
+ view->nodeSlidedToIndex(node, newIndex, oldIndex);
+ }
+}
+
+ComponentAction *FormEditorMainView::componentAction() const
+{
+ return m_formMainEditorWidget->componentAction();
+}
+
+ZoomAction *FormEditorMainView::zoomAction() const
+{
+ return m_formMainEditorWidget->zoomAction();
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainview.h b/src/plugins/qmldesigner/components/formeditor/formeditormainview.h
new file mode 100644
index 0000000000..05a563f09e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditormainview.h
@@ -0,0 +1,123 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORMAINVIEW_H
+#define FORMEDITORMAINVIEW_H
+
+#include <forwardview.h>
+
+#include <formeditormainwidget.h>
+#include <formeditorview.h>
+#include <QPointer>
+
+
+namespace QmlDesigner {
+class AbstractFormEditorTool;
+
+class FormEditorMainView : public ForwardView<FormEditorView>
+{
+ Q_OBJECT
+
+public:
+ FormEditorMainView();
+ ~FormEditorMainView();
+
+ // AbstractView
+ void modelAttached(Model *model);
+ void modelAboutToBeDetached(Model *model);
+ void nodeCreated(const ModelNode &createdNode);
+ void nodeAboutToBeRemoved(const ModelNode &removedNode);
+ void nodeReparented(const ModelNode &node, const ModelNode &oldParent, const ModelNode &newParent);
+ void propertiesAdded(const NodeState &state, const QList<NodeProperty>& propertyList);
+ void propertiesAboutToBeRemoved(const NodeState &state, const QList<NodeProperty>& propertyList);
+ void propertyValuesChanged(const NodeState& state, const QList<NodeProperty> &propertyList);
+ void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId);
+
+ void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
+ const QList<ModelNode> &lastSelectedNodeList);
+
+ void modelStateAboutToBeRemoved(const ModelState &modelState);
+ void modelStateAdded(const ModelState &modelState);
+
+ void nodeStatesAboutToBeRemoved(const QList<NodeState> &nodeStateList);
+ void nodeStatesAdded(const QList<NodeState> &nodeStateList);
+
+ void auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data);
+ // FormEditorMainView
+ FormEditorMainWidget *widget() const;
+ NodeInstanceView *nodeInstanceView(const ModelState &modelState) const;
+
+ void setCurrentState(const ModelState &state);
+ ModelState currentState() const;
+
+ enum EditorTool {
+ MoveTool,
+ DragTool,
+ SelectTool,
+ ResizeTool,
+ AnchorTool
+ };
+
+ EditorTool currentTool() const;
+ void setCurrentTool(EditorTool tool);
+
+ void changeToMoveTool();
+ void changeToMoveTool(const QPointF &beginPoint);
+ void changeToDragTool();
+ void changeToSelectionTool();
+ void changeToResizeTool();
+ void changeToTransformTools();
+ void changeToAnchorTool();
+
+ void anchorsChanged(const NodeState &nodeState);
+ void nodeSlidedToIndex(const ModelNode &node, int newIndex, int oldIndex);
+
+ ComponentAction *componentAction() const;
+ ZoomAction *zoomAction() const;
+
+signals:
+ void stateChanged(const ModelState &state);
+ void toolChanged(EditorTool tool);
+
+protected:
+ void setupSubViews();
+ void createSubView(const QmlModelState &state);
+ void removeSubView(const QmlModelState &state);
+ void resetViews();
+
+private:
+ QWeakPointer<FormEditorMainWidget> m_formMainEditorWidget;
+ QList<QWeakPointer<FormEditorView> > m_formEditorViewList;
+ QMap<ModelState, QWeakPointer<QWidget> > m_subWindowMap;
+ EditorTool m_currentTool;
+};
+
+} // namespace QmlDesigner
+
+#endif // FORMEDITORMAINVIEW_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp
new file mode 100644
index 0000000000..ade4aace51
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.cpp
@@ -0,0 +1,156 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditormainwidget.h"
+
+#include <QAction>
+#include <formeditormainview.h>
+#include <QtDebug>
+#include <QToolBar>
+#include <QVBoxLayout>
+#include <QFile>
+#include "toolbox.h"
+#include "componentaction.h"
+#include "zoomaction.h"
+#include <QWheelEvent>
+#include <cmath>
+
+namespace QmlDesigner {
+
+FormEditorMainWidget::FormEditorMainWidget(FormEditorMainView *mainView)
+ : QWidget(),
+ m_formEditorMainView(mainView),
+ m_stackedWidget(new QStackedWidget(this))
+{
+ QFile file(":/qmldesigner/stylesheet.css");
+ file.open(QFile::ReadOnly);
+ QString styleSheet = QLatin1String(file.readAll());
+ setStyleSheet(styleSheet);
+
+ QVBoxLayout *fillLayout = new QVBoxLayout(this);
+ fillLayout->setMargin(0);
+ fillLayout->setSpacing(0);
+ setLayout(fillLayout);
+
+ QActionGroup *toolActionGroup = new QActionGroup(this);
+
+ QAction *transformToolAction = toolActionGroup->addAction("Transform Tool (Press Key Q)");
+ transformToolAction->setShortcut(Qt::Key_Q);
+ transformToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+ transformToolAction->setCheckable(true);
+ transformToolAction->setChecked(true);
+ transformToolAction->setIcon(QPixmap(":/icon/tool/transform.png"));
+ connect(transformToolAction, SIGNAL(triggered(bool)), SLOT(changeTransformTool(bool)));
+
+ QAction *anchorToolAction = toolActionGroup->addAction("Anchor Tool (Press Key W)");
+ anchorToolAction->setShortcut(Qt::Key_W);
+ anchorToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+ anchorToolAction->setCheckable(true);
+ anchorToolAction->setIcon(QPixmap(":/icon/tool/anchor.png"));
+ connect(anchorToolAction, SIGNAL(triggered(bool)), SLOT(changeAnchorTool(bool)));
+
+ addActions(toolActionGroup->actions());
+
+
+ m_componentAction = new ComponentAction(toolActionGroup);
+ addAction(m_componentAction.data());
+
+ m_zoomAction = new ZoomAction(toolActionGroup);
+ addAction(m_zoomAction.data());
+
+ ToolBox *toolBox = new ToolBox(this);
+ toolBox->setActions(actions());
+ fillLayout->addWidget(toolBox);
+
+ fillLayout->addWidget(m_stackedWidget.data());
+}
+
+void FormEditorMainWidget::addWidget(QWidget *widget)
+{
+ m_stackedWidget->addWidget(widget);
+}
+
+QWidget *FormEditorMainWidget::currentWidget() const
+{
+ return m_stackedWidget->currentWidget();
+}
+
+void FormEditorMainWidget::setCurrentWidget(QWidget *widget)
+{
+ m_stackedWidget->setCurrentWidget(widget);
+}
+
+void FormEditorMainWidget::setModel(Model *model)
+{
+ m_componentAction->setDisabled(true);
+
+ if (model) {
+ m_componentAction->setModel(model->masterModel());
+ m_componentAction->setEnabled(true);
+ }
+}
+
+void FormEditorMainWidget::changeTransformTool(bool checked)
+{
+ if (checked)
+ m_formEditorMainView->changeToTransformTools();
+}
+
+void FormEditorMainWidget::changeAnchorTool(bool checked)
+{
+ if (checked)
+ m_formEditorMainView->changeToAnchorTool();
+}
+
+ComponentAction *FormEditorMainWidget::componentAction() const
+{
+ return m_componentAction.data();
+}
+
+ZoomAction *FormEditorMainWidget::zoomAction() const
+{
+ return m_zoomAction.data();
+}
+
+void FormEditorMainWidget::wheelEvent(QWheelEvent *event)
+{
+ if (event->modifiers().testFlag(Qt::ControlModifier)) {
+ if (event->delta() > 0) {
+ zoomAction()->zoomIn();
+ } else {
+ zoomAction()->zoomOut();
+ }
+
+ event->accept();
+ } else {
+ QWidget::wheelEvent(event);
+ }
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h
new file mode 100644
index 0000000000..d07afa5fc4
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditormainwidget.h
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORMAINWIDGET_H
+#define FORMEDITORMAINWIDGET_H
+
+#include <QStackedWidget>
+#include <QWeakPointer>
+
+
+
+namespace QmlDesigner {
+
+class Model;
+class FormEditorMainView;
+class ComponentAction;
+class ZoomAction;
+
+class FormEditorMainWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ FormEditorMainWidget(FormEditorMainView *mainView);
+
+ void addWidget(QWidget *widget);
+ QWidget *currentWidget() const;
+ void setCurrentWidget(QWidget *widget);
+ void setModel(Model *model);
+
+ ComponentAction *componentAction() const;
+ ZoomAction *zoomAction() const;
+
+protected:
+ void wheelEvent(QWheelEvent *event);
+
+private slots:
+ void changeTransformTool(bool checked);
+ void changeAnchorTool(bool checked);
+
+private:
+ QWeakPointer<FormEditorMainView> m_formEditorMainView;
+ QWeakPointer<QStackedWidget> m_stackedWidget;
+ QWeakPointer<ComponentAction> m_componentAction;
+ QWeakPointer<ZoomAction> m_zoomAction;
+};
+
+}
+#endif // FORMEDITORMAINWIDGET_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp
new file mode 100644
index 0000000000..7516f55934
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.cpp
@@ -0,0 +1,48 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditornodeinstanceview.h"
+#include "formeditorview.h"
+
+#include <modelnode.h>
+#include <QtCore/QDebug>
+
+
+namespace QmlDesigner {
+
+FormEditorNodeInstanceView::FormEditorNodeInstanceView(QObject * parent) : NodeInstanceView(parent)
+{
+
+}
+
+FormEditorNodeInstanceView::~FormEditorNodeInstanceView()
+{
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h
new file mode 100644
index 0000000000..b1c9909e92
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditornodeinstanceview.h
@@ -0,0 +1,50 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORNODEINSTANCE_H
+#define FORMEDITORNODEINSTANCE_H
+
+
+#include <nodeinstanceview.h>
+
+namespace QmlDesigner {
+
+class FormEditorView;
+
+class FormEditorNodeInstanceView : public NodeInstanceView
+{
+ Q_OBJECT
+public:
+ FormEditorNodeInstanceView(QObject * parent);
+ ~FormEditorNodeInstanceView();
+};
+
+
+}
+#endif //FORMEDITORNODEINSTANCE_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp
new file mode 100644
index 0000000000..9c7c69d67a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp
@@ -0,0 +1,364 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditorscene.h"
+#include "formeditorview.h"
+#include "formeditorwidget.h"
+#include "formeditoritem.h"
+#include "movemanipulator.h"
+#include <metainfo.h>
+#include <QGraphicsSceneDragDropEvent>
+
+#include <QEvent>
+#include <QGraphicsSceneMouseEvent>
+#include <QGraphicsSceneHoverEvent>
+#include <QGraphicsView>
+
+#include <QApplication>
+#include <QDebug>
+#include <QList>
+
+#include "formeditornodeinstanceview.h"
+
+#include "resizehandleitem.h"
+#include <QtDebug>
+
+
+
+namespace QmlDesigner {
+
+FormEditorScene::FormEditorScene(FormEditorWidget *view, FormEditorView *editorView)
+ : QGraphicsScene(),
+ m_editorView(editorView),
+ m_formLayerItem(new LayerItem(this)),
+ m_manipulatorLayerItem(new LayerItem(this)),
+ m_paintMode(NormalMode)
+
+{
+ setSceneRect(0, 0, 1, 1); // prevent automatic calculation (causing a recursion), right size will be set later
+
+ m_manipulatorLayerItem->setZValue(1.0);
+ m_formLayerItem->setZValue(0.0);
+ m_formLayerItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
+ view->setScene(this);
+
+// setItemIndexMethod(QGraphicsScene::NoIndex);
+}
+
+FormEditorScene::~FormEditorScene()
+{
+ clear(); //FormEditorItems have to be cleared before destruction
+ //Reason: FormEditorItems accesses FormEditorScene in destructor
+}
+
+
+FormEditorItem* FormEditorScene::itemForQmlItemNode(const QmlItemNode &qmlItemNode) const
+{
+ Q_ASSERT(hasItemForQmlItemNode(qmlItemNode));
+ return m_qmlItemNodeItemHash.value(qmlItemNode);
+}
+
+
+QList<FormEditorItem*> FormEditorScene::itemsForQmlItemNodes(const QList<QmlItemNode> &nodeList) const
+{
+ QList<FormEditorItem*> itemList;
+ foreach (const QmlItemNode &node, nodeList) {
+ if (hasItemForQmlItemNode(node))
+ itemList += itemForQmlItemNode(node);
+ }
+
+ return itemList;
+}
+
+QList<FormEditorItem*> FormEditorScene::allFormEditorItems() const
+{
+ return m_qmlItemNodeItemHash.values();
+}
+
+void FormEditorScene::updateAllFormEditorItems()
+{
+ foreach (FormEditorItem *item, allFormEditorItems()) {
+ item->update();
+ }
+}
+
+bool FormEditorScene::hasItemForQmlItemNode(const QmlItemNode &qmlItemNode) const
+{
+ return m_qmlItemNodeItemHash.contains(qmlItemNode);
+}
+
+void FormEditorScene::removeItemFromHash(FormEditorItem *item)
+{
+ m_qmlItemNodeItemHash.remove(item->qmlItemNode());
+}
+
+
+AbstractFormEditorTool* FormEditorScene::currentTool() const
+{
+ return m_editorView->currentTool();
+}
+
+//This method calculates the possible parent for reparent
+FormEditorItem* FormEditorScene::calulateNewParent(FormEditorItem *formEditorItem)
+{
+ QList<QGraphicsItem *> list = items(formEditorItem->qmlItemNode().instanceBoundingRect().center());
+ foreach (QGraphicsItem *graphicsItem, list) {
+ if (qgraphicsitem_cast<FormEditorItem*>(graphicsItem) &&
+ graphicsItem->collidesWithItem(formEditorItem, Qt::ContainsItemShape))
+ return qgraphicsitem_cast<FormEditorItem*>(graphicsItem);
+ }
+ return 0;
+}
+
+void FormEditorScene::synchronizeTransformation(const QmlItemNode &qmlItemNode)
+{
+ FormEditorItem *item = itemForQmlItemNode(qmlItemNode);
+ item->updateGeometry();
+ item->update();
+
+ if (qmlItemNode.isRootNode()) {
+ QRectF sceneRect(qmlItemNode.instanceBoundingRect());
+
+ setSceneRect(sceneRect);
+ formLayerItem()->update();
+ manipulatorLayerItem()->update();
+ }
+}
+
+void FormEditorScene::synchronizeParent(const QmlItemNode &qmlItemNode)
+{
+ QmlItemNode parentNode = qmlItemNode.instanceParent().toQmlItemNode();
+ if (parentNode.isValid())
+ reparentItem(qmlItemNode, parentNode);
+}
+
+void FormEditorScene::synchronizeOtherProperty(const QmlItemNode &qmlItemNode)
+{
+ if (hasItemForQmlItemNode(qmlItemNode)) {
+ FormEditorItem *item = itemForQmlItemNode(qmlItemNode);
+ if (item)
+ item->update();
+ }
+}
+
+void FormEditorScene::synchronizeState(const QmlItemNode &qmlItemNode)
+{
+ if (hasItemForQmlItemNode(qmlItemNode)) {
+ FormEditorItem *item = itemForQmlItemNode(qmlItemNode);
+ if (item)
+ item->update();
+ }
+}
+
+
+FormEditorItem *FormEditorScene::addFormEditorItem(const QmlItemNode &qmlItemNode)
+{
+ FormEditorItem *formEditorItem = new FormEditorItem(qmlItemNode, this);
+ Q_ASSERT(!m_qmlItemNodeItemHash.contains(qmlItemNode));
+
+ m_qmlItemNodeItemHash.insert(qmlItemNode, formEditorItem);
+ if (qmlItemNode.isRootNode()) {
+ QRectF sceneRect(qmlItemNode.instanceBoundingRect());
+
+ setSceneRect(sceneRect);
+ formLayerItem()->update();
+ manipulatorLayerItem()->update();
+ }
+
+ return formEditorItem;
+}
+
+
+void FormEditorScene::dropEvent(QGraphicsSceneDragDropEvent * event)
+{
+ currentTool()->dropEvent(event);
+
+ if (views().first())
+ views().first()->setFocus();
+}
+
+void FormEditorScene::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
+{
+ currentTool()->dragEnterEvent(event);
+}
+
+void FormEditorScene::dragLeaveEvent(QGraphicsSceneDragDropEvent * event)
+{
+ currentTool()->dragLeaveEvent(event);
+
+ return;
+
+ if (m_dragNode.isValid()) {
+ m_dragNode.destroy();
+ }
+}
+
+void FormEditorScene::dragMoveEvent(QGraphicsSceneDragDropEvent * event)
+{
+ currentTool()->dragMoveEvent(event);
+}
+
+QList<QGraphicsItem *> FormEditorScene::removeLayerItems(const QList<QGraphicsItem *> &itemList)
+{
+ QList<QGraphicsItem *> itemListWithoutLayerItems;
+
+ foreach (QGraphicsItem *item, itemList)
+ if (item != manipulatorLayerItem() && item != formLayerItem())
+ itemListWithoutLayerItems.append(item);
+
+ return itemListWithoutLayerItems;
+}
+
+void FormEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ currentTool()->mousePressEvent(removeLayerItems(items(event->scenePos())), event);
+}
+
+void FormEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->buttons())
+ currentTool()->mouseMoveEvent(removeLayerItems(items(event->scenePos())), event);
+ else
+ currentTool()->hoverMoveEvent(removeLayerItems(items(event->scenePos())), event);
+
+ event->accept();
+}
+
+void FormEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ currentTool()->mouseReleaseEvent(removeLayerItems(items(event->scenePos())), event);
+
+ event->accept();
+ }
+
+void FormEditorScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
+{
+ currentTool()->mouseDoubleClickEvent(removeLayerItems(items(event->scenePos())), event);
+
+ event->accept();
+}
+
+void FormEditorScene::keyPressEvent(QKeyEvent *keyEvent)
+{
+ currentTool()->keyPressEvent(keyEvent);
+}
+
+void FormEditorScene::keyReleaseEvent(QKeyEvent *keyEvent)
+{
+ currentTool()->keyReleaseEvent(keyEvent);
+}
+
+FormEditorView *FormEditorScene::editorView() const
+{
+ return m_editorView;
+}
+
+LayerItem* FormEditorScene::manipulatorLayerItem() const
+{
+ return m_manipulatorLayerItem.data();
+}
+
+LayerItem* FormEditorScene::formLayerItem() const
+{
+ return m_formLayerItem.data();
+}
+
+bool FormEditorScene::event(QEvent * event)
+{
+ switch(event->type())
+ {
+ case QEvent::GraphicsSceneHoverEnter :
+ hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ return true;
+ case QEvent::GraphicsSceneHoverMove :
+ hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ return true;
+ case QEvent::GraphicsSceneHoverLeave :
+ hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
+ return true;
+ default: return QGraphicsScene::event(event);
+ }
+
+}
+
+void FormEditorScene::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
+{
+ qDebug() << __FUNCTION__;
+}
+
+void FormEditorScene::hoverMoveEvent(QGraphicsSceneHoverEvent * /*event*/)
+{
+ qDebug() << __FUNCTION__;
+}
+
+void FormEditorScene::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
+{
+ qDebug() << __FUNCTION__;
+}
+
+
+void FormEditorScene::reparentItem(const QmlItemNode &node, const QmlItemNode &newParent)
+{
+ Q_ASSERT(hasItemForQmlItemNode(node));
+ Q_ASSERT(hasItemForQmlItemNode(newParent));
+ FormEditorItem *item = itemForQmlItemNode(node);
+ FormEditorItem *parentItem = itemForQmlItemNode(newParent);
+ item->setParentItem(parentItem);
+ item->setParent(parentItem);
+}
+
+FormEditorItem* FormEditorScene::rootFormEditorItem() const
+{
+ QList<QGraphicsItem*> childItemList(m_formLayerItem->childItems());
+ if (!childItemList.isEmpty())
+ return FormEditorItem::fromQGraphicsItem(childItemList.first());
+
+ return 0;
+}
+
+FormEditorScene::PaintMode FormEditorScene::paintMode() const
+{
+ return m_paintMode;
+}
+
+void FormEditorScene::setPaintMode(PaintMode paintMode)
+{
+ m_paintMode = paintMode;
+}
+
+void FormEditorScene::clearFormEditorItems()
+{
+ foreach (QGraphicsItem *item, items()) {
+ if (qgraphicsitem_cast<FormEditorItem* >(item))
+ delete item;
+ }
+}
+
+}
+
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h
new file mode 100644
index 0000000000..89098ba7ab
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h
@@ -0,0 +1,133 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORSCENE_H
+#define FORMEDITORSCENE_H
+
+
+#include <QGraphicsScene>
+#include <QWeakPointer>
+#include <QHash>
+#include <qmlitemnode.h>
+#include "abstractformeditortool.h"
+
+
+class QGraphicsSceneMouseEvent;
+
+namespace QmlDesigner {
+
+class FormEditorWidget;
+class FormEditorItem;
+class FormEditorView;
+class LayerItem;
+
+class FormEditorScene : public QGraphicsScene
+{
+ Q_OBJECT
+
+ friend class QmlDesigner::FormEditorItem;
+ friend class QmlDesigner::FormEditorView;
+
+public:
+ enum PaintMode {
+ NormalMode,
+ AnchorMode
+ };
+
+ FormEditorScene(FormEditorWidget *widget, FormEditorView *editorView);
+ ~FormEditorScene();
+ FormEditorItem *addFormEditorItem(const QmlItemNode &qmlItemNode);
+
+ FormEditorItem* itemForQmlItemNode(const QmlItemNode &qmlItemNode) const;
+
+ QList<FormEditorItem*> itemsForQmlItemNodes(const QList<QmlItemNode> &nodeList) const;
+ QList<FormEditorItem*> allFormEditorItems() const;
+
+ void updateAllFormEditorItems();
+
+ bool hasItemForQmlItemNode(const QmlItemNode &qmlItemNode) const;
+
+ void synchronizeTransformation(const QmlItemNode &qmlItemNode);
+ void synchronizeParent(const QmlItemNode &qmlItemNode);
+ void synchronizeOtherProperty(const QmlItemNode &qmlItemNode);
+ void synchronizeState(const QmlItemNode &qmlItemNode);
+
+ FormEditorItem* calulateNewParent(FormEditorItem *widget);
+ bool event(QEvent *event);
+ LayerItem* manipulatorLayerItem() const;
+ LayerItem* formLayerItem() const;
+ FormEditorView *editorView() const;
+
+ FormEditorItem *rootFormEditorItem() const;
+
+ void reparentItem(const QmlItemNode &node, const QmlItemNode &newParent);
+
+ PaintMode paintMode() const;
+ void setPaintMode(PaintMode paintMode);
+
+ void clearFormEditorItems();
+
+protected:
+ void dropEvent(QGraphicsSceneDragDropEvent * event);
+ void dragEnterEvent(QGraphicsSceneDragDropEvent * event);
+ void dragLeaveEvent(QGraphicsSceneDragDropEvent * event);
+ void dragMoveEvent(QGraphicsSceneDragDropEvent * event);
+ void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
+
+ void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
+ void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
+
+ void keyPressEvent(QKeyEvent *keyEvent);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+private:
+ QList<QGraphicsItem *> removeLayerItems(const QList<QGraphicsItem *> &itemList);
+
+ AbstractFormEditorTool* currentTool() const;
+ void removeItemFromHash(FormEditorItem*);
+
+ FormEditorView *m_editorView;
+ AbstractFormEditorTool *m_currentTool;
+ QHash<QmlItemNode, FormEditorItem*> m_qmlItemNodeItemHash;
+ QWeakPointer<LayerItem> m_formLayerItem;
+ QWeakPointer<LayerItem> m_manipulatorLayerItem;
+ ModelNode m_dragNode;
+ PaintMode m_paintMode;
+};
+
+
+
+
+}
+#endif //FORMEDITORSCENE_H
+
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp
new file mode 100644
index 0000000000..8fe38a042e
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.cpp
@@ -0,0 +1,38 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditorsubwindow.h"
+
+namespace QmlDesigner {
+
+FormEditorSubWindow::FormEditorSubWindow()
+{
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h
new file mode 100644
index 0000000000..9376d73b89
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorsubwindow.h
@@ -0,0 +1,45 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORSUBWINDOW_H
+#define FORMEDITORSUBWINDOW_H
+
+#include <QMdiSubWindow>
+
+namespace QmlDesigner {
+
+class FormEditorSubWindow : public QMdiSubWindow
+{
+public:
+ FormEditorSubWindow();
+};
+
+} // namespace QmlDesigner
+
+#endif // FORMEDITORSUBWINDOW_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
new file mode 100644
index 0000000000..7da0cb9ed5
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
@@ -0,0 +1,531 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "selectiontool.h"
+#include "movetool.h"
+#include "resizetool.h"
+#include "anchortool.h"
+#include "dragtool.h"
+#include "itemcreatortool.h"
+#include "formeditorview.h"
+#include "formeditorwidget.h"
+#include "formeditornodeinstanceview.h"
+#include "formeditoritem.h"
+#include "formeditorscene.h"
+#include <rewritertransaction.h>
+#include <modelnode.h>
+#include <modelutilities.h>
+#include <itemlibraryinfo.h>
+#include <metainfo.h>
+#include <model.h>
+#include <QApplication>
+#include <QtDebug>
+#include <QPair>
+#include <QString>
+#include <QDir>
+#include <QAction>
+#include <zoomaction.h>
+
+namespace QmlDesigner {
+
+FormEditorView::FormEditorView(QObject *parent)
+ : QmlModelView(parent),
+ m_formEditorWidget(new FormEditorWidget(this)),
+ m_scene(new FormEditorScene(m_formEditorWidget.data(), this)),
+ m_moveTool(new MoveTool(this)),
+ m_selectionTool(new SelectionTool(this)),
+ m_resizeTool(new ResizeTool(this)),
+ m_anchorTool(new AnchorTool(this)),
+ m_dragTool(new DragTool(this)),
+ m_itemCreatorTool(new ItemCreatorTool(this)),
+ m_currentTool(m_selectionTool)
+{
+ connect(widget()->zoomAction(), SIGNAL(zoomLevelChanged(double)), SLOT(updateGraphicsIndicators()));
+}
+
+FormEditorScene* FormEditorView::scene() const
+{
+ return m_scene.data();
+}
+
+FormEditorView::~FormEditorView()
+{
+ delete m_selectionTool;
+ m_selectionTool = 0;
+ delete m_moveTool;
+ m_moveTool = 0;
+ delete m_resizeTool;
+ m_resizeTool = 0;
+ delete m_anchorTool;
+ m_anchorTool = 0;
+ delete m_dragTool;
+ m_dragTool = 0;
+
+
+ // delete scene after tools to prevent double deletion
+ // of items
+ delete m_scene.data();
+ delete m_formEditorWidget.data();
+}
+
+void FormEditorView::modelAttached(Model *model)
+{
+ Q_ASSERT(model);
+
+ QmlModelView::modelAttached(model);
+
+ Q_ASSERT(m_scene->formLayerItem());
+
+ if (rootQmlObjectNode().toQmlItemNode().isValid())
+ setupFormEditorItemTree(rootQmlObjectNode().toQmlItemNode());
+}
+
+
+//This method does the setup of the inital FormEditorItem tree in the scene
+void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode)
+{
+ m_scene->addFormEditorItem(qmlItemNode);
+
+ foreach (const QmlItemNode &nextNode, qmlItemNode.children()) //TODO instance children
+ setupFormEditorItemTree(nextNode);
+}
+
+void FormEditorView::nodeCreated(const ModelNode &createdNode)
+{
+ QmlModelView::nodeCreated(createdNode);
+ ModelNode node(createdNode);
+ if (QmlItemNode(node).isValid()) //only setup QmlItems
+ setupFormEditorItemTree(QmlItemNode(node));
+}
+
+void FormEditorView::modelAboutToBeDetached(Model *model)
+{
+ m_selectionTool->clear();
+ m_moveTool->clear();
+ m_resizeTool->clear();
+ m_anchorTool->clear();
+ m_dragTool->clear();
+ m_scene->clearFormEditorItems();
+
+ QmlModelView::modelAboutToBeDetached(model);
+}
+
+void FormEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode)
+{
+ QmlItemNode qmlItemNode(removedNode);
+
+ if (qmlItemNode.isValid()) {
+
+ FormEditorItem *item = m_scene->itemForQmlItemNode(qmlItemNode);
+
+ QList<QmlItemNode> nodeList;
+ nodeList.append(qmlItemNode.allSubModelNodes());
+ nodeList.append(qmlItemNode);
+
+ QList<FormEditorItem*> removedItemList;
+ removedItemList.append(scene()->itemsForQmlItemNodes(nodeList));
+ m_currentTool->itemsAboutToRemoved(removedItemList);
+
+ delete item;
+ }
+
+ QmlModelView::nodeAboutToBeRemoved(removedNode);
+}
+
+ void FormEditorView::nodeTypeChanged(const ModelNode &node,const QString &type, int majorVersion, int minorVersion)
+ {
+ QmlItemNode oldItemNode(node);
+ if (oldItemNode.isValid() && m_scene->hasItemForQmlItemNode(oldItemNode)) {
+ FormEditorItem *item = m_scene->itemForQmlItemNode(oldItemNode);
+
+ QList<QmlItemNode> nodeList;
+ nodeList.append(oldItemNode.allSubModelNodes());
+ nodeList.append(oldItemNode);
+
+ QList<FormEditorItem*> removedItemList;
+ removedItemList.append(scene()->itemsForQmlItemNodes(nodeList));
+ m_currentTool->itemsAboutToRemoved(removedItemList);
+
+ delete item;
+ }
+
+ QmlModelView::nodeTypeChanged(node, type, majorVersion, minorVersion);
+
+ QmlItemNode newItemNode(node);
+ if (newItemNode.isValid()) //only setup QmlItems
+ setupFormEditorItemTree(newItemNode);
+ }
+
+void FormEditorView::propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList)
+{
+ QmlModelView::propertiesAboutToBeRemoved(propertyList);
+}
+void FormEditorView::nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange)
+{
+ QmlModelView::nodeReparented(node, newPropertyParent, oldPropertyParent, propertyChange);
+}
+
+void FormEditorView::variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange)
+{
+ QmlModelView::variantPropertiesChanged(propertyList, propertyChange);
+}
+
+void FormEditorView::bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange)
+{
+ QmlModelView::bindingPropertiesChanged(propertyList, propertyChange);
+}
+
+FormEditorWidget *FormEditorView::widget() const
+{
+ Q_ASSERT(!m_formEditorWidget.isNull());
+ return m_formEditorWidget.data();
+}
+
+void FormEditorView::nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId)
+{
+ nodeInstanceView()->nodeIdChanged(node, newId, oldId);
+}
+
+void FormEditorView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
+ const QList<ModelNode> &lastSelectedNodeList)
+{
+ QmlModelView::selectedNodesChanged(selectedNodeList, lastSelectedNodeList);
+
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(toQmlItemNodeList(selectedNodeList)));
+ if (scene()->paintMode() == FormEditorScene::AnchorMode) {
+ foreach (FormEditorItem *item, m_scene->itemsForQmlItemNodes(toQmlItemNodeList(selectedNodeList)))
+ item->update();
+
+ foreach (FormEditorItem *item, m_scene->itemsForQmlItemNodes(toQmlItemNodeList(lastSelectedNodeList)))
+ item->update();
+ }
+
+ m_scene->update();
+}
+
+AbstractFormEditorTool* FormEditorView::currentTool() const
+{
+ return m_currentTool;
+}
+
+void FormEditorView::changeToMoveTool()
+{
+ if (m_currentTool == m_moveTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::SizeAllCursor);
+ m_currentTool->clear();
+ m_currentTool = m_moveTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+}
+
+void FormEditorView::changeToDragTool()
+{
+ if (m_currentTool == m_dragTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::ArrowCursor);
+ setCurrentState(baseState());
+ m_currentTool->clear();
+ m_currentTool = m_dragTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+}
+
+
+void FormEditorView::changeToMoveTool(const QPointF &beginPoint)
+{
+ if (m_currentTool == m_moveTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::SizeAllCursor);
+ m_currentTool->clear();
+ m_currentTool = m_moveTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+ m_moveTool->beginWithPoint(beginPoint);
+}
+
+void FormEditorView::changeToSelectionTool()
+{
+ if (m_currentTool == m_selectionTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::ArrowCursor);
+ m_currentTool->clear();
+ m_currentTool = m_selectionTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+}
+
+void FormEditorView::changeToItemCreatorTool()
+{
+ if(m_currentTool == m_itemCreatorTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::CrossCursor);
+ setCurrentState(baseState());
+ m_currentTool->clear();
+ m_currentTool = m_itemCreatorTool;
+ m_currentTool->clear();
+ setSelectedQmlItemNodes(QList<QmlItemNode>());
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+}
+
+void FormEditorView::changeToSelectionTool(QGraphicsSceneMouseEvent *event)
+{
+ if (m_currentTool == m_selectionTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::ArrowCursor);
+ m_currentTool->clear();
+ m_currentTool = m_selectionTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+
+ m_selectionTool->selectUnderPoint(event);
+}
+
+void FormEditorView::changeToResizeTool()
+{
+ if (m_currentTool == m_resizeTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::NormalMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::ArrowCursor);
+ m_currentTool->clear();
+ m_currentTool = m_resizeTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+}
+
+void FormEditorView::changeToAnchorTool()
+{
+ if (m_currentTool == m_anchorTool)
+ return;
+
+ scene()->setPaintMode(FormEditorScene::AnchorMode);
+ m_scene->updateAllFormEditorItems();
+ setCursor(Qt::ArrowCursor);
+ m_currentTool->clear();
+ m_currentTool = m_anchorTool;
+ m_currentTool->clear();
+ m_currentTool->setItems(scene()->itemsForQmlItemNodes(selectedQmlItemNodes()));
+}
+
+void FormEditorView::changeToTransformTools()
+{
+ if (m_currentTool == m_moveTool ||
+ m_currentTool == m_resizeTool ||
+ m_currentTool == m_selectionTool)
+ return;
+
+ changeToSelectionTool();
+}
+
+void FormEditorView::setCursor(const QCursor &cursor)
+{
+ m_formEditorWidget->setCursor(cursor);
+}
+
+bool FormEditorView::isSnapButtonChecked() const
+{
+ return m_formEditorWidget->isSnapButtonChecked();
+}
+
+
+void FormEditorView::nodeSlidedToIndex(const NodeListProperty &listProperty, int /*newIndex*/, int /*oldIndex*/)
+{
+ QList<ModelNode> newOrderModelNodeList = listProperty.toModelNodeList();
+ foreach(const ModelNode &node, newOrderModelNodeList) {
+ FormEditorItem *item = m_scene->itemForQmlItemNode(QmlItemNode(node));
+ if (item) {
+ FormEditorItem *oldParentItem = item->parentItem();
+ item->setParentItem(0);
+ item->setParentItem(oldParentItem);
+ }
+ }
+
+ m_currentTool->formEditorItemsChanged(scene()->allFormEditorItems());
+}
+
+void FormEditorView::auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data)
+{
+ QmlModelView::auxiliaryDataChanged(node, name, data);
+ if (name == "invisible") {
+ FormEditorItem *item(m_scene->itemForQmlItemNode(QmlItemNode(node)));
+ bool isInvisible = data.toBool();
+ item->setVisible(!isInvisible);
+ ModelNode newNode(node);
+ if (isInvisible)
+ newNode.deselectNode();
+ }
+}
+
+double FormEditorView::margins() const
+{
+ return m_formEditorWidget->margins();
+}
+
+double FormEditorView::spacing() const
+{
+ return m_formEditorWidget->spacing();
+}
+
+void FormEditorView::activateItemCreator(const QString &name)
+{
+ if (m_currentTool == m_itemCreatorTool) {
+ m_itemCreatorTool->setItemString(name);
+ return;
+ }
+ changeToItemCreatorTool();
+ m_itemCreatorTool->setItemString(name);
+}
+
+void FormEditorView::deActivateItemCreator()
+{
+ if (m_currentTool == m_itemCreatorTool) {
+ changeToSelectionTool();
+ emit ItemCreatorDeActivated();
+ }
+}
+
+QList<ModelNode> FormEditorView::adjustStatesForModelNodes(const QList<ModelNode> &nodeList) const
+{
+ QList<ModelNode> adjustedNodeList;
+ foreach (const ModelNode &node, nodeList)
+ adjustedNodeList.append(node);
+
+ return adjustedNodeList;
+}
+
+QmlItemNode findRecursiveQmlItemNode(const QmlObjectNode &firstQmlObjectNode)
+{
+ QmlObjectNode qmlObjectNode = firstQmlObjectNode;
+
+ while (true) {
+ QmlItemNode itemNode = qmlObjectNode.toQmlItemNode();
+ if (itemNode.isValid())
+ return itemNode;
+ if (qmlObjectNode.hasInstanceParent())
+ qmlObjectNode = qmlObjectNode.instanceParent();
+ else
+ break;
+ }
+
+ return QmlItemNode();
+}
+
+void FormEditorView::transformChanged(const QmlObjectNode &qmlObjectNode)
+{
+ QmlItemNode itemNode = qmlObjectNode.toQmlItemNode();
+ if (itemNode.isValid() && scene()->hasItemForQmlItemNode(itemNode)) {
+ m_scene->synchronizeTransformation(itemNode);
+ m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode));
+ }
+}
+
+void FormEditorView::parentChanged(const QmlObjectNode &qmlObjectNode)
+{
+ QmlItemNode itemNode = qmlObjectNode.toQmlItemNode();
+ QmlItemNode parentNode = qmlObjectNode.instanceParent().toQmlItemNode();
+ if (itemNode.isValid()
+ && scene()->hasItemForQmlItemNode(itemNode)
+ && parentNode.isValid()
+ && scene()->hasItemForQmlItemNode(parentNode)
+ && scene()->itemForQmlItemNode(itemNode)->parentItem() != scene()->itemForQmlItemNode(parentNode)) {
+ scene()->synchronizeParent(itemNode);
+ m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode));
+ }
+}
+
+void FormEditorView::otherPropertyChanged(const QmlObjectNode &qmlObjectNode)
+{
+ Q_ASSERT(qmlObjectNode.isValid());
+
+ QmlItemNode itemNode = findRecursiveQmlItemNode(qmlObjectNode);
+
+ if (itemNode.isValid() && scene()->hasItemForQmlItemNode(itemNode)) {
+ m_scene->synchronizeOtherProperty(itemNode);
+ m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode));
+ }
+}
+
+void FormEditorView::updateGraphicsIndicators()
+{
+ m_currentTool->formEditorItemsChanged(scene()->allFormEditorItems());
+}
+
+void FormEditorView::updateItem(const QmlObjectNode &qmlObjectNode)
+{
+
+ Q_ASSERT(qmlObjectNode.isValid());
+
+ QmlItemNode itemNode = findRecursiveQmlItemNode(qmlObjectNode);
+
+ if (itemNode.isValid() && scene()->hasItemForQmlItemNode(itemNode)) {
+ m_scene->synchronizeOtherProperty(itemNode);
+ m_currentTool->formEditorItemsChanged(QList<FormEditorItem*>() << m_scene->itemForQmlItemNode(itemNode));
+ }
+}
+
+void FormEditorView::stateChanged(const QmlModelState &newQmlModelState, const QmlModelState &oldQmlModelState)
+{
+ QmlModelView::stateChanged(newQmlModelState, oldQmlModelState);
+
+
+ m_formEditorWidget->anchorToolAction()->setEnabled(newQmlModelState.isBaseState());
+
+ if (!newQmlModelState.isBaseState() && currentTool() == m_anchorTool) {
+ changeToTransformTools();
+ m_formEditorWidget->transformToolAction()->setChecked(true);
+ }
+
+// FormEditorItem *item = m_scene->itemForQmlItemNode(fxObjectNode);
+//
+// m_currentTool->formEditorItemsChanged(itemList);
+}
+
+
+}
+
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h
new file mode 100644
index 0000000000..82b6f18a75
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h
@@ -0,0 +1,141 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORVIEW_H
+#define FORMEDITORVIEW_H
+
+#include <qmlmodelview.h>
+
+class QGraphicsScene;
+class QGraphicsSceneMouseEvent;
+
+namespace QmlDesigner {
+
+class FormEditorWidget;
+class FormEditorNodeInstanceView;
+class FormEditorScene;
+class NodeInstanceView;
+
+class AbstractFormEditorTool;
+class MoveTool;
+class SelectionTool;
+class ResizeTool;
+class AnchorTool;
+class DragTool;
+class ItemCreatorTool;
+class ItemLibraryInfo;
+class QmlItemNode;
+
+class FormEditorView : public QmlModelView
+{
+ Q_OBJECT
+
+public:
+ FormEditorView(QObject *parent);
+ ~FormEditorView();
+
+ // AbstractView
+ void modelAttached(Model *model);
+ void modelAboutToBeDetached(Model *model);
+
+ void nodeCreated(const ModelNode &createdNode);
+ void nodeAboutToBeRemoved(const ModelNode &removedNode);
+ void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
+ void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId);
+ void propertiesAboutToBeRemoved(const QList<AbstractProperty>& propertyList);
+ void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChange);
+ void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChange);
+ void nodeTypeChanged(const ModelNode &node,const QString &type, int majorVersion, int minorVersion);
+
+ void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
+ const QList<ModelNode> &lastSelectedNodeList);
+
+ // FormEditorView
+ FormEditorWidget *widget() const;
+ AbstractFormEditorTool *currentTool() const;
+ FormEditorScene *scene() const;
+
+ void changeToMoveTool();
+ void changeToMoveTool(const QPointF &beginPoint);
+ void changeToDragTool();
+ void changeToSelectionTool();
+ void changeToItemCreatorTool();
+ void changeToSelectionTool(QGraphicsSceneMouseEvent *event);
+ void changeToResizeTool();
+ void changeToAnchorTool();
+ void changeToTransformTools();
+
+ void setCursor(const QCursor &cursor);
+
+ bool isSnapButtonChecked() const;
+
+ void nodeSlidedToIndex(const NodeListProperty &listProperty, int newIndex, int oldIndex);
+ void auxiliaryDataChanged(const ModelNode &node, const QString &name, const QVariant &data);
+
+ double margins() const;
+ double spacing() const;
+ void deActivateItemCreator();
+
+public slots:
+ void activateItemCreator(const QString &name);
+
+signals:
+ void ItemCreatorDeActivated();
+
+protected:
+ void transformChanged(const QmlObjectNode &qmlObjectNode);
+ void parentChanged(const QmlObjectNode &qmlObjectNode);
+ void otherPropertyChanged(const QmlObjectNode &qmlObjectNode);
+ void updateItem(const QmlObjectNode &qmlObjectNode);
+ void stateChanged(const QmlModelState &newQmlModelState, const QmlModelState &oldQmlModelState);
+
+protected slots:
+ QList<ModelNode> adjustStatesForModelNodes(const QList<ModelNode> &nodeList) const;
+ void updateGraphicsIndicators();
+
+private: //functions
+ void setupFormEditorItemTree(const QmlItemNode &qmlItemNode);
+
+
+private: //variables
+ QWeakPointer<FormEditorWidget> m_formEditorWidget;
+ QWeakPointer<FormEditorScene> m_scene;
+ MoveTool *m_moveTool;
+ SelectionTool *m_selectionTool;
+ ResizeTool *m_resizeTool;
+ AnchorTool *m_anchorTool;
+ DragTool *m_dragTool;
+ ItemCreatorTool *m_itemCreatorTool;
+ AbstractFormEditorTool *m_currentTool;
+
+};
+
+}
+
+#endif //FORMEDITORVIEW_H
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp
new file mode 100644
index 0000000000..5217711fa4
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp
@@ -0,0 +1,221 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "formeditorwidget.h"
+
+#include <QWheelEvent>
+#include <cmath>
+#include <QCoreApplication>
+#include <QPushButton>
+#include <QFile>
+#include <QVBoxLayout>
+#include <QActionGroup>
+#include <QGraphicsView>
+#include <toolbox.h>
+#include <zoomaction.h>
+#include <formeditorgraphicsview.h>
+#include <formeditorscene.h>
+#include <formeditorview.h>
+#include "numberseriesaction.h"
+
+namespace QmlDesigner {
+
+FormEditorWidget::FormEditorWidget(FormEditorView *view)
+ : QWidget(),
+ m_formEditorView(view)
+{
+ QFile file(":/qmldesigner/stylesheet.css");
+ file.open(QFile::ReadOnly);
+ QString styleSheet = QLatin1String(file.readAll());
+ setStyleSheet(styleSheet);
+
+ QVBoxLayout *fillLayout = new QVBoxLayout(this);
+ fillLayout->setMargin(0);
+ fillLayout->setSpacing(0);
+ setLayout(fillLayout);
+
+ m_toolActionGroup = new QActionGroup(this);
+
+ m_transformToolAction = m_toolActionGroup->addAction("Transform Tool (Press Key Q)");
+ m_transformToolAction->setShortcut(Qt::Key_Q);
+ m_transformToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+ m_transformToolAction->setCheckable(true);
+ m_transformToolAction->setChecked(true);
+ m_transformToolAction->setIcon(QPixmap(":/icon/tool/transform.png"));
+ connect(m_transformToolAction.data(), SIGNAL(triggered(bool)), SLOT(changeTransformTool(bool)));
+
+ m_anchorToolAction = m_toolActionGroup->addAction("Anchor Tool (Press Key W)");
+ m_anchorToolAction->setShortcut(Qt::Key_W);
+ m_anchorToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+ m_anchorToolAction->setCheckable(true);
+ m_anchorToolAction->setIcon(QPixmap(":/icon/tool/anchor.png"));
+ connect(m_anchorToolAction.data(), SIGNAL(triggered(bool)), SLOT(changeAnchorTool(bool)));
+
+ addActions(m_toolActionGroup->actions());
+
+ QActionGroup *layoutActionGroup = new QActionGroup(this);
+ layoutActionGroup->setExclusive(false);
+
+ m_snappingToolAction = layoutActionGroup->addAction("Toogle Snapping (Press Key E)");
+ m_snappingToolAction->setShortcut(Qt::Key_E);
+ m_snappingToolAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
+ m_snappingToolAction->setCheckable(true);
+ m_snappingToolAction->setChecked(true);
+ m_snappingToolAction->setIcon(QPixmap(":/icon/layout/snapping.png"));
+ connect(m_snappingToolAction.data(), SIGNAL(triggered(bool)), SLOT(changeSnappingTool(bool)));
+
+ m_snappingMarginAction = new NumberSeriesAction(layoutActionGroup);
+ m_snappingMarginAction->addEntry("no margins (0)", 0);
+ m_snappingMarginAction->addEntry("small margin (2)", 2);
+ m_snappingMarginAction->addEntry("medium margin (6)", 6);
+ m_snappingMarginAction->addEntry("all in margin (10)", 10);
+ m_snappingMarginAction->setCurrentEntryIndex(3);
+ layoutActionGroup->addAction(m_snappingMarginAction.data());
+ addActions(layoutActionGroup->actions());
+
+ m_snappingSpacingAction = new NumberSeriesAction(layoutActionGroup);
+ m_snappingSpacingAction->addEntry("no spacing (0)", 0);
+ m_snappingSpacingAction->addEntry("small spacing (2)", 2);
+ m_snappingSpacingAction->addEntry("medium spacing (4)", 4);
+ m_snappingSpacingAction->addEntry("all in spacing (6)", 6);
+ m_snappingSpacingAction->setCurrentEntryIndex(1);
+ layoutActionGroup->addAction(m_snappingSpacingAction.data());
+
+ addActions(layoutActionGroup->actions());
+
+ m_zoomAction = new ZoomAction(toolActionGroup());
+ connect(m_zoomAction.data(), SIGNAL(zoomLevelChanged(double)), SLOT(setZoomLevel(double)));
+ addAction(m_zoomAction.data());
+
+ QAction *separatorAction = new QAction(toolActionGroup());
+ separatorAction->setSeparator(true);
+ addAction(separatorAction);
+
+ m_toolBox = new ToolBox(this);
+ toolBox()->setActions(actions());
+ fillLayout->addWidget(toolBox());
+
+ m_graphicsView = new FormEditorGraphicsView(this);
+ fillLayout->addWidget(m_graphicsView.data());
+}
+
+void FormEditorWidget::enterEvent(QEvent *event)
+{
+ setFocus();
+ QWidget::enterEvent(event);
+}
+
+void FormEditorWidget::changeTransformTool(bool checked)
+{
+ if (checked)
+ m_formEditorView->changeToTransformTools();
+}
+
+void FormEditorWidget::changeAnchorTool(bool checked)
+{
+ if (checked && m_formEditorView->currentState().isBaseState())
+ m_formEditorView->changeToAnchorTool();
+}
+
+void FormEditorWidget::changeSnappingTool(bool /*checked*/)
+{
+ // TODO
+}
+
+void FormEditorWidget::wheelEvent(QWheelEvent *event)
+{
+ if (event->modifiers().testFlag(Qt::ControlModifier)) {
+ if (event->delta() > 0) {
+ zoomAction()->zoomIn();
+ } else {
+ zoomAction()->zoomOut();
+ }
+
+ event->accept();
+ } else {
+ QWidget::wheelEvent(event);
+ }
+
+}
+
+ZoomAction *FormEditorWidget::zoomAction() const
+{
+ return m_zoomAction.data();
+}
+
+QAction *FormEditorWidget::anchorToolAction() const
+{
+ return m_anchorToolAction.data();
+}
+
+QAction *FormEditorWidget::transformToolAction() const
+{
+ return m_transformToolAction.data();
+}
+
+void FormEditorWidget::setZoomLevel(double zoomLevel)
+{
+ m_graphicsView->resetTransform();
+
+ m_graphicsView->scale(zoomLevel, zoomLevel);
+}
+
+void FormEditorWidget::setScene(FormEditorScene *scene)
+{
+ m_graphicsView->setScene(scene);
+}
+
+QActionGroup *FormEditorWidget::toolActionGroup() const
+{
+ return m_toolActionGroup.data();
+}
+
+ToolBox *FormEditorWidget::toolBox() const
+{
+ return m_toolBox.data();
+}
+
+bool FormEditorWidget::isSnapButtonChecked() const
+{
+ return m_snappingToolAction->isChecked();
+}
+
+double FormEditorWidget::spacing() const
+{
+ return m_snappingSpacingAction->currentValue().toDouble();
+}
+
+double FormEditorWidget::margins() const
+{
+ return m_snappingMarginAction->currentValue().toDouble();
+}
+
+}
+
+
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h
new file mode 100644
index 0000000000..2a718507f8
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef FORMEDITORWIDGET_H
+#define FORMEDITORWIDGET_H
+
+#include <QWidget>
+
+class QActionGroup;
+
+namespace QmlDesigner {
+
+class ZoomAction;
+class FormEditorView;
+class FormEditorScene;
+class FormEditorGraphicsView;
+class ToolBox;
+class NumberSeriesAction;
+
+class FormEditorWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ FormEditorWidget(FormEditorView *view);
+ bool isSnapButtonChecked() const;
+
+ ZoomAction *zoomAction() const;
+ QAction *anchorToolAction() const;
+ QAction *transformToolAction() const;
+
+ void setScene(FormEditorScene *scene);
+ ToolBox *toolBox() const;
+
+ double spacing() const;
+ double margins() const;
+
+
+protected:
+ void enterEvent(QEvent *event);
+ void wheelEvent(QWheelEvent *event);
+ QActionGroup *toolActionGroup() const;
+
+private slots:
+ void changeTransformTool(bool checked);
+ void changeAnchorTool(bool checked);
+ void setZoomLevel(double zoomLevel);
+ void changeSnappingTool(bool checked);
+
+private:
+ QWeakPointer<FormEditorView> m_formEditorView;
+ QWeakPointer<FormEditorGraphicsView> m_graphicsView;
+ QWeakPointer<ZoomAction> m_zoomAction;
+ QWeakPointer<QAction> m_anchorToolAction;
+ QWeakPointer<QAction> m_transformToolAction;
+ QWeakPointer<QActionGroup> m_toolActionGroup;
+ QWeakPointer<ToolBox> m_toolBox;
+ QWeakPointer<QAction> m_snappingToolAction;
+ QWeakPointer<NumberSeriesAction> m_snappingMarginAction;
+ QWeakPointer<NumberSeriesAction> m_snappingSpacingAction;
+};
+
+
+}
+#endif //FORMEDITORWIDGET_H
+
diff --git a/src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp
new file mode 100644
index 0000000000..9376ed18dc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.cpp
@@ -0,0 +1,191 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "itemcreatortool.h"
+#include "formeditorscene.h"
+#include "formeditorview.h"
+
+#include <metainfo.h>
+#include <itemlibrary.h>
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QtDebug>
+#include <QClipboard>
+
+namespace QmlDesigner {
+
+ItemCreatorTool::ItemCreatorTool(FormEditorView *editorView)
+ : AbstractFormEditorTool(editorView),
+ m_rubberbandSelectionManipulator(editorView->scene()->manipulatorLayerItem(), editorView)
+
+{
+
+}
+
+
+ItemCreatorTool::~ItemCreatorTool()
+{
+}
+
+void ItemCreatorTool::mousePressEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ m_rubberbandSelectionManipulator.begin(event->scenePos());
+ else
+ view()->deActivateItemCreator();
+}
+
+void ItemCreatorTool::mouseMoveEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *event)
+{
+ view()->setCursor(Qt::CrossCursor);
+ if (m_rubberbandSelectionManipulator.isActive()) {
+ m_rubberbandSelectionManipulator.update(event->scenePos());
+ } else {
+
+ }
+}
+
+void ItemCreatorTool::hoverMoveEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+}
+
+void ItemCreatorTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton) {
+ if (m_rubberbandSelectionManipulator.isActive()) {
+ QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->scenePos();
+ if (mouseMovementVector.toPoint().manhattanLength() < QApplication::startDragDistance()) {
+ m_rubberbandSelectionManipulator.update(event->scenePos());
+ } else {
+ m_rubberbandSelectionManipulator.update(event->scenePos());
+ QRectF rect(m_rubberbandSelectionManipulator.beginPoint(), event->scenePos());
+ createAtItem(rect);
+ m_rubberbandSelectionManipulator.end();
+ view()->deActivateItemCreator();
+ }
+ }
+ } else {
+ view()->deActivateItemCreator();
+ }
+}
+
+void ItemCreatorTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+
+}
+
+void ItemCreatorTool::keyPressEvent(QKeyEvent *event)
+{
+ switch(event->key()) {
+ case Qt::Key_Escape:
+ view()->deActivateItemCreator();
+ break;
+ }
+}
+
+void ItemCreatorTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/)
+{
+
+}
+
+void ItemCreatorTool::itemsAboutToRemoved(const QList<FormEditorItem*> &/*itemList*/)
+{
+
+}
+
+void ItemCreatorTool::clear()
+{
+ m_rubberbandSelectionManipulator.clear();
+}
+
+void ItemCreatorTool::selectedItemsChanged(const QList<FormEditorItem*> &/*itemList*/)
+{
+}
+
+void ItemCreatorTool::formEditorItemsChanged(const QList<FormEditorItem*> &/*itemList*/)
+{
+}
+
+void ItemCreatorTool::setItemString(const QString &itemString)
+{
+ m_itemString = itemString;
+}
+
+FormEditorItem* ItemCreatorTool::calculateContainer(const QPointF &point)
+{
+ QList<QGraphicsItem *> list = scene()->items(point);
+ foreach (QGraphicsItem *item, list) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem && formEditorItem->isContainer())
+ return formEditorItem;
+ }
+ return 0;
+}
+
+void ItemCreatorTool::createAtItem(const QRectF &rect)
+{
+ QPointF pos = rect.topLeft();
+
+ QmlItemNode parentNode = view()->rootQmlItemNode();
+ FormEditorItem *parentItem = calculateContainer(pos);
+ if (parentItem) {
+ parentNode = parentItem->qmlItemNode();
+ pos = parentItem->mapFromScene(pos);
+ }
+
+ QStringList list = m_itemString.split("^");
+ if (list.count() != 2)
+ return;
+ if (list.first() == "item") {
+ RewriterTransaction transaction = view()->beginRewriterTransaction();
+ ItemLibraryInfo itemLibraryRepresentation = view()->model()->metaInfo().itemLibraryRepresentation(list.at(1));
+ QmlItemNode newNode = view()->createQmlItemNode(itemLibraryRepresentation, pos, parentNode);
+ newNode.modelNode().variantProperty("width") = rect.width();
+ newNode.modelNode().variantProperty("height") = rect.height();
+ QList<QmlItemNode> nodeList;
+ nodeList.append(newNode);
+ view()->setSelectedQmlItemNodes(nodeList);
+ } else if (list.first() == "image") {
+ RewriterTransaction transaction = view()->beginRewriterTransaction();
+ QmlItemNode newNode = view()->createQmlItemNodeFromImage(list.at(1), pos, parentNode);
+ newNode.modelNode().variantProperty("width") = rect.width();
+ newNode.modelNode().variantProperty("height") = rect.height();
+ QList<QmlItemNode> nodeList;
+ nodeList.append(newNode);
+ view()->setSelectedQmlItemNodes(nodeList);
+ }
+}
+
+} //QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/itemcreatortool.h b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.h
new file mode 100644
index 0000000000..c266103905
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/itemcreatortool.h
@@ -0,0 +1,82 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ITEMCREATORTOOL_H
+#define ITEMCREATORTOOL_H
+
+
+#include "abstractformeditortool.h"
+#include "rubberbandselectionmanipulator.h"
+
+#include <QHash>
+
+
+namespace QmlDesigner {
+
+
+class ItemCreatorTool : public AbstractFormEditorTool
+{
+public:
+ ItemCreatorTool(FormEditorView* editorView);
+ ~ItemCreatorTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList);
+
+ void clear();
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void setItemString(const QString &itemString);
+
+ FormEditorItem* calculateContainer(const QPointF &point);
+
+ void createAtItem(const QRectF &rect);
+
+private:
+ RubberBandSelectionManipulator m_rubberbandSelectionManipulator;
+ QString m_itemString;
+};
+
+}
+#endif // ITEMCREATORTOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp
new file mode 100644
index 0000000000..405b617e9d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.cpp
@@ -0,0 +1,78 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "itemutilfunctions.h"
+#include <modelutilities.h>
+#include <formeditorscene.h>
+
+#include <QRectF>
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+
+QRectF boundingRectForItemList(QList<FormEditorItem*> itemList)
+{
+ QRectF boundingRect;
+
+ foreach (FormEditorItem *item, itemList)
+ {
+ boundingRect = boundingRect.united(item->mapToScene(item->qmlItemNode().instanceBoundingRect()).boundingRect());
+ }
+
+ return boundingRect;
+}
+
+//ModelNode parentNodeSemanticallyChecked(const ModelNode &childNode, const ModelNode &parentNode)
+//{
+// if (ModelUtilities::canReparent(childNode, parentNode)) {
+// ModelNode newParentNode;
+// newParentNode = ModelUtilities::mapGraphicsViewToGraphicsScene(parentNode);
+// if (newParentNode == childNode.parentNode())
+// return ModelNode();
+// if (ModelUtilities::isQWidget(childNode))
+// return ModelUtilities::reparentAndProxymize(childNode, newParentNode);
+// else
+// return parentNode;
+// }
+//
+// return ModelNode();
+//}
+
+//FormEditorItem* mapGraphicsViewToGraphicsScene(FormEditorItem* item)
+//{
+// if (item == 0) //null pointer
+// return 0;
+// ModelNode newNode = ModelUtilities::mapGraphicsViewToGraphicsScene(item->modelNode());
+// return item->scene()->itemForNode(newNode);
+//}
+
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h
new file mode 100644
index 0000000000..95760f2cb8
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/itemutilfunctions.h
@@ -0,0 +1,48 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ITEMUTILFUNCTIONS_H
+#define ITEMUTILFUNCTIONS_H
+
+#include <QRectF>
+#include <QGraphicsItem>
+#include "formeditoritem.h"
+
+
+namespace QmlDesigner {
+
+QRectF boundingRectForItemList(QList<FormEditorItem*> itemList);
+
+ModelNode parentNodeSemanticallyChecked(const ModelNode &childNode, const ModelNode &parentNode);
+
+FormEditorItem* mapGraphicsViewToGraphicsScene(FormEditorItem* item);
+
+}
+
+#endif // ITEMUTILFUNCTIONS_H
diff --git a/src/plugins/qmldesigner/components/formeditor/layeritem.cpp b/src/plugins/qmldesigner/components/formeditor/layeritem.cpp
new file mode 100644
index 0000000000..5a94811531
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/layeritem.cpp
@@ -0,0 +1,73 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "layeritem.h"
+
+#include <formeditorscene.h>
+
+
+namespace QmlDesigner {
+
+LayerItem::LayerItem(FormEditorScene* scene)
+ : QGraphicsObject()
+{
+ scene->addItem(this);
+ setZValue(1);
+ setFlag(QGraphicsItem::ItemIsMovable, false);
+}
+
+LayerItem::~LayerItem()
+{
+}
+
+void LayerItem::paint(QPainter * /*painter*/, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
+{
+}
+
+QRectF LayerItem::boundingRect() const
+{
+ return childrenBoundingRect();
+}
+
+QList<QGraphicsItem*> LayerItem::findAllChildItems() const
+{
+ return findAllChildItems(this);
+}
+
+QList<QGraphicsItem*> LayerItem::findAllChildItems(const QGraphicsItem *item) const
+{
+ QList<QGraphicsItem*> itemList(item->childItems());
+
+ foreach (QGraphicsItem *childItem, item->childItems())
+ itemList += findAllChildItems(childItem);
+
+ return itemList;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/layeritem.h b/src/plugins/qmldesigner/components/formeditor/layeritem.h
new file mode 100644
index 0000000000..09881a065c
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/layeritem.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef LAYERITEM_H
+#define LAYERITEM_H
+
+#include <QGraphicsObject>
+#include <QWeakPointer>
+
+namespace QmlDesigner {
+
+class FormEditorScene;
+
+class LayerItem : public QGraphicsObject
+{
+public:
+ enum
+ {
+ Type = 0xEAAA
+ };
+ LayerItem(FormEditorScene* scene);
+ ~LayerItem();
+ void paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 );
+ QRectF boundingRect() const;
+ int type() const;
+
+ QList<QGraphicsItem*> findAllChildItems() const;
+
+protected:
+ QList<QGraphicsItem*> findAllChildItems(const QGraphicsItem *item) const;
+};
+
+inline int LayerItem::type() const
+{
+ return Type;
+}
+
+}
+
+#endif // LAYERITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h b/src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h
new file mode 100644
index 0000000000..215d1702fe
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/manipulatorlayeritem.h
@@ -0,0 +1,39 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MANIPULATORLAYERITEM_H
+#define MANIPULATORLAYERITEM_H
+
+class ManipulatorLayerItem
+{
+public:
+ ManipulatorLayerItem();
+};
+
+#endif // MANIPULATORLAYERITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp
new file mode 100644
index 0000000000..fe0ca9893a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp
@@ -0,0 +1,363 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "movemanipulator.h"
+#include "itemutilfunctions.h"
+#include "layeritem.h"
+#include "formeditoritem.h"
+#include "formeditorscene.h"
+
+#include <QPointF>
+#include <QtDebug>
+#include <QColor>
+#include <QPen>
+#include <QApplication>
+
+#include <limits>
+#include <model.h>
+#include <qmlanchors.h>
+
+
+namespace QmlDesigner {
+
+MoveManipulator::MoveManipulator(LayerItem *layerItem, FormEditorView *view)
+ : m_layerItem(layerItem),
+ m_view(view),
+ m_isActive(false)
+{
+}
+
+MoveManipulator::~MoveManipulator()
+{
+ deleteSnapLines();
+}
+
+QPointF MoveManipulator::beginPoint() const
+{
+ return m_beginPoint;
+}
+
+void MoveManipulator::setItem(FormEditorItem* item)
+{
+ QList<FormEditorItem*> itemList;
+ itemList.append(item);
+
+ setItems(itemList);
+}
+
+void MoveManipulator::setItems(const QList<FormEditorItem*> &itemList)
+{
+ m_itemList = itemList;
+ if (!m_itemList.isEmpty()) {
+ if (m_itemList.first()->parentItem())
+ m_snapper.setContainerFormEditorItem(m_itemList.first()->parentItem());
+ else
+ m_snapper.setContainerFormEditorItem(m_itemList.first());
+ m_snapper.setTransformtionSpaceFormEditorItem(m_snapper.containerFormEditorItem());
+ }
+}
+
+void MoveManipulator::updateHashes()
+{
+// foreach (FormEditorItem* item, m_itemList)
+// m_beginItemRectHash[item] = item->mapRectToParent(item->qmlItemNode().instanceBoundingRect());
+
+ foreach (FormEditorItem* item, m_itemList) {
+ QPointF positionInParentSpace = m_snapper.containerFormEditorItem()->mapFromScene(m_beginPositionInSceneSpaceHash.value(item));
+ m_beginItemRectHash[item].translate(positionInParentSpace - m_beginPositionHash.value(item));
+ m_beginPositionHash.insert(item, positionInParentSpace);
+ }
+}
+
+bool MoveManipulator::itemsCanReparented() const
+{
+ foreach (FormEditorItem* item, m_itemList) {
+ if (!item->qmlItemNode().canReparent())
+ return false;
+ }
+
+ return true;
+}
+
+void MoveManipulator::begin(const QPointF &beginPoint)
+{
+ m_isActive = true;
+
+ m_snapper.updateSnappingLines(m_itemList);
+
+
+ foreach (FormEditorItem* item, m_itemList)
+ m_beginItemRectHash.insert(item, m_snapper.containerFormEditorItem()->mapRectFromItem(item, item->qmlItemNode().instanceBoundingRect()));
+
+ foreach (FormEditorItem* item, m_itemList) {
+ QPointF positionInParentSpace(item->qmlItemNode().instancePosition());
+ QPointF positionInScenesSpace = m_snapper.containerFormEditorItem()->mapToScene(positionInParentSpace);
+ m_beginPositionInSceneSpaceHash.insert(item, positionInScenesSpace);
+ }
+
+ foreach (FormEditorItem* item, m_itemList) {
+ QPointF positionInParentSpace = m_snapper.containerFormEditorItem()->mapFromScene(m_beginPositionInSceneSpaceHash.value(item));
+ m_beginPositionHash.insert(item, positionInParentSpace);
+
+ QmlAnchors anchors(item->qmlItemNode().anchors());
+ m_beginTopMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Top));
+ m_beginLeftMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Left));
+ m_beginRightMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Right));
+ m_beginBottomMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Bottom));
+ m_beginHorizontalCenterHash.insert(item, anchors.instanceMargin(AnchorLine::HorizontalCenter));
+ m_beginVerticalCenterHash.insert(item, anchors.instanceMargin(AnchorLine::VerticalCenter));
+ }
+
+ m_beginPoint = beginPoint;
+
+// setOpacityForAllElements(0.62);
+
+ m_rewriterTransaction = m_view->beginRewriterTransaction();
+}
+
+
+
+
+
+QPointF MoveManipulator::findSnappingOffset(const QList<QRectF> &boundingRectList)
+{
+ QPointF offset;
+
+ QMap<double, double> verticalOffsetMap;
+ foreach (const QRectF &boundingRect, boundingRectList) {
+ double verticalOffset = m_snapper.snappedVerticalOffset(boundingRect);
+ if (verticalOffset < std::numeric_limits<double>::max())
+ verticalOffsetMap.insert(qAbs(verticalOffset), verticalOffset);
+ }
+
+
+ if (!verticalOffsetMap.isEmpty())
+ offset.rx() = verticalOffsetMap.begin().value();
+
+
+
+ QMap<double, double> horizontalOffsetMap;
+ foreach (const QRectF &boundingRect, boundingRectList) {
+ double horizontalOffset = m_snapper.snappedHorizontalOffset(boundingRect);
+ if (horizontalOffset < std::numeric_limits<double>::max())
+ horizontalOffsetMap.insert(qAbs(horizontalOffset), horizontalOffset);
+ }
+
+
+ if (!horizontalOffsetMap.isEmpty())
+ offset.ry() = horizontalOffsetMap.begin().value();
+
+ return offset;
+}
+
+
+void MoveManipulator::generateSnappingLines(const QList<QRectF> &boundingRectList)
+{
+ m_graphicsLineList = m_snapper.generateSnappingLines(boundingRectList,
+ m_layerItem.data(),
+ m_snapper.transformtionSpaceFormEditorItem()->sceneTransform());
+}
+
+
+
+QList<QRectF> MoveManipulator::tanslatedBoundingRects(const QList<QRectF> &boundingRectList, const QPointF& offsetVector)
+{
+ QList<QRectF> translatedBoundingRectList;
+ foreach (const QRectF &boundingRect, boundingRectList)
+ translatedBoundingRectList.append(boundingRect.translated(offsetVector));
+
+ return translatedBoundingRectList;
+}
+
+
+
+/*
+ /brief updates the position of the items.
+*/
+void MoveManipulator::update(const QPointF& updatePoint, Snapping useSnapping)
+{
+ deleteSnapLines(); //Since they position is changed and the item is moved the snapping lines are
+ //are obsolete. The new updated snapping lines (color and visibility) will be
+ //calculated in snapPoint() called in moveNode() later
+
+ if (m_itemList.isEmpty()) {
+ return;
+ } else {
+ QPointF updatePointInContainerSpace(m_snapper.containerFormEditorItem()->mapFromScene(updatePoint));
+ QPointF beginPointInContainerSpace(m_snapper.containerFormEditorItem()->mapFromScene(m_beginPoint));
+
+ QPointF offsetVector(updatePointInContainerSpace - beginPointInContainerSpace);
+ if (useSnapping == UseSnapping) {
+ offsetVector -= findSnappingOffset(tanslatedBoundingRects(m_beginItemRectHash.values(), offsetVector));
+ generateSnappingLines(tanslatedBoundingRects(m_beginItemRectHash.values(), offsetVector));
+ }
+
+ foreach (FormEditorItem* item, m_itemList) {
+ QPointF positionInContainerSpace(m_beginPositionHash.value(item) + offsetVector);
+ QmlAnchors anchors(item->qmlItemNode().anchors());
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top)) {
+ anchors.setMargin(AnchorLine::Top, m_beginTopMarginHash.value(item) + offsetVector.y());
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left)) {
+ anchors.setMargin(AnchorLine::Left, m_beginLeftMarginHash.value(item) + offsetVector.x());
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
+ anchors.setMargin(AnchorLine::Bottom, m_beginBottomMarginHash.value(item) - offsetVector.y());
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right)) {
+ anchors.setMargin(AnchorLine::Right, m_beginRightMarginHash.value(item) - offsetVector.x());
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ anchors.setMargin(AnchorLine::HorizontalCenter, m_beginHorizontalCenterHash.value(item) + offsetVector.x());
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ anchors.setMargin(AnchorLine::VerticalCenter, m_beginVerticalCenterHash.value(item) + offsetVector.y());
+ }
+
+ item->qmlItemNode().setPosition(positionInContainerSpace);
+ }
+
+
+ }
+}
+
+void MoveManipulator::clear()
+{
+ deleteSnapLines();
+ m_beginItemRectHash.clear();
+ m_beginPositionHash.clear();
+ m_beginPositionInSceneSpaceHash.clear();
+ m_itemList.clear();
+
+ m_rewriterTransaction.commit();
+
+ m_beginTopMarginHash.clear();
+ m_beginLeftMarginHash.clear();
+ m_beginRightMarginHash.clear();
+ m_beginBottomMarginHash.clear();
+ m_beginHorizontalCenterHash.clear();
+ m_beginVerticalCenterHash.clear();
+}
+
+void MoveManipulator::reparentTo(FormEditorItem *newParent)
+{
+ deleteSnapLines();
+
+ if (!newParent)
+ return;
+
+ if (!itemsCanReparented())
+ return;
+
+ foreach (FormEditorItem* item, m_itemList) {
+ QmlItemNode parent(newParent->qmlItemNode());
+ if (parent.isValid()) {
+ item->qmlItemNode().setParentProperty(parent.nodeAbstractProperty("data"));
+ }
+ }
+
+ if (m_view->model()) {
+ m_snapper.setContainerFormEditorItem(newParent);
+ m_snapper.setTransformtionSpaceFormEditorItem(m_snapper.containerFormEditorItem());
+ m_snapper.updateSnappingLines(m_itemList);
+ updateHashes();
+ }
+}
+
+
+void MoveManipulator::end(const QPointF &/*endPoint*/)
+{
+ m_isActive = false;
+ deleteSnapLines();
+// setOpacityForAllElements(1.0);
+ clear();
+}
+
+void MoveManipulator::moveBy(double deltaX, double deltaY)
+{
+ foreach (FormEditorItem* item, m_itemList) {
+ QmlAnchors anchors(item->qmlItemNode().anchors());
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top)) {
+ anchors.setMargin(AnchorLine::Top, anchors.instanceMargin(AnchorLine::Top) - deltaY);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left)) {
+ anchors.setMargin(AnchorLine::Left, anchors.instanceMargin(AnchorLine::Left) + deltaX);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
+ anchors.setMargin(AnchorLine::Bottom, anchors.instanceMargin(AnchorLine::Bottom) + deltaY);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right)) {
+ anchors.setMargin(AnchorLine::Right, anchors.instanceMargin(AnchorLine::Right) - deltaX);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ anchors.setMargin(AnchorLine::HorizontalCenter, anchors.instanceMargin(AnchorLine::HorizontalCenter) + deltaX);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ anchors.setMargin(AnchorLine::VerticalCenter, anchors.instanceMargin(AnchorLine::VerticalCenter) + deltaY);
+ }
+
+ item->qmlItemNode().setPosition(QPointF(item->qmlItemNode().instanceValue("x").toDouble() + deltaX,
+ item->qmlItemNode().instanceValue("y").toDouble() + deltaY));
+ }
+}
+
+void MoveManipulator::setOpacityForAllElements(qreal opacity)
+{
+ foreach (FormEditorItem* item, m_itemList)
+ item->setOpacity(opacity);
+}
+
+void MoveManipulator::deleteSnapLines()
+{
+ if (m_layerItem) {
+ foreach (QGraphicsItem *item, m_graphicsLineList)
+ m_layerItem->scene()->removeItem(item);
+ }
+ m_graphicsLineList.clear();
+ m_view->scene()->update();
+}
+
+bool MoveManipulator::isActive() const
+{
+ return m_isActive;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.h b/src/plugins/qmldesigner/components/formeditor/movemanipulator.h
new file mode 100644
index 0000000000..3501625b4d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.h
@@ -0,0 +1,114 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MOVEMANIPULATOR_H
+#define MOVEMANIPULATOR_H
+
+#include <QWeakPointer>
+#include <QGraphicsItem>
+#include <QGraphicsLineItem>
+#include <QHash>
+#include <QPointF>
+#include <QRectF>
+
+#include "controlelement.h"
+#include "formeditoritem.h"
+#include "rewritertransaction.h"
+#include "snapper.h"
+#include "formeditorview.h"
+
+namespace QmlDesigner {
+
+class ModelNodeChangeSet;
+class Model;
+
+class MoveManipulator
+{
+public:
+ enum Snapping {
+ UseSnapping,
+ NoSnapping
+ };
+
+ MoveManipulator(LayerItem *layerItem, FormEditorView *view);
+ ~MoveManipulator();
+ void setItems(const QList<FormEditorItem*> &itemList);
+ void setItem(FormEditorItem* item);
+
+ void begin(const QPointF& beginPoint);
+ void update(const QPointF& updatePoint, Snapping useSnapping);
+ void reparentTo(FormEditorItem *newParent);
+ void end(const QPointF& endPoint);
+
+ void moveBy(double deltaX, double deltaY);
+
+ QPointF beginPoint() const;
+
+ void clear();
+
+ bool isActive() const;
+
+protected:
+ void setOpacityForAllElements(qreal opacity);
+
+ QPointF findSnappingOffset(const QList<QRectF> &boundingRectList);
+
+ void deleteSnapLines();
+
+ QList<QRectF> tanslatedBoundingRects(const QList<QRectF> &boundingRectList, const QPointF& offset);
+ QPointF calculateBoundingRectMovementOffset(const QPointF& updatePoint);
+ QRectF boundingRect(FormEditorItem* item, const QPointF& updatePoint);
+
+ void generateSnappingLines(const QList<QRectF> &boundingRectList);
+ void updateHashes();
+
+ bool itemsCanReparented() const;
+
+private:
+ Snapper m_snapper;
+ QWeakPointer<LayerItem> m_layerItem;
+ QWeakPointer<FormEditorView> m_view;
+ QList<FormEditorItem*> m_itemList;
+ QHash<FormEditorItem*, QRectF> m_beginItemRectHash;
+ QHash<FormEditorItem*, QPointF> m_beginPositionHash;
+ QHash<FormEditorItem*, QPointF> m_beginPositionInSceneSpaceHash;
+ QPointF m_beginPoint;
+ QHash<FormEditorItem*, double> m_beginTopMarginHash;
+ QHash<FormEditorItem*, double> m_beginLeftMarginHash;
+ QHash<FormEditorItem*, double> m_beginRightMarginHash;
+ QHash<FormEditorItem*, double> m_beginBottomMarginHash;
+ QHash<FormEditorItem*, double> m_beginHorizontalCenterHash;
+ QHash<FormEditorItem*, double> m_beginVerticalCenterHash;
+ QList<QGraphicsItem*> m_graphicsLineList;
+ bool m_isActive;
+ RewriterTransaction m_rewriterTransaction;
+};
+
+}
+#endif // MOVEMANIPULATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.cpp b/src/plugins/qmldesigner/components/formeditor/movetool.cpp
new file mode 100644
index 0000000000..09f5ec73c1
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/movetool.cpp
@@ -0,0 +1,345 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "movetool.h"
+
+#include "formeditorscene.h"
+#include "formeditorview.h"
+#include "modelutilities.h"
+#include "itemutilfunctions.h"
+
+#include "resizehandleitem.h"
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+MoveTool::MoveTool(FormEditorView *editorView)
+ : AbstractFormEditorTool(editorView),
+ m_moveManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
+ m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
+ m_resizeIndicator(editorView->scene()->manipulatorLayerItem())
+{
+// view()->setCursor(Qt::SizeAllCursor);
+}
+
+
+MoveTool::~MoveTool()
+{
+
+}
+
+void MoveTool::clear()
+{
+ m_moveManipulator.clear();
+ m_movingItems.clear();
+ m_selectionIndicator.clear();
+ m_resizeIndicator.clear();
+}
+
+void MoveTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (itemList.isEmpty())
+ return;
+ m_movingItems = movingItems(items());
+ if (m_movingItems.isEmpty())
+ return;
+
+ m_moveManipulator.setItems(m_movingItems);
+ m_moveManipulator.begin(event->scenePos());
+}
+
+void MoveTool::mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_movingItems.isEmpty())
+ return;
+
+// m_selectionIndicator.hide();
+ m_resizeIndicator.hide();
+
+ FormEditorItem *containerItem = containerFormEditorItem(itemList, m_movingItems);
+ if (containerItem &&
+ containerItem != m_movingItems.first()->parentItem() &&
+ view()->currentState().isBaseState() &&
+ !event->modifiers().testFlag(Qt::ShiftModifier)) {
+
+ m_moveManipulator.reparentTo(containerItem);
+ }
+
+ MoveManipulator::Snapping useSnapping = MoveManipulator::NoSnapping;
+ if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked())
+ useSnapping = MoveManipulator::UseSnapping;
+
+ m_moveManipulator.update(event->scenePos(), useSnapping);
+}
+
+void MoveTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+ if (itemList.isEmpty()) {
+ view()->changeToSelectionTool();
+ return;
+ }
+
+ ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first());
+ if (resizeHandle) {
+ view()->changeToResizeTool();
+ return;
+ }
+
+ if (!topSelectedItemIsMovable(itemList)) {
+ view()->changeToSelectionTool();
+ return;
+ }
+}
+
+void MoveTool::keyPressEvent(QKeyEvent *event)
+{
+ switch(event->key()) {
+ case Qt::Key_Shift:
+ case Qt::Key_Alt:
+ case Qt::Key_Control:
+ case Qt::Key_AltGr:
+ event->setAccepted(false);
+ return;
+ }
+
+ double moveStep = 1.0;
+
+ if (event->modifiers().testFlag(Qt::ShiftModifier))
+ moveStep = 10.0;
+
+ if (!event->isAutoRepeat()) {
+ QList<FormEditorItem*> movableItems(movingItems(items()));
+ if (movableItems.isEmpty())
+ return;
+
+ m_moveManipulator.setItems(movableItems);
+// m_selectionIndicator.hide();
+ m_resizeIndicator.hide();
+ }
+
+ switch(event->key()) {
+ case Qt::Key_Left: m_moveManipulator.moveBy(-moveStep, 0.0); break;
+ case Qt::Key_Right: m_moveManipulator.moveBy(moveStep, 0.0); break;
+ case Qt::Key_Up: m_moveManipulator.moveBy(0.0, -moveStep); break;
+ case Qt::Key_Down: m_moveManipulator.moveBy(0.0, moveStep); break;
+ }
+
+
+}
+
+void MoveTool::keyReleaseEvent(QKeyEvent *keyEvent)
+{
+ switch(keyEvent->key()) {
+ case Qt::Key_Shift:
+ case Qt::Key_Alt:
+ case Qt::Key_Control:
+ case Qt::Key_AltGr:
+ keyEvent->setAccepted(false);
+ return;
+ }
+
+ if (!keyEvent->isAutoRepeat()) {
+ m_moveManipulator.clear();
+// m_selectionIndicator.show();
+ m_resizeIndicator.show();
+ }
+}
+
+void MoveTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_movingItems.isEmpty())
+ return;
+
+ QLineF moveVector(event->scenePos(), m_moveManipulator.beginPoint());
+ if (moveVector.length() < QApplication::startDragDistance())
+ {
+ QPointF beginPoint(m_moveManipulator.beginPoint());
+
+ m_moveManipulator.end(beginPoint);
+
+// m_selectionIndicator.show();
+ m_resizeIndicator.show();
+ m_movingItems.clear();
+
+ view()->changeToSelectionTool(event);
+ } else {
+ m_moveManipulator.end(event->scenePos());
+
+ m_selectionIndicator.show();
+ m_resizeIndicator.show();
+ m_movingItems.clear();
+ }
+}
+
+void MoveTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+
+}
+
+void MoveTool::itemsAboutToRemoved(const QList<FormEditorItem*> &removedItemList)
+{
+ foreach (FormEditorItem* removedItem, removedItemList)
+ m_movingItems.removeOne(removedItem);
+}
+
+void MoveTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
+{
+ m_selectionIndicator.setItems(movingItems(itemList));
+ m_resizeIndicator.setItems(itemList);
+ updateMoveManipulator();
+}
+
+bool MoveTool::haveSameParent(const QList<FormEditorItem*> &itemList)
+{
+ if (itemList.isEmpty())
+ return false;
+
+ QGraphicsItem *firstParent = itemList.first()->parentItem();
+ foreach (FormEditorItem* item, itemList)
+ {
+ if (firstParent != item->parentItem())
+ return false;
+ }
+
+ return true;
+}
+
+bool MoveTool::isAncestorOfAllItems(FormEditorItem* maybeAncestorItem,
+ const QList<FormEditorItem*> &itemList)
+{
+ foreach (FormEditorItem* item, itemList)
+ {
+ if (!maybeAncestorItem->isAncestorOf(item) && item != maybeAncestorItem)
+ return false;
+ }
+
+ return true;
+}
+
+
+FormEditorItem* MoveTool::ancestorIfOtherItemsAreChild(const QList<FormEditorItem*> &itemList)
+{
+ if (itemList.isEmpty())
+ return 0;
+
+
+ foreach (FormEditorItem* item, itemList)
+ {
+ if (isAncestorOfAllItems(item, itemList))
+ return item;
+ }
+
+ return 0;
+}
+
+void MoveTool::updateMoveManipulator()
+{
+ if (m_moveManipulator.isActive())
+ return;
+}
+
+void MoveTool::beginWithPoint(const QPointF &beginPoint)
+{
+ m_movingItems = movingItems(items());
+ if (m_movingItems.isEmpty())
+ return;
+
+ m_moveManipulator.setItems(m_movingItems);
+ m_moveManipulator.begin(beginPoint);
+}
+
+static bool isNotAncestorOfItemInList(FormEditorItem *formEditorItem, const QList<FormEditorItem*> &itemList)
+{
+ foreach (FormEditorItem *item, itemList) {
+ if (item->qmlItemNode().isAncestorOf(formEditorItem->qmlItemNode()))
+ return false;
+ }
+
+ return true;
+}
+
+FormEditorItem* MoveTool::containerFormEditorItem(const QList<QGraphicsItem*> &itemUnderMouseList,
+ const QList<FormEditorItem*> &selectedItemList)
+{
+ Q_ASSERT(!selectedItemList.isEmpty());
+
+ foreach (QGraphicsItem* item, itemUnderMouseList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+ if (formEditorItem
+ && !selectedItemList.contains(formEditorItem)
+ && isNotAncestorOfItemInList(formEditorItem, selectedItemList))
+ if (formEditorItem->isContainer()) {
+ return formEditorItem;
+ }
+
+ }
+
+ return 0;
+}
+
+
+QList<FormEditorItem*> MoveTool::movingItems(const QList<FormEditorItem*> &selectedItemList)
+{
+ FormEditorItem* ancestorItem = ancestorIfOtherItemsAreChild(selectedItemList);
+
+ if (ancestorItem != 0 && ancestorItem->qmlItemNode().isRootNode()) {
+// view()->changeToSelectionTool();
+ return QList<FormEditorItem*>();
+ }
+
+
+ if (ancestorItem != 0 && ancestorItem->parentItem() != 0) {
+ QList<FormEditorItem*> ancestorItemList;
+ ancestorItemList.append(ancestorItem);
+ return ancestorItemList;
+ }
+
+ if (!haveSameParent(selectedItemList)) {
+// view()->changeToSelectionTool();
+ return QList<FormEditorItem*>();
+ }
+
+ return selectedItemList;
+}
+
+void MoveTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList)
+{
+ m_selectionIndicator.updateItems(itemList);
+ m_resizeIndicator.updateItems(itemList);
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/movetool.h b/src/plugins/qmldesigner/components/formeditor/movetool.h
new file mode 100644
index 0000000000..df3c65b791
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/movetool.h
@@ -0,0 +1,97 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef MOVETOOL_H
+#define MOVETOOL_H
+
+#include "abstractformeditortool.h"
+#include "movemanipulator.h"
+#include "selectionindicator.h"
+#include "resizeindicator.h"
+
+#include <QHash>
+
+
+namespace QmlDesigner {
+
+
+class MoveTool : public AbstractFormEditorTool
+{
+public:
+ MoveTool(FormEditorView* editorView);
+ ~MoveTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList);
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void updateMoveManipulator();
+
+
+
+ void beginWithPoint(const QPointF &beginPoint);
+
+ void clear();
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList);
+
+protected:
+ static bool haveSameParent(const QList<FormEditorItem*> &itemList);
+
+ static QList<FormEditorItem*> movingItems(const QList<FormEditorItem*> &selectedItemList);
+
+ static FormEditorItem* containerFormEditorItem(const QList<QGraphicsItem*> &itemUnderMouseList,
+ const QList<FormEditorItem*> &selectedItemList);
+
+ static bool isAncestorOfAllItems(FormEditorItem* maybeAncestorItem,
+ const QList<FormEditorItem*> &itemList);
+ static FormEditorItem* ancestorIfOtherItemsAreChild(const QList<FormEditorItem*> &itemList);
+
+private:
+ MoveManipulator m_moveManipulator;
+ SelectionIndicator m_selectionIndicator;
+ ResizeIndicator m_resizeIndicator;
+ QList<FormEditorItem*> m_movingItems;
+};
+
+}
+#endif // MOVETOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp
new file mode 100644
index 0000000000..ba6354f01d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.cpp
@@ -0,0 +1,88 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "numberseriesaction.h"
+#include <QStandardItemModel>
+#include <QComboBox>
+#include <QtDebug>
+
+
+namespace QmlDesigner {
+
+NumberSeriesAction::NumberSeriesAction(QObject *parent) :
+ QWidgetAction(parent),
+ m_comboBoxModelIndex(-1)
+{
+}
+
+void NumberSeriesAction::addEntry(const QString &text, const QVariant &value)
+{
+ if (m_comboBoxModel.isNull())
+ m_comboBoxModel = new QStandardItemModel(this);
+
+ QStandardItem *newItem = new QStandardItem(text);
+ newItem->setData(value);
+ m_comboBoxModel->appendRow(newItem);
+}
+
+QVariant NumberSeriesAction::currentValue() const
+{
+ return m_comboBoxModel->item(m_comboBoxModelIndex)->data();
+}
+
+QWidget *NumberSeriesAction::createWidget(QWidget *parent)
+{
+ QComboBox *comboBox = new QComboBox(parent);
+
+ comboBox->setModel(m_comboBoxModel.data());
+
+ comboBox->setCurrentIndex(m_comboBoxModelIndex);
+ connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(emitValueChanged(int)));
+
+ return comboBox;
+}
+
+void NumberSeriesAction::emitValueChanged(int index)
+{
+ if (index == -1)
+ return;
+
+ m_comboBoxModelIndex = index;
+
+ emit valueChanged(m_comboBoxModel.data()->item(index)->data());
+}
+
+void NumberSeriesAction::setCurrentEntryIndex(int index)
+{
+ Q_ASSERT(index < m_comboBoxModel->rowCount());
+
+ m_comboBoxModelIndex = index;
+}
+
+} // namespace QKinecticDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/numberseriesaction.h b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.h
new file mode 100644
index 0000000000..e6a8c82f16
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/numberseriesaction.h
@@ -0,0 +1,66 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef NUMBERSERIESACTION_H
+#define NUMBERSERIESACTION_H
+
+#include <QWidgetAction>
+
+class QStandardItemModel;
+
+namespace QmlDesigner {
+
+class NumberSeriesAction : public QWidgetAction
+{
+Q_OBJECT
+public:
+ explicit NumberSeriesAction(QObject *parent = 0);
+
+ void addEntry(const QString &text, const QVariant &value);
+ void setCurrentEntryIndex(int index);
+
+ QVariant currentValue() const;
+
+protected:
+ QWidget *createWidget(QWidget *parent);
+
+signals:
+ void valueChanged(const QVariant &value);
+
+private slots:
+ void emitValueChanged(int index);
+
+private:
+ QWeakPointer<QStandardItemModel> m_comboBoxModel;
+ int m_comboBoxModelIndex;
+};
+
+} // namespace QKinecticDesigner
+
+#endif // NUMBERSERIESACTION_H
diff --git a/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp
new file mode 100644
index 0000000000..e77afe8a14
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.cpp
@@ -0,0 +1,146 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "onedimensionalcluster.h"
+
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+double sum(const QList<double> & list)
+{
+ double sum = 0.0;
+ for(QList<double>::const_iterator iterator = list.constBegin(); iterator != list.constEnd(); ++iterator)
+ {
+ sum += *iterator;
+ }
+
+ return sum;
+}
+
+OneDimensionalCluster::OneDimensionalCluster(const QList<double> & coordinateList )
+ : m_coordinateList(coordinateList)
+{
+}
+
+double OneDimensionalCluster::mean() const
+{
+ Q_ASSERT(!m_coordinateList.isEmpty());
+
+ if (m_coordinateList.size() == 1)
+ {
+ return m_coordinateList.first();
+ }
+
+ return sum(m_coordinateList) / m_coordinateList.size();
+}
+
+double OneDimensionalCluster::first() const
+{
+ Q_ASSERT(!m_coordinateList.isEmpty());
+
+ return m_coordinateList.first();
+}
+
+QList<OneDimensionalCluster> OneDimensionalCluster::createOneDimensionalClusterList(const QList<double> & oneDimensionalCoordinateList)
+{
+ QList<OneDimensionalCluster> oneDimensionalClusterList;
+ foreach (double coordinate, oneDimensionalCoordinateList)
+ {
+ QList<double> initialList;
+ initialList.append(coordinate);
+ OneDimensionalCluster cluster(initialList);
+ oneDimensionalClusterList.append(initialList);
+ }
+
+ return oneDimensionalClusterList;
+}
+
+QList<OneDimensionalCluster> OneDimensionalCluster::reduceOneDimensionalClusterList(const QList<OneDimensionalCluster> & unreducedClusterList, double maximumDistance)
+{
+ if (unreducedClusterList.size() < 2)
+ return unreducedClusterList;
+
+
+ QList<OneDimensionalCluster> workingList(unreducedClusterList);
+ QList<OneDimensionalCluster> reducedList;
+ while (true)
+ {
+ qSort(workingList);
+ reducedList.clear();
+ bool clusterMerged = false;
+ QListIterator<OneDimensionalCluster> clusterIterator(workingList);
+ while (clusterIterator.hasNext())
+ {
+ OneDimensionalCluster currentCluster = clusterIterator.next();
+ if (clusterIterator.hasNext())
+ {
+ OneDimensionalCluster nextCluster = clusterIterator.peekNext();
+ if ((nextCluster.mean() - currentCluster.mean()) < maximumDistance)
+ {
+ reducedList.append(currentCluster + nextCluster);
+ clusterIterator.next();
+ clusterMerged = true;
+ }
+ else
+ {
+ reducedList.append(currentCluster);
+ }
+ }
+ else
+ {
+ reducedList.append(currentCluster);
+ break;
+ }
+
+ }
+
+ workingList = reducedList;
+
+ if (clusterMerged == false)
+ break;
+ }
+
+
+ return reducedList;
+}
+
+QList<double> OneDimensionalCluster::reduceLines(const QList<double> & oneDimensionalCoordinateList, double maximumDistance)
+{
+ QList<OneDimensionalCluster> clusterList(createOneDimensionalClusterList(oneDimensionalCoordinateList));
+ clusterList = reduceOneDimensionalClusterList(clusterList, maximumDistance);
+
+ QList<double> lineList;
+ foreach (const OneDimensionalCluster &cluster, clusterList)
+ lineList.append(cluster.first());
+
+ return lineList;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h
new file mode 100644
index 0000000000..dcf179eb18
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/onedimensionalcluster.h
@@ -0,0 +1,70 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ONEDIMENSIONALCLUSTER_H
+#define ONEDIMENSIONALCLUSTER_H
+
+#include <QList>
+
+namespace QmlDesigner {
+
+class OneDimensionalCluster
+{
+ friend inline OneDimensionalCluster operator+(const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster);
+ friend inline bool operator < (const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster);
+public:
+ static QList<double> reduceLines(const QList<double> & oneDimensionalCoordinateList, double maximumDistance);
+
+private:
+
+ OneDimensionalCluster(const QList<double> & coordinateList );
+ double mean() const;
+ double first() const;
+
+
+
+ static QList<OneDimensionalCluster> createOneDimensionalClusterList(const QList<double> & oneDimensionalCoordinateList);
+ static QList<OneDimensionalCluster> reduceOneDimensionalClusterList(const QList<OneDimensionalCluster> & unreducedClusterList, double maximumDistance);
+
+ QList<double> m_coordinateList;
+};
+
+inline bool operator < (const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster)
+{
+ return firstCluster.mean() < secondCluster.mean();
+}
+
+inline OneDimensionalCluster operator+(const OneDimensionalCluster & firstCluster, const OneDimensionalCluster & secondCluster)
+{
+
+ return OneDimensionalCluster(firstCluster.m_coordinateList + secondCluster.m_coordinateList);
+}
+
+}
+#endif // ONEDIMENSIONALCLUSTER_H
diff --git a/src/plugins/qmldesigner/components/formeditor/resize_handle.png b/src/plugins/qmldesigner/components/formeditor/resize_handle.png
new file mode 100644
index 0000000000..2934f25b74
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resize_handle.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp b/src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp
new file mode 100644
index 0000000000..9929df14ee
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizecontroller.cpp
@@ -0,0 +1,273 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "resizecontroller.h"
+
+#include "formeditoritem.h"
+#include "layeritem.h"
+
+#include <resizehandleitem.h>
+#include <QCursor>
+#include <QGraphicsScene>
+
+namespace QmlDesigner {
+
+
+
+ResizeControllerData::ResizeControllerData(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : layerItem(layerItem),
+ formEditorItem(formEditorItem),
+ topLeftItem(0),
+ topRightItem(0),
+ bottomLeftItem(0),
+ bottomRightItem(0),
+ topItem(0),
+ leftItem(0),
+ rightItem(0),
+ bottomItem(0)
+{
+
+}
+
+ResizeControllerData::ResizeControllerData(const ResizeControllerData &other)
+ : layerItem(other.layerItem),
+ formEditorItem(other.formEditorItem),
+ topLeftItem(other.topLeftItem),
+ topRightItem(other.topRightItem),
+ bottomLeftItem(other.bottomLeftItem),
+ bottomRightItem(other.bottomRightItem),
+ topItem(other.topItem),
+ leftItem(other.leftItem),
+ rightItem(other.rightItem),
+ bottomItem(other.bottomItem)
+{}
+
+ResizeControllerData::~ResizeControllerData()
+{
+ if (layerItem) {
+ layerItem->scene()->removeItem(topLeftItem);
+ layerItem->scene()->removeItem(topRightItem);
+ layerItem->scene()->removeItem(bottomLeftItem);
+ layerItem->scene()->removeItem(bottomRightItem);
+ layerItem->scene()->removeItem(topItem);
+ layerItem->scene()->removeItem(leftItem);
+ layerItem->scene()->removeItem(rightItem);
+ layerItem->scene()->removeItem(bottomItem);
+ }
+}
+
+
+ResizeController::ResizeController()
+ : m_data(new ResizeControllerData(0, 0))
+{
+
+}
+
+ResizeController::ResizeController(const QSharedPointer<ResizeControllerData> &data)
+ : m_data(data)
+{
+
+}
+
+ResizeController::ResizeController(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : m_data(new ResizeControllerData(layerItem, formEditorItem))
+{
+ m_data->topLeftItem = new ResizeHandleItem(layerItem, *this);
+ m_data->topLeftItem->setZValue(302);
+ m_data->topLeftItem->setCursor(Qt::SizeFDiagCursor);
+
+ m_data->topRightItem = new ResizeHandleItem(layerItem, *this);
+ m_data->topRightItem->setZValue(301);
+ m_data->topRightItem->setCursor(Qt::SizeBDiagCursor);
+
+ m_data->bottomLeftItem = new ResizeHandleItem(layerItem, *this);
+ m_data->bottomLeftItem->setZValue(301);
+ m_data->bottomLeftItem->setCursor(Qt::SizeBDiagCursor);
+
+ m_data->bottomRightItem = new ResizeHandleItem(layerItem, *this);
+ m_data->bottomRightItem->setZValue(305);
+ m_data->bottomRightItem->setCursor(Qt::SizeFDiagCursor);
+
+ m_data->topItem = new ResizeHandleItem(layerItem, *this);
+ m_data->topItem->setZValue(300);
+ m_data->topItem->setCursor(Qt::SizeVerCursor);
+
+ m_data->leftItem = new ResizeHandleItem(layerItem, *this);
+ m_data->leftItem->setZValue(300);
+ m_data->leftItem->setCursor(Qt::SizeHorCursor);
+
+ m_data->rightItem = new ResizeHandleItem(layerItem, *this);
+ m_data->rightItem->setZValue(300);
+ m_data->rightItem->setCursor(Qt::SizeHorCursor);
+
+ m_data->bottomItem = new ResizeHandleItem(layerItem, *this);
+ m_data->bottomItem->setZValue(300);
+ m_data->bottomItem->setCursor(Qt::SizeVerCursor);
+
+ updatePosition();
+}
+
+
+bool ResizeController::isValid() const
+{
+ return m_data->formEditorItem != 0;
+}
+
+void ResizeController::show()
+{
+ m_data->topLeftItem->show();
+ m_data->topRightItem->show();
+ m_data->bottomLeftItem->show();
+ m_data->bottomRightItem->show();
+ m_data->topItem->show();
+ m_data->leftItem->show();
+ m_data->rightItem->show();
+ m_data->bottomItem->show();
+}
+void ResizeController::hide()
+{
+ m_data->topLeftItem->hide();
+ m_data->topRightItem->hide();
+ m_data->bottomLeftItem->hide();
+ m_data->bottomRightItem->hide();
+ m_data->topItem->hide();
+ m_data->leftItem->hide();
+ m_data->rightItem->hide();
+ m_data->bottomItem->hide();
+}
+
+
+static QPointF topCenter(const QRectF &rect)
+{
+ return QPointF(rect.center().x(), rect.top());
+}
+
+static QPointF leftCenter(const QRectF &rect)
+{
+ return QPointF(rect.left(), rect.center().y());
+}
+
+static QPointF rightCenter(const QRectF &rect)
+{
+ return QPointF(rect.right(), rect.center().y());
+}
+
+static QPointF bottomCenter(const QRectF &rect)
+{
+ return QPointF(rect.center().x(), rect.bottom());
+}
+
+
+void ResizeController::updatePosition()
+{
+ QRectF originalBoundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect();
+ QRectF boundingRect = m_data->formEditorItem->qmlItemNode().instanceBoundingRect().adjusted(0.49, 0.49, 0.49, 0.49);
+ QPointF topLeftPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ boundingRect.topLeft()));
+ QPointF topRightPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ boundingRect.topRight()));
+ QPointF bottomLeftPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ boundingRect.bottomLeft()));
+ QPointF bottomRightPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ boundingRect.bottomRight()));
+
+ QPointF topPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ topCenter(boundingRect)));
+ QPointF leftPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ leftCenter(boundingRect)));
+
+ QPointF rightPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ rightCenter(boundingRect)));
+ QPointF bottomPointInLayerSpace(m_data->formEditorItem->mapToItem(m_data->layerItem.data(),
+ bottomCenter(boundingRect)));
+
+
+
+ m_data->topRightItem->setHandlePosition(topRightPointInLayerSpace, originalBoundingRect.topRight());
+ m_data->topLeftItem->setHandlePosition(topLeftPointInLayerSpace, originalBoundingRect.topLeft());
+ m_data->bottomLeftItem->setHandlePosition(bottomLeftPointInLayerSpace, originalBoundingRect.bottomLeft());
+ m_data->bottomRightItem->setHandlePosition(bottomRightPointInLayerSpace, originalBoundingRect.bottomRight());
+ m_data->topItem->setHandlePosition(topPointInLayerSpace, topCenter(originalBoundingRect));
+ m_data->leftItem->setHandlePosition(leftPointInLayerSpace, leftCenter(originalBoundingRect));
+ m_data->rightItem->setHandlePosition(rightPointInLayerSpace, rightCenter(originalBoundingRect));
+ m_data->bottomItem->setHandlePosition(bottomPointInLayerSpace, bottomCenter(originalBoundingRect));
+}
+
+
+FormEditorItem* ResizeController::formEditorItem() const
+{
+ return m_data->formEditorItem;
+}
+
+QWeakPointer<ResizeControllerData> ResizeController::weakPointer() const
+{
+ return m_data;
+}
+
+bool ResizeController::isTopLeftHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->topLeftItem;
+}
+
+bool ResizeController::isTopRightHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->topRightItem;
+}
+
+bool ResizeController::isBottomLeftHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->bottomLeftItem;
+}
+
+bool ResizeController::isBottomRightHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->bottomRightItem;
+}
+
+bool ResizeController::isTopHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->topItem;
+}
+
+bool ResizeController::isLeftHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->leftItem;
+}
+
+bool ResizeController::isRightHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->rightItem;
+}
+
+bool ResizeController::isBottomHandle(const ResizeHandleItem *handle) const
+{
+ return handle == m_data->bottomItem;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/resizecontroller.h b/src/plugins/qmldesigner/components/formeditor/resizecontroller.h
new file mode 100644
index 0000000000..be1e44824a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizecontroller.h
@@ -0,0 +1,104 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RESIZECONTROLLER_H
+#define RESIZECONTROLLER_H
+
+#include <QWeakPointer>
+#include <QSharedPointer>
+
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+class LayerItem;
+class ResizeHandleItem;
+
+
+class ResizeControllerData
+{
+public:
+ ResizeControllerData(LayerItem *layerItem,
+ FormEditorItem *formEditorItem);
+ ResizeControllerData(const ResizeControllerData &other);
+ ~ResizeControllerData();
+
+
+ QWeakPointer<LayerItem> layerItem;
+ FormEditorItem *formEditorItem;
+ ResizeHandleItem *topLeftItem;
+ ResizeHandleItem *topRightItem;
+ ResizeHandleItem *bottomLeftItem;
+ ResizeHandleItem *bottomRightItem;
+ ResizeHandleItem *topItem;
+ ResizeHandleItem *leftItem;
+ ResizeHandleItem *rightItem;
+ ResizeHandleItem *bottomItem;
+};
+
+
+
+
+class ResizeController
+{
+public:
+ friend class ResizeHandleItem;
+
+ ResizeController();
+ ResizeController(LayerItem *layerItem, FormEditorItem *formEditorItem);
+
+ void show();
+ void hide();
+
+ void updatePosition();
+
+ bool isValid() const;
+
+ FormEditorItem *formEditorItem() const;
+
+ bool isTopLeftHandle(const ResizeHandleItem *handle) const;
+ bool isTopRightHandle(const ResizeHandleItem *handle) const;
+ bool isBottomLeftHandle(const ResizeHandleItem *handle) const;
+ bool isBottomRightHandle(const ResizeHandleItem *handle) const;
+
+ bool isTopHandle(const ResizeHandleItem *handle) const;
+ bool isLeftHandle(const ResizeHandleItem *handle) const;
+ bool isRightHandle(const ResizeHandleItem *handle) const;
+ bool isBottomHandle(const ResizeHandleItem *handle) const;
+
+private: // functions
+ ResizeController(const QSharedPointer<ResizeControllerData> &data);
+ QWeakPointer<ResizeControllerData> weakPointer() const;
+private: // variables
+ QSharedPointer<ResizeControllerData> m_data;
+};
+
+}
+
+#endif // RESIZECONTROLLER_H
diff --git a/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp
new file mode 100644
index 0000000000..ae388cf2cd
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.cpp
@@ -0,0 +1,118 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "resizehandleitem.h"
+
+#include <formeditoritem.h>
+#include <QCursor>
+
+namespace QmlDesigner {
+
+ResizeHandleItem::ResizeHandleItem(QGraphicsItem *parent, const ResizeController &resizeController)
+ : QGraphicsPixmapItem(QPixmap(":/icon/handle/resize_handle.png"), parent),
+ m_resizeControllerData(resizeController.weakPointer())
+{
+ setShapeMode(QGraphicsPixmapItem::BoundingRectShape);
+ setOffset(-pixmap().rect().center());
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
+}
+
+void ResizeHandleItem::setHandlePosition(const QPointF & globalPosition, const QPointF & itemSpacePosition)
+{
+ m_itemSpacePosition = itemSpacePosition;
+ setPos(globalPosition);
+}
+
+QRectF ResizeHandleItem::boundingRect() const
+{
+ return QGraphicsPixmapItem::boundingRect().adjusted(-1, -1, 1, 1);
+}
+
+QPainterPath ResizeHandleItem::shape() const
+{
+ return QGraphicsItem::shape();
+}
+
+ResizeController ResizeHandleItem::resizeController() const
+{
+ Q_ASSERT(!m_resizeControllerData.isNull());
+ return ResizeController(m_resizeControllerData.toStrongRef());
+}
+
+ResizeHandleItem* ResizeHandleItem::fromGraphicsItem(QGraphicsItem *item)
+{
+ return qgraphicsitem_cast<ResizeHandleItem*>(item);
+}
+
+bool ResizeHandleItem::isTopLeftHandle() const
+{
+ return resizeController().isTopLeftHandle(this);
+}
+
+bool ResizeHandleItem::isTopRightHandle() const
+{
+ return resizeController().isTopRightHandle(this);
+}
+
+bool ResizeHandleItem::isBottomLeftHandle() const
+{
+ return resizeController().isBottomLeftHandle(this);
+}
+
+bool ResizeHandleItem::isBottomRightHandle() const
+{
+ return resizeController().isBottomRightHandle(this);
+}
+
+bool ResizeHandleItem::isTopHandle() const
+{
+ return resizeController().isTopHandle(this);
+}
+
+bool ResizeHandleItem::isLeftHandle() const
+{
+ return resizeController().isLeftHandle(this);
+}
+
+bool ResizeHandleItem::isRightHandle() const
+{
+ return resizeController().isRightHandle(this);
+}
+
+bool ResizeHandleItem::isBottomHandle() const
+{
+ return resizeController().isBottomHandle(this);
+}
+
+QPointF ResizeHandleItem::itemSpacePosition() const
+{
+ return m_itemSpacePosition;
+}
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/resizehandleitem.h b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.h
new file mode 100644
index 0000000000..3177e3aa24
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizehandleitem.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RESIZEHANDLEITEM_H
+#define RESIZEHANDLEITEM_H
+
+#include <QGraphicsPixmapItem>
+
+#include "resizecontroller.h"
+
+namespace QmlDesigner {
+
+class ResizeHandleItem : public QGraphicsPixmapItem
+{
+public:
+ enum
+ {
+ Type = 0xEAEA
+ };
+
+
+ ResizeHandleItem(QGraphicsItem *parent, const ResizeController &resizeController);
+
+ void setHandlePosition(const QPointF & globalPosition, const QPointF & itemSpacePosition);
+
+ int type() const;
+ QRectF boundingRect() const;
+ QPainterPath shape() const;
+
+ ResizeController resizeController() const;
+
+ static ResizeHandleItem* fromGraphicsItem(QGraphicsItem *item);
+
+ bool isTopLeftHandle() const;
+ bool isTopRightHandle() const;
+ bool isBottomLeftHandle() const;
+ bool isBottomRightHandle() const;
+
+ bool isTopHandle() const;
+ bool isLeftHandle() const;
+ bool isRightHandle() const;
+ bool isBottomHandle() const;
+
+ QPointF itemSpacePosition() const;
+
+private:
+ QWeakPointer<ResizeControllerData> m_resizeControllerData;
+ QPointF m_itemSpacePosition;
+};
+
+inline int ResizeHandleItem::type() const
+{
+ return Type;
+}
+
+}
+
+#endif // RESIZEHANDLEITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp b/src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp
new file mode 100644
index 0000000000..9add9a65c7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizeindicator.cpp
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "resizeindicator.h"
+
+#include "formeditoritem.h"
+
+namespace QmlDesigner {
+
+ResizeIndicator::ResizeIndicator(LayerItem *layerItem)
+ : m_layerItem(layerItem)
+{
+ Q_ASSERT(layerItem);
+}
+
+ResizeIndicator::~ResizeIndicator()
+{
+ m_itemControllerHash.clear();
+}
+
+void ResizeIndicator::show()
+{
+ QHashIterator<FormEditorItem*, ResizeController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ ResizeController controller = itemControllerIterator.next().value();
+ controller.show();
+ }
+}
+void ResizeIndicator::hide()
+{
+ QHashIterator<FormEditorItem*, ResizeController> itemControllerIterator(m_itemControllerHash);
+ while (itemControllerIterator.hasNext()) {
+ ResizeController controller = itemControllerIterator.next().value();
+ controller.hide();
+ }
+}
+
+void ResizeIndicator::clear()
+{
+ m_itemControllerHash.clear();
+}
+
+void ResizeIndicator::setItems(const QList<FormEditorItem*> &itemList)
+{
+ clear();
+
+ foreach (FormEditorItem* item, itemList) {
+ if (item->qmlItemNode().isRootNode())
+ continue;
+ ResizeController controller(m_layerItem, item);
+ m_itemControllerHash.insert(item, controller);
+ }
+}
+
+void ResizeIndicator::updateItems(const QList<FormEditorItem*> &itemList)
+{
+ foreach (FormEditorItem* item, itemList) {
+ if (m_itemControllerHash.contains(item)) {
+ ResizeController controller(m_itemControllerHash.value(item));
+ controller.updatePosition();
+ }
+ }
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/resizeindicator.h b/src/plugins/qmldesigner/components/formeditor/resizeindicator.h
new file mode 100644
index 0000000000..e8881ec3e7
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizeindicator.h
@@ -0,0 +1,81 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RESIZEINDICATOR_H
+#define RESIZEINDICATOR_H
+
+#include <QHash>
+#include <QPair>
+
+#include "resizecontroller.h"
+
+class QGraphicsRectItem;
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+class LayerItem;
+
+class ResizeIndicator
+{
+public:
+ enum Orientation {
+ Top = 1,
+ Right = 2,
+ Bottom = 4,
+ Left = 8
+ };
+
+ ResizeIndicator(LayerItem *layerItem);
+ ~ResizeIndicator();
+
+ void show();
+ void hide();
+
+ void clear();
+
+ void setItems(const QList<FormEditorItem*> &itemList);
+ void updateItems(const QList<FormEditorItem*> &itemList);
+
+//
+// QPair<FormEditorItem*,Orientation> pick(QGraphicsRectItem* pickedItem) const;
+//
+// void show();
+// void hide();
+
+
+
+private:
+ QHash<FormEditorItem*, ResizeController> m_itemControllerHash;
+
+ LayerItem *m_layerItem;
+};
+
+}
+#endif // SCALEINDICATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp
new file mode 100644
index 0000000000..b0f2189646
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.cpp
@@ -0,0 +1,504 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "resizemanipulator.h"
+
+#include "formeditoritem.h"
+#include "formeditorscene.h"
+#include "qmlanchors.h"
+#include <QtDebug>
+#include <model.h>
+#include "mathutils.h"
+
+#include <limits>
+
+namespace QmlDesigner {
+
+ResizeManipulator::ResizeManipulator(LayerItem *layerItem, FormEditorView *view)
+ : m_view(view),
+ m_beginTopMargin(0.0),
+ m_beginLeftMargin(0.0),
+ m_beginRightMargin(0.0),
+ m_beginBottomMargin(0.0),
+ m_layerItem(layerItem),
+ m_resizeHandle(0)
+{
+}
+
+ResizeManipulator::~ResizeManipulator()
+{
+ deleteSnapLines();
+}
+
+void ResizeManipulator::setHandle(ResizeHandleItem *resizeHandle)
+{
+ Q_ASSERT(resizeHandle);
+ m_resizeHandle = resizeHandle;
+ m_resizeController = resizeHandle->resizeController();
+ m_snapper.setContainerFormEditorItem(m_resizeController.formEditorItem()->parentItem());
+ m_snapper.setTransformtionSpaceFormEditorItem(m_resizeController.formEditorItem());
+ Q_ASSERT(m_resizeController.isValid());
+}
+
+void ResizeManipulator::removeHandle()
+{
+ m_resizeController = ResizeController();
+ m_resizeHandle = 0;
+}
+
+void ResizeManipulator::begin(const QPointF &/*beginPoint*/)
+{
+ if (m_resizeController.isValid()) {
+ m_beginBoundingRect = m_resizeController.formEditorItem()->qmlItemNode().instanceBoundingRect();
+ m_beginToSceneTransform = m_resizeController.formEditorItem()->qmlItemNode().instanceSceneTransform();
+ m_beginFromSceneTransform = m_beginToSceneTransform.inverted();
+ m_beginToParentTransform = m_resizeController.formEditorItem()->qmlItemNode().instanceTransform();
+ m_rewriterTransaction = m_view->beginRewriterTransaction();
+ m_snapper.updateSnappingLines(m_resizeController.formEditorItem());
+ m_beginBottomRightPoint = m_beginToParentTransform.map(m_resizeController.formEditorItem()->qmlItemNode().instanceBoundingRect().bottomRight());
+
+ QmlAnchors anchors(m_resizeController.formEditorItem()->qmlItemNode().anchors());
+ m_beginTopMargin = anchors.instanceMargin(AnchorLine::Top);
+ m_beginLeftMargin = anchors.instanceMargin(AnchorLine::Left);
+ m_beginRightMargin = anchors.instanceMargin(AnchorLine::Right);
+ m_beginBottomMargin = anchors.instanceMargin(AnchorLine::Bottom);
+ }
+}
+
+//static QSizeF mapSizeToParent(const QSizeF &size, QGraphicsItem *item)
+//{
+// QPointF sizeAsPoint(size.width(), size.height());
+// sizeAsPoint = item->mapToParent(sizeAsPoint);
+// return QSizeF(sizeAsPoint.x(), sizeAsPoint.y());
+//}
+
+void ResizeManipulator::update(const QPointF& updatePoint, Snapping useSnapping)
+{
+ const double minimumWidth = 15.0;
+ const double minimumHeight = 15.0;
+
+ deleteSnapLines();
+
+ if (m_resizeController.isValid()) {
+
+ FormEditorItem *formEditorItem = m_resizeController.formEditorItem();
+ FormEditorItem *containerItem = m_snapper.containerFormEditorItem();
+
+ if (!containerItem)
+ return;
+
+ QPointF updatePointInLocalSpace = m_beginFromSceneTransform.map(updatePoint);
+ QmlAnchors anchors(formEditorItem->qmlItemNode().anchors());
+
+ QRectF boundingRect(m_beginBoundingRect);
+ if (m_resizeHandle->isBottomRightHandle()) {
+ boundingRect.setBottomRight(updatePointInLocalSpace);
+
+ if (useSnapping == UseSnapping) {
+ double rightOffset = m_snapper.snapRightOffset(boundingRect);
+ if (rightOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.rx() -= rightOffset;
+
+ double bottomOffset = m_snapper.snapBottomOffset(boundingRect);
+ if (bottomOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.ry() -= bottomOffset;
+ }
+ boundingRect.setBottomRight(updatePointInLocalSpace);
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ boundingRect.setLeft(boundingRect.left() - (updatePointInLocalSpace.x() - m_beginBoundingRect.right()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ boundingRect.setTop(boundingRect.top() - (updatePointInLocalSpace.y() - m_beginBoundingRect.bottom()));
+ }
+
+ if (boundingRect.width() < minimumWidth)
+ boundingRect.setWidth(minimumWidth);
+ if (boundingRect.height() < minimumHeight)
+ boundingRect.setHeight(minimumHeight);
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
+ anchors.setMargin(AnchorLine::Bottom,
+ m_beginBottomMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).y());
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right)) {
+ anchors.setMargin(AnchorLine::Right,
+ m_beginRightMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).x());
+ }
+ } else if (m_resizeHandle->isTopLeftHandle()) {
+ boundingRect.setTopLeft(updatePointInLocalSpace);
+
+ if (useSnapping == UseSnapping) {
+ double leftOffset = m_snapper.snapLeftOffset(boundingRect);
+ if (leftOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.rx() -= leftOffset;
+
+ double topOffset = m_snapper.snapTopOffset(boundingRect);
+ if (topOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.ry() -= topOffset;
+ }
+ boundingRect.setTopLeft(updatePointInLocalSpace);
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ boundingRect.setRight(boundingRect.right() - (updatePointInLocalSpace.x() - m_beginBoundingRect.left()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ boundingRect.setBottom(boundingRect.bottom() - (updatePointInLocalSpace.y() - m_beginBoundingRect.top()));
+ }
+
+
+ if (boundingRect.width() < minimumWidth)
+ boundingRect.setLeft(boundingRect.left() - minimumWidth + boundingRect.width());
+ if (boundingRect.height() < minimumHeight)
+ boundingRect.setTop(boundingRect.top() - minimumHeight + boundingRect.height());
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+ formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft()));
+
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top)) {
+ anchors.setMargin(AnchorLine::Top,
+ m_beginTopMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).y() + m_beginToParentTransform.map(boundingRect.topLeft()).y()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left)) {
+ anchors.setMargin(AnchorLine::Left,
+ m_beginLeftMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).x() + m_beginToParentTransform.map(boundingRect.topLeft()).x()));
+ }
+
+ } else if (m_resizeHandle->isTopRightHandle()) {
+ boundingRect.setTopRight(updatePointInLocalSpace);
+
+ if (useSnapping == UseSnapping) {
+ double rightOffset = m_snapper.snapRightOffset(boundingRect);
+ if (rightOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.rx() -= rightOffset;
+
+ double topOffset = m_snapper.snapTopOffset(boundingRect);
+ if (topOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.ry() -= topOffset;
+ }
+ boundingRect.setTopRight(updatePointInLocalSpace);
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ boundingRect.setLeft(boundingRect.left() - (updatePointInLocalSpace.x() - m_beginBoundingRect.right()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ boundingRect.setBottom(boundingRect.bottom() - (updatePointInLocalSpace.y() - m_beginBoundingRect.top()));
+ }
+
+ if (boundingRect.height() < minimumHeight)
+ boundingRect.setTop(boundingRect.top() - minimumHeight + boundingRect.height());
+ if (boundingRect.width() < minimumWidth)
+ boundingRect.setWidth(minimumWidth);
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+ formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft()));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top)) {
+ anchors.setMargin(AnchorLine::Top,
+ m_beginTopMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).y() + m_beginToParentTransform.map(boundingRect.topLeft()).y()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right)) {
+ anchors.setMargin(AnchorLine::Right,
+ m_beginRightMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).x());
+ }
+ } else if (m_resizeHandle->isBottomLeftHandle()) {
+ boundingRect.setBottomLeft(updatePointInLocalSpace);
+
+ if (useSnapping == UseSnapping) {
+ double leftOffset = m_snapper.snapLeftOffset(boundingRect);
+ if (leftOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.rx() -= leftOffset;
+
+ double bottomOffset = m_snapper.snapBottomOffset(boundingRect);
+ if (bottomOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.ry() -= bottomOffset;
+ }
+
+ boundingRect.setBottomLeft(updatePointInLocalSpace);
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ boundingRect.setRight(boundingRect.right() - (updatePointInLocalSpace.x() - m_beginBoundingRect.left()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ boundingRect.setTop(boundingRect.top() - (updatePointInLocalSpace.y() - m_beginBoundingRect.bottom()));
+ }
+
+ if (boundingRect.height() < minimumHeight)
+ boundingRect.setHeight(minimumHeight);
+ if (boundingRect.width() < minimumWidth)
+ boundingRect.setLeft(boundingRect.left() - minimumWidth + boundingRect.width());
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+ formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft()));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left)) {
+ anchors.setMargin(AnchorLine::Left,
+ m_beginLeftMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).x() + m_beginToParentTransform.map(boundingRect.topLeft()).x()));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
+ anchors.setMargin(AnchorLine::Bottom,
+ m_beginBottomMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).y());
+ }
+ } else if (m_resizeHandle->isBottomHandle()) {
+ boundingRect.setBottom(updatePointInLocalSpace.y());
+
+ if (useSnapping == UseSnapping) {
+ double bottomOffset = m_snapper.snapBottomOffset(boundingRect);
+ if (bottomOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.ry() -= bottomOffset;
+ }
+
+ boundingRect.setBottom(updatePointInLocalSpace.y());
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ boundingRect.setTop(boundingRect.top() - (updatePointInLocalSpace.y() - m_beginBoundingRect.bottom()));
+ }
+
+ if (boundingRect.height() < minimumHeight)
+ boundingRect.setHeight(minimumHeight);
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
+ anchors.setMargin(AnchorLine::Bottom,
+ m_beginBottomMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).y());
+ }
+ } else if (m_resizeHandle->isTopHandle()) {
+ boundingRect.setTop(updatePointInLocalSpace.y());
+
+ if (useSnapping == UseSnapping) {
+ double topOffset = m_snapper.snapTopOffset(boundingRect);
+ if (topOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.ry() -= topOffset;
+ }
+
+ boundingRect.setTop(updatePointInLocalSpace.y());
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ boundingRect.setBottom(boundingRect.bottom() - (updatePointInLocalSpace.y() - m_beginBoundingRect.top()));
+ }
+
+ if (boundingRect.height() < minimumHeight)
+ boundingRect.setTop(boundingRect.top() - minimumHeight + boundingRect.height());
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+ formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft()));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top)) {
+ anchors.setMargin(AnchorLine::Top,
+ m_beginTopMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).y() + m_beginToParentTransform.map(boundingRect.topLeft()).y()));
+ }
+ } else if (m_resizeHandle->isRightHandle()) {
+ boundingRect.setRight(updatePointInLocalSpace.x());
+
+ if (useSnapping == UseSnapping) {
+ double rightOffset = m_snapper.snapRightOffset(boundingRect);
+ if (rightOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.rx() -= rightOffset;
+ }
+
+ boundingRect.setRight(updatePointInLocalSpace.x());
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ boundingRect.setLeft(boundingRect.left() - (updatePointInLocalSpace.x() - m_beginBoundingRect.right()));
+ }
+
+ if (boundingRect.width() < minimumWidth)
+ boundingRect.setWidth(minimumWidth);
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right)) {
+ anchors.setMargin(AnchorLine::Right,
+ m_beginRightMargin - (m_beginToParentTransform.map(boundingRect.bottomRight()) - m_beginBottomRightPoint).x());
+ }
+ } else if (m_resizeHandle->isLeftHandle()) {
+ boundingRect.setLeft(updatePointInLocalSpace.x());
+
+ if (useSnapping == UseSnapping) {
+ double leftOffset = m_snapper.snapLeftOffset(boundingRect);
+ if (leftOffset < std::numeric_limits<double>::max())
+ updatePointInLocalSpace.rx() -= leftOffset;
+ }
+
+ boundingRect.setLeft(updatePointInLocalSpace.x());
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ boundingRect.setRight(boundingRect.right() - (updatePointInLocalSpace.x() - m_beginBoundingRect.left()));
+ }
+
+ if (boundingRect.width() < minimumWidth)
+ boundingRect.setLeft(boundingRect.left() - minimumWidth + boundingRect.width());
+
+ formEditorItem->qmlItemNode().setSize(boundingRect.size());
+ formEditorItem->qmlItemNode().setPosition(m_beginToParentTransform.map(boundingRect.topLeft()));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left)) {
+ anchors.setMargin(AnchorLine::Left,
+ m_beginLeftMargin + (-m_beginToParentTransform.map(m_beginBoundingRect.topLeft()).x() + m_beginToParentTransform.map(boundingRect.topLeft()).x()));
+ }
+ }
+
+ if (useSnapping == UseSnapping)
+ m_graphicsLineList = m_snapper.generateSnappingLines(boundingRect,
+ m_layerItem.data(),
+ m_beginToSceneTransform);
+ }
+}
+
+void ResizeManipulator::end()
+{
+ m_rewriterTransaction.commit();
+ clear();
+ removeHandle();
+}
+
+void ResizeManipulator::moveBy(double deltaX, double deltaY)
+{
+ if (resizeHandle()) {
+ QmlItemNode qmlItemNode(m_resizeController.formEditorItem()->qmlItemNode());
+ QmlAnchors anchors(qmlItemNode.anchors());
+
+ if (m_resizeController.isLeftHandle(resizeHandle())
+ || m_resizeController.isTopLeftHandle(resizeHandle())
+ || m_resizeController.isBottomLeftHandle(resizeHandle())) {
+ qmlItemNode.setVariantProperty("x", round((qmlItemNode.instanceValue("x").toDouble() + deltaX), 4));
+ qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() - deltaX, 4));
+
+
+ if (anchors.instanceHasAnchor(AnchorLine::Left)) {
+ anchors.setMargin(AnchorLine::Left, anchors.instanceMargin(AnchorLine::Left) + deltaX);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() - (deltaX * 2), 4));
+ }
+ }
+
+ if (m_resizeController.isRightHandle(resizeHandle())
+ || m_resizeController.isTopRightHandle(resizeHandle())
+ || m_resizeController.isBottomRightHandle(resizeHandle())) {
+ qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() + deltaX, 4));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Right)) {
+ anchors.setMargin(AnchorLine::Right, round(anchors.instanceMargin(AnchorLine::Right) - deltaX, 4));
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
+ qmlItemNode.setVariantProperty("width", round(qmlItemNode.instanceValue("width").toDouble() + (deltaX * 2), 4));
+ }
+ }
+
+
+ if (m_resizeController.isTopHandle(resizeHandle())
+ || m_resizeController.isTopLeftHandle(resizeHandle())
+ || m_resizeController.isTopRightHandle(resizeHandle())) {
+ qmlItemNode.setVariantProperty("y", round(qmlItemNode.instanceValue("y").toDouble() + deltaY, 4));
+ qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() - deltaY, 4));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Top)) {
+ anchors.setMargin(AnchorLine::Top, anchors.instanceMargin(AnchorLine::Top) + deltaY);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() - (deltaY * 2), 4));
+ }
+ }
+
+ if (m_resizeController.isBottomHandle(resizeHandle())
+ || m_resizeController.isBottomLeftHandle(resizeHandle())
+ || m_resizeController.isBottomRightHandle(resizeHandle())) {
+ qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() + deltaY, 4));
+
+ if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
+ anchors.setMargin(AnchorLine::Bottom, anchors.instanceMargin(AnchorLine::Bottom) - deltaY);
+ }
+
+ if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
+ qmlItemNode.setVariantProperty("height", round(qmlItemNode.instanceValue("height").toDouble() + (deltaY * 2), 4));
+ }
+ }
+
+ }
+}
+
+bool ResizeManipulator::isInvalidSize(const QSizeF & size)
+{
+ if (size.width() < 15 || size.height() < 15)
+ return true;
+
+ return false;
+}
+
+void ResizeManipulator::deleteSnapLines()
+{
+ if (m_layerItem) {
+ foreach (QGraphicsItem *item, m_graphicsLineList)
+ m_layerItem->scene()->removeItem(item);
+ }
+
+ m_graphicsLineList.clear();
+ m_view->scene()->update();
+}
+
+ResizeHandleItem *ResizeManipulator::resizeHandle()
+{
+ return m_resizeHandle;
+}
+
+void ResizeManipulator::clear()
+{
+ m_rewriterTransaction.commit();
+
+ deleteSnapLines();
+ m_beginBoundingRect = QRectF();
+ m_beginFromSceneTransform = QTransform();
+ m_beginToSceneTransform = QTransform();
+ m_beginToParentTransform = QTransform();
+ m_beginTopMargin = 0.0;
+ m_beginLeftMargin = 0.0;
+ m_beginRightMargin = 0.0;
+ m_beginBottomMargin = 0.0;
+ removeHandle();
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/resizemanipulator.h b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.h
new file mode 100644
index 0000000000..913966537f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizemanipulator.h
@@ -0,0 +1,91 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RESIZEMANIPULATOR_H
+#define RESIZEMANIPULATOR_H
+
+#include <QWeakPointer>
+#include "resizehandleitem.h"
+#include <snapper.h>
+#include "rewritertransaction.h"
+#include "formeditorview.h"
+
+namespace QmlDesigner {
+
+class ResizeHandleItem;
+class Model;
+
+class ResizeManipulator
+{
+public:
+ enum Snapping {
+ UseSnapping,
+ NoSnapping
+ };
+
+ ResizeManipulator(LayerItem *layerItem, FormEditorView *view);
+ ~ResizeManipulator();
+
+ void setHandle(ResizeHandleItem *resizeHandle);
+ void removeHandle();
+
+ void begin(const QPointF& beginPoint);
+ void update(const QPointF& updatePoint, Snapping useSnapping);
+ void end();
+
+ void moveBy(double deltaX, double deltaY);
+
+ void clear();
+
+protected:
+ bool isInvalidSize(const QSizeF & size);
+ void deleteSnapLines();
+ ResizeHandleItem *resizeHandle();
+
+private:
+ Snapper m_snapper;
+ QWeakPointer<FormEditorView> m_view;
+ QList<QGraphicsItem*> m_graphicsLineList;
+ ResizeController m_resizeController; // hold the controller so that the handle cant be deleted
+ QTransform m_beginFromSceneTransform;
+ QTransform m_beginToSceneTransform;
+ QTransform m_beginToParentTransform;
+ QRectF m_beginBoundingRect;
+ QPointF m_beginBottomRightPoint;
+ double m_beginTopMargin;
+ double m_beginLeftMargin;
+ double m_beginRightMargin;
+ double m_beginBottomMargin;
+ QWeakPointer<LayerItem> m_layerItem;
+ ResizeHandleItem *m_resizeHandle;
+ RewriterTransaction m_rewriterTransaction;
+};
+
+}
+#endif // RESIZEMANIPULATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/resizetool.cpp b/src/plugins/qmldesigner/components/formeditor/resizetool.cpp
new file mode 100644
index 0000000000..bd7d5157e1
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizetool.cpp
@@ -0,0 +1,177 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "resizetool.h"
+
+#include "formeditorscene.h"
+#include "formeditorview.h"
+
+#include "resizehandleitem.h"
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+ResizeTool::ResizeTool(FormEditorView *editorView)
+ : AbstractFormEditorTool(editorView),
+ m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
+ m_resizeIndicator(editorView->scene()->manipulatorLayerItem()),
+ m_resizeManipulator(editorView->scene()->manipulatorLayerItem(), editorView)
+{
+}
+
+
+ResizeTool::~ResizeTool()
+{
+}
+
+void ResizeTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (itemList.isEmpty())
+ return;
+
+ ResizeHandleItem *resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first());
+ if (resizeHandle) {
+ m_resizeManipulator.setHandle(resizeHandle);
+ m_resizeManipulator.begin(event->scenePos());
+ m_selectionIndicator.hide();
+ m_resizeIndicator.hide();
+ }
+}
+
+void ResizeTool::mouseMoveEvent(const QList<QGraphicsItem*> &,
+ QGraphicsSceneMouseEvent *event)
+{
+
+
+ ResizeManipulator::Snapping useSnapping = ResizeManipulator::NoSnapping;
+ if (event->modifiers().testFlag(Qt::ControlModifier) != view()->isSnapButtonChecked())
+ useSnapping = ResizeManipulator::UseSnapping;
+
+ m_resizeManipulator.update(event->scenePos(), useSnapping);
+}
+
+void ResizeTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+ if (itemList.isEmpty())
+ return;
+ ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first());
+ if (resizeHandle) {
+ m_resizeManipulator.setHandle(resizeHandle);
+ } else {
+ view()->changeToSelectionTool();
+ return;
+ }
+}
+
+void ResizeTool::mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+ if (itemList.isEmpty())
+ return;
+
+ m_selectionIndicator.show();
+ m_resizeIndicator.show();
+ m_resizeManipulator.end();
+}
+
+void ResizeTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> & /*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+}
+
+void ResizeTool::keyPressEvent(QKeyEvent * event)
+{
+ switch(event->key()) {
+ case Qt::Key_Shift:
+ case Qt::Key_Alt:
+ case Qt::Key_Control:
+ case Qt::Key_AltGr:
+ event->setAccepted(false);
+ return;
+ }
+
+ double moveStep = 1.0;
+
+ if (event->modifiers().testFlag(Qt::ShiftModifier))
+ moveStep = 10.0;
+
+ switch(event->key()) {
+ case Qt::Key_Left: m_resizeManipulator.moveBy(-moveStep, 0.0); break;
+ case Qt::Key_Right: m_resizeManipulator.moveBy(moveStep, 0.0); break;
+ case Qt::Key_Up: m_resizeManipulator.moveBy(0.0, -moveStep); break;
+ case Qt::Key_Down: m_resizeManipulator.moveBy(0.0, moveStep); break;
+ }
+
+}
+
+void ResizeTool::keyReleaseEvent(QKeyEvent * keyEvent)
+{
+ switch(keyEvent->key()) {
+ case Qt::Key_Shift:
+ case Qt::Key_Alt:
+ case Qt::Key_Control:
+ case Qt::Key_AltGr:
+ keyEvent->setAccepted(false);
+ return;
+ }
+
+// if (!keyEvent->isAutoRepeat())
+// m_resizeManipulator.clear();
+}
+
+void ResizeTool::itemsAboutToRemoved(const QList<FormEditorItem*> & /*itemList*/)
+{
+
+}
+
+void ResizeTool::selectedItemsChanged(const QList<FormEditorItem*> & /*itemList*/)
+{
+ m_selectionIndicator.setItems(items());
+ m_resizeIndicator.setItems(items());
+}
+
+void ResizeTool::clear()
+{
+ m_selectionIndicator.clear();
+ m_resizeIndicator.clear();
+ m_resizeManipulator.clear();
+}
+
+void ResizeTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList)
+{
+ m_selectionIndicator.updateItems(itemList);
+ m_resizeIndicator.updateItems(itemList);
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/resizetool.h b/src/plugins/qmldesigner/components/formeditor/resizetool.h
new file mode 100644
index 0000000000..f376748ac0
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/resizetool.h
@@ -0,0 +1,76 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RESIZETOOL_H
+#define RESIZETOOL_H
+
+#include "abstractformeditortool.h"
+#include "selectionindicator.h"
+#include "resizeindicator.h"
+#include "resizemanipulator.h"
+
+
+namespace QmlDesigner {
+
+class ResizeTool : public AbstractFormEditorTool
+{
+public:
+ ResizeTool(FormEditorView* editorView);
+ ~ResizeTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList);
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void clear();
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList);
+
+private:
+ SelectionIndicator m_selectionIndicator;
+ ResizeIndicator m_resizeIndicator;
+ ResizeManipulator m_resizeManipulator;
+};
+
+}
+
+#endif // RESIZETOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp
new file mode 100644
index 0000000000..f9ca6b0831
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.cpp
@@ -0,0 +1,153 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "rubberbandselectionmanipulator.h"
+
+#include "model.h"
+#include "formeditorscene.h"
+
+namespace QmlDesigner {
+
+RubberBandSelectionManipulator::RubberBandSelectionManipulator(LayerItem *layerItem, FormEditorView *editorView)
+ : m_selectionRectangleElement(layerItem),
+ m_editorView(editorView),
+ m_beginFormEditorItem(0),
+ m_isActive(false)
+{
+ m_selectionRectangleElement.hide();
+}
+
+void RubberBandSelectionManipulator::clear()
+{
+ m_selectionRectangleElement.clear();
+ m_isActive = false;
+ m_beginPoint = QPointF();
+ m_itemList.clear();
+ m_oldSelectionList.clear();
+}
+
+FormEditorItem *RubberBandSelectionManipulator::topFormEditorItem(const QList<QGraphicsItem*> &itemList)
+{
+ foreach (QGraphicsItem *item, itemList) {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+
+ if (formEditorItem)
+ {
+ return formEditorItem;
+ }
+ }
+
+ return m_editorView->scene()->rootFormEditorItem();
+}
+
+void RubberBandSelectionManipulator::begin(const QPointF& beginPoint)
+{
+ m_beginPoint = beginPoint;
+ m_selectionRectangleElement.setRect(m_beginPoint, m_beginPoint);
+ m_selectionRectangleElement.show();
+ m_isActive = true;
+ m_beginFormEditorItem = topFormEditorItem(m_editorView->scene()->items(beginPoint));
+ m_oldSelectionList = m_editorView->selectedQmlItemNodes();
+}
+
+void RubberBandSelectionManipulator::update(const QPointF& updatePoint)
+{
+ m_selectionRectangleElement.setRect(m_beginPoint, updatePoint);
+}
+
+void RubberBandSelectionManipulator::end()
+{
+ m_oldSelectionList.clear();
+ m_selectionRectangleElement.hide();
+ m_isActive = false;
+}
+
+void RubberBandSelectionManipulator::select(SelectionType selectionType)
+{
+ if (!m_beginFormEditorItem)
+ return;
+
+ QList<QGraphicsItem*> itemList = m_editorView->scene()->items(m_selectionRectangleElement.rect(),
+ Qt::IntersectsItemBoundingRect);
+ QList<QmlItemNode> newNodeList;
+
+ foreach (QGraphicsItem* item, itemList)
+ {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+
+ if (formEditorItem
+ && m_beginFormEditorItem->childItems().contains(formEditorItem)
+ && !formEditorItem->qmlItemNode().isRootNode())
+ {
+ newNodeList.append(formEditorItem->qmlItemNode());
+ }
+ }
+
+ if (newNodeList.isEmpty() && !m_beginFormEditorItem->qmlItemNode().isRootNode())
+ newNodeList.append(m_beginFormEditorItem->qmlItemNode());
+
+ QList<QmlItemNode> nodeList;
+
+ switch(selectionType) {
+ case AddToSelection: {
+ nodeList.append(m_oldSelectionList);
+ nodeList.append(newNodeList);
+ }
+ break;
+ case ReplaceSelection: {
+ nodeList.append(newNodeList);
+ }
+ break;
+ case RemoveFromSelection: {
+ QSet<QmlItemNode> oldSelectionSet(m_oldSelectionList.toSet());
+ QSet<QmlItemNode> newSelectionSet(newNodeList.toSet());
+ nodeList.append(oldSelectionSet.subtract(newSelectionSet).toList());
+ }
+ }
+
+ m_editorView->setSelectedQmlItemNodes(nodeList);
+}
+
+
+void RubberBandSelectionManipulator::setItems(const QList<FormEditorItem*> &itemList)
+{
+ m_itemList = itemList;
+}
+
+QPointF RubberBandSelectionManipulator::beginPoint() const
+{
+ return m_beginPoint;
+}
+
+bool RubberBandSelectionManipulator::isActive() const
+{
+ return m_isActive;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h
new file mode 100644
index 0000000000..bd8d9b6b2a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/rubberbandselectionmanipulator.h
@@ -0,0 +1,83 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef RUBBERBANDSELECTIONMANIPULATOR_H
+#define RUBBERBANDSELECTIONMANIPULATOR_H
+
+
+#include "selectionrectangle.h"
+#include "formeditorview.h"
+#include "formeditoritem.h"
+
+namespace QmlDesigner {
+
+
+class RubberBandSelectionManipulator
+{
+public:
+ enum SelectionType {
+ ReplaceSelection,
+ AddToSelection,
+ RemoveFromSelection
+ };
+
+
+ RubberBandSelectionManipulator(LayerItem *layerItem, FormEditorView *editorView);
+
+ void setItems(const QList<FormEditorItem*> &itemList);
+
+ void begin(const QPointF& beginPoint);
+ void update(const QPointF& updatePoint);
+ void end();
+
+ void clear();
+
+ void select(SelectionType selectionType);
+
+ QPointF beginPoint() const;
+
+ bool isActive() const;
+
+protected:
+ FormEditorItem *topFormEditorItem(const QList<QGraphicsItem*> &itemList);
+
+
+private:
+ QList<FormEditorItem*> m_itemList;
+ QList<QmlItemNode> m_oldSelectionList;
+ SelectionRectangle m_selectionRectangleElement;
+ QPointF m_beginPoint;
+ FormEditorView *m_editorView;
+ FormEditorItem *m_beginFormEditorItem;
+ bool m_isActive;
+};
+
+}
+
+#endif // RUBBERBANDSELECTIONMANIPULATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/scaleitem.cpp b/src/plugins/qmldesigner/components/formeditor/scaleitem.cpp
new file mode 100644
index 0000000000..def9aeb5ee
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/scaleitem.cpp
@@ -0,0 +1,49 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "scaleitem.h"
+
+#include "layeritem.h"
+
+namespace QmlDesigner {
+
+ScaleItem::ScaleItem(LayerItem *layerItem, ScaleIndicator *indicator)
+ : QGraphicsRectItem(layerItem),
+ m_indicator(indicator)
+{
+ Q_ASSERT(layerItem);
+ Q_ASSERT(indicator);
+}
+
+ScaleIndicator* ScaleItem::indicator() const
+{
+ return m_indicator;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/scaleitem.h b/src/plugins/qmldesigner/components/formeditor/scaleitem.h
new file mode 100644
index 0000000000..c06d2170e2
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/scaleitem.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SCALEITEM_H
+#define SCALEITEM_H
+
+#include <QGraphicsRectItem>
+
+namespace QmlDesigner {
+
+class LayerItem;
+class ScaleIndicator;
+
+class ScaleItem : public QGraphicsRectItem
+{
+public:
+ ScaleItem(LayerItem *layerItem, ScaleIndicator *indicator);
+
+ ScaleIndicator* indicator() const;
+
+private:
+ ScaleIndicator* m_indicator;
+};
+
+};
+
+#endif // SCALEITEM_H
diff --git a/src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp
new file mode 100644
index 0000000000..0c329f22b9
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.cpp
@@ -0,0 +1,45 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "scalemanipulator.h"
+
+
+namespace QmlDesigner {
+
+ScaleManipulator::ScaleManipulator(LayerItem *layerItem, FormEditorItem *formEditorItem)
+ : m_layerItem(layerItem),
+ m_formEditorItem(formEditorItem)
+{
+}
+
+ScaleManipulator::~ScaleManipulator()
+{
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/scalemanipulator.h b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.h
new file mode 100644
index 0000000000..9d853d7f35
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/scalemanipulator.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SCALEMANIPULATOR_H
+#define SCALEMANIPULATOR_H
+
+#include <QPointF>
+#include <QList>
+
+
+
+class QGraphicsLineItem;
+
+namespace QmlDesigner {
+
+class LayerItem;
+class FormEditorItem;
+
+class ScaleManipulator
+{
+public:
+ ScaleManipulator(LayerItem *layerItem, FormEditorItem *formEditorItem);
+ virtual ~ScaleManipulator();
+
+
+ void begin(const QPointF& beginPoint);
+ void update(const QPointF& updatePoint);
+ void reparentTo(FormEditorItem *newParent);
+ void end(const QPointF& updatePoint);
+
+private:
+ LayerItem *m_layerItem;
+ FormEditorItem *m_formEditorItem;
+};
+
+}
+#endif // SCALEMANIPULATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
new file mode 100644
index 0000000000..d71ef6cca2
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.cpp
@@ -0,0 +1,118 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "selectionindicator.h"
+
+#include <QPen>
+#include <cmath>
+#include <QGraphicsScene>
+#include <formeditorview.h>
+#include <formeditorwidget.h>
+#include <zoomaction.h>
+
+namespace QmlDesigner {
+
+SelectionIndicator::SelectionIndicator(LayerItem *layerItem)
+ : m_layerItem(layerItem)
+{
+}
+
+SelectionIndicator::~SelectionIndicator()
+{
+ clear();
+}
+
+void SelectionIndicator::show()
+{
+ foreach (QGraphicsPolygonItem *item, m_indicatorShapeHash.values())
+ item->show();
+}
+
+void SelectionIndicator::hide()
+{
+ foreach (QGraphicsPolygonItem *item, m_indicatorShapeHash.values())
+ item->hide();
+}
+
+void SelectionIndicator::clear()
+{
+ if (m_layerItem) {
+ foreach (QGraphicsItem *item, m_indicatorShapeHash.values())
+ m_layerItem->scene()->removeItem(item);
+ }
+ m_indicatorShapeHash.clear();
+}
+
+static void alignVertices(QPolygonF &polygon, double factor)
+{
+ QMutableVectorIterator<QPointF> iterator(polygon);
+ while (iterator.hasNext()) {
+ QPointF &vertex = iterator.next();
+ vertex.setX(std::floor(vertex.x()) + factor);
+ vertex.setY(std::floor(vertex.y()) + factor);
+ }
+
+}
+
+void SelectionIndicator::setItems(const QList<FormEditorItem*> &itemList)
+{
+ clear();
+
+ foreach (FormEditorItem *item, itemList) {
+ QGraphicsPolygonItem *newSelectionIndicatorGraphicsItem = new QGraphicsPolygonItem(m_layerItem.data());
+ m_indicatorShapeHash.insert(item, newSelectionIndicatorGraphicsItem);
+ QPolygonF boundingRectInSceneSpace(item->mapToScene(item->qmlItemNode().instanceBoundingRect()));
+ alignVertices(boundingRectInSceneSpace, 0.5 / item->formEditorView()->widget()->zoomAction()->zoomLevel());
+ QPolygonF boundingRectInLayerItemSpace = m_layerItem->mapFromScene(boundingRectInSceneSpace);
+ newSelectionIndicatorGraphicsItem->setPolygon(boundingRectInLayerItemSpace);
+ newSelectionIndicatorGraphicsItem->setFlag(QGraphicsItem::ItemIsSelectable, false);
+
+ QPen pen;
+ pen.setColor(QColor(108, 141, 221));
+ newSelectionIndicatorGraphicsItem->setPen(pen);
+ }
+}
+
+
+
+void SelectionIndicator::updateItems(const QList<FormEditorItem*> &itemList)
+{
+ foreach (FormEditorItem *item, itemList) {
+ if (m_indicatorShapeHash.contains(item)) {
+ QGraphicsPolygonItem *indicatorGraphicsItem = m_indicatorShapeHash.value(item);
+ QPolygonF boundingRectInSceneSpace(item->mapToScene(item->qmlItemNode().instanceBoundingRect()));
+ alignVertices(boundingRectInSceneSpace, 0.5 / item->formEditorView()->widget()->zoomAction()->zoomLevel());
+ QPolygonF boundingRectInLayerItemSpace = m_layerItem->mapFromScene(boundingRectInSceneSpace);
+ indicatorGraphicsItem->setPolygon(boundingRectInLayerItemSpace);
+ }
+ }
+}
+
+}
+
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionindicator.h b/src/plugins/qmldesigner/components/formeditor/selectionindicator.h
new file mode 100644
index 0000000000..27e641b0a8
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/selectionindicator.h
@@ -0,0 +1,65 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SELECTIONINDICATOR_H
+#define SELECTIONINDICATOR_H
+
+#include <QWeakPointer>
+#include <QGraphicsPolygonItem>
+#include "layeritem.h"
+#include "formeditoritem.h"
+
+
+
+namespace QmlDesigner {
+
+
+class SelectionIndicator
+{
+public:
+ SelectionIndicator(LayerItem *layerItem);
+ ~SelectionIndicator();
+
+ void show();
+ void hide();
+
+ void clear();
+
+ void setItems(const QList<FormEditorItem*> &itemList);
+ void updateItems(const QList<FormEditorItem*> &itemList);
+
+private:
+ QHash<FormEditorItem*, QGraphicsPolygonItem *> m_indicatorShapeHash;
+ QWeakPointer<LayerItem> m_layerItem;
+
+};
+
+}
+
+#endif // SELECTIONINDICATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp
new file mode 100644
index 0000000000..058de243e0
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.cpp
@@ -0,0 +1,87 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "selectionrectangle.h"
+
+#include <QPen>
+#include <QGraphicsScene>
+#include <QtDebug>
+#include <cmath>
+#include <QGraphicsScene>
+
+namespace QmlDesigner {
+
+SelectionRectangle::SelectionRectangle(LayerItem *layerItem)
+ : m_controlShape(new QGraphicsRectItem(layerItem)),
+ m_layerItem(layerItem)
+{
+ m_controlShape->setPen(QPen(Qt::black));
+ m_controlShape->setBrush(QColor(128, 128, 128, 50));
+}
+
+SelectionRectangle::~SelectionRectangle()
+{
+ if (m_layerItem)
+ m_layerItem->scene()->removeItem(m_controlShape);
+}
+
+void SelectionRectangle::clear()
+{
+ hide();
+}
+void SelectionRectangle::show()
+{
+ m_controlShape->show();
+}
+
+void SelectionRectangle::hide()
+{
+ m_controlShape->hide();
+}
+
+QRectF SelectionRectangle::rect() const
+{
+ return m_controlShape->mapFromScene(m_controlShape->rect()).boundingRect();
+}
+
+void SelectionRectangle::setRect(const QPointF &firstPoint,
+ const QPointF &secondPoint)
+{
+ double firstX = std::floor(firstPoint.x()) + 0.5;
+ double firstY = std::floor(firstPoint.y()) + 0.5;
+ double secondX = std::floor(secondPoint.x()) + 0.5;
+ double secondY = std::floor(secondPoint.y()) + 0.5;
+ QPointF topLeftPoint(firstX < secondX ? firstX : secondX, firstY < secondY ? firstY : secondY);
+ QPointF bottomRightPoint(firstX > secondX ? firstX : secondX, firstY > secondY ? firstY : secondY);
+
+ QRectF rect(topLeftPoint, bottomRightPoint);
+ m_controlShape->setRect(rect);
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/selectionrectangle.h b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.h
new file mode 100644
index 0000000000..91839be73f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/selectionrectangle.h
@@ -0,0 +1,63 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SELECTIONRECTANGLE_H
+#define SELECTIONRECTANGLE_H
+
+#include <QWeakPointer>
+#include <QGraphicsRectItem>
+#include "layeritem.h"
+
+
+namespace QmlDesigner {
+
+class SelectionRectangle
+{
+public:
+ SelectionRectangle(LayerItem *layerItem);
+ ~SelectionRectangle();
+
+ void show();
+ void hide();
+
+ void clear();
+
+ void setRect(const QPointF &firstPoint,
+ const QPointF &secondPoint);
+
+ QRectF rect() const;
+
+private:
+ QGraphicsRectItem *m_controlShape;
+ QWeakPointer<LayerItem> m_layerItem;
+};
+
+}
+
+#endif // SELECTIONRECTANGLE_H
diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp
new file mode 100644
index 0000000000..a3e7c1ee60
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp
@@ -0,0 +1,280 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "selectiontool.h"
+#include "formeditorscene.h"
+#include "formeditorview.h"
+
+#include "resizehandleitem.h"
+
+
+#include <QApplication>
+#include <QGraphicsSceneMouseEvent>
+#include <QtDebug>
+#include <QClipboard>
+
+namespace QmlDesigner {
+
+SelectionTool::SelectionTool(FormEditorView *editorView)
+ : AbstractFormEditorTool(editorView),
+ m_rubberbandSelectionManipulator(editorView->scene()->manipulatorLayerItem(), editorView),
+ m_singleSelectionManipulator(editorView),
+ m_selectionIndicator(editorView->scene()->manipulatorLayerItem()),
+ m_resizeIndicator(editorView->scene()->manipulatorLayerItem())
+
+{
+// view()->setCursor(Qt::CrossCursor);
+}
+
+
+SelectionTool::~SelectionTool()
+{
+}
+
+void SelectionTool::mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event)
+{
+ m_mousePressTimer.start();
+ FormEditorItem* formEditorItem = topFormEditorItem(itemList);
+ if (formEditorItem && !formEditorItem->qmlItemNode().hasChildren()) {
+ m_singleSelectionManipulator.begin(event->scenePos());
+
+ if (event->modifiers().testFlag(Qt::ControlModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection);
+ else if (event->modifiers().testFlag(Qt::ShiftModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection);
+ else
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection);
+ } else {
+ if (event->modifiers().testFlag(Qt::AltModifier)) {
+ m_singleSelectionManipulator.begin(event->scenePos());
+
+ if (event->modifiers().testFlag(Qt::ControlModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection);
+ else if (event->modifiers().testFlag(Qt::ShiftModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection);
+ else
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection);
+
+ m_singleSelectionManipulator.end(event->scenePos());
+ view()->changeToMoveTool(event->scenePos());
+ } else {
+ m_rubberbandSelectionManipulator.begin(event->scenePos());
+ }
+ }
+}
+
+void SelectionTool::mouseMoveEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_singleSelectionManipulator.isActive()) {
+ QPointF mouseMovementVector = m_singleSelectionManipulator.beginPoint() - event->scenePos();
+ if ((mouseMovementVector.toPoint().manhattanLength() > QApplication::startDragDistance())
+ && (m_mousePressTimer.elapsed() > QApplication::startDragTime())) {
+ m_singleSelectionManipulator.end(event->scenePos());
+ view()->changeToMoveTool(m_singleSelectionManipulator.beginPoint());
+ return;
+ }
+ } else if (m_rubberbandSelectionManipulator.isActive()) {
+ QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->scenePos();
+ if ((mouseMovementVector.toPoint().manhattanLength() > QApplication::startDragDistance())
+ && (m_mousePressTimer.elapsed() > QApplication::startDragTime())) {
+ m_rubberbandSelectionManipulator.update(event->scenePos());
+
+ if (event->modifiers().testFlag(Qt::ControlModifier))
+ m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::RemoveFromSelection);
+ else if (event->modifiers().testFlag(Qt::ShiftModifier))
+ m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::AddToSelection);
+ else
+ m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::ReplaceSelection);
+ }
+ }
+}
+
+void SelectionTool::hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+ if (itemList.isEmpty())
+ return;
+
+ ResizeHandleItem* resizeHandle = ResizeHandleItem::fromGraphicsItem(itemList.first());
+ if (resizeHandle) {
+ view()->changeToResizeTool();
+ return;
+ }
+
+ if (topSelectedItemIsMovable(itemList))
+ view()->changeToMoveTool();
+}
+
+void SelectionTool::mouseReleaseEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent *event)
+{
+ if (m_singleSelectionManipulator.isActive()) {
+ qDebug() << __FUNCTION__ << "single";
+ m_singleSelectionManipulator.end(event->scenePos());
+ }
+ else if (m_rubberbandSelectionManipulator.isActive()) {
+
+ QPointF mouseMovementVector = m_rubberbandSelectionManipulator.beginPoint() - event->scenePos();
+ if (mouseMovementVector.toPoint().manhattanLength() < QApplication::startDragDistance()) {
+ m_singleSelectionManipulator.begin(event->scenePos());
+
+ if (event->modifiers().testFlag(Qt::ControlModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection);
+ else if (event->modifiers().testFlag(Qt::ShiftModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection);
+ else
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::InvertSelection);
+
+ m_singleSelectionManipulator.end(event->scenePos());
+ } else {
+ m_rubberbandSelectionManipulator.update(event->scenePos());
+
+ if (event->modifiers().testFlag(Qt::ControlModifier))
+ m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::RemoveFromSelection);
+ else if (event->modifiers().testFlag(Qt::ShiftModifier))
+ m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::AddToSelection);
+ else
+ m_rubberbandSelectionManipulator.select(RubberBandSelectionManipulator::ReplaceSelection);
+
+ m_rubberbandSelectionManipulator.end();
+ }
+ }
+
+}
+
+void SelectionTool::mouseDoubleClickEvent(const QList<QGraphicsItem*> &/*itemList*/,
+ QGraphicsSceneMouseEvent * /*event*/)
+{
+
+}
+
+void SelectionTool::keyPressEvent(QKeyEvent *event)
+{
+ switch(event->key()) {
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ view()->changeToMoveTool();
+ view()->currentTool()->keyPressEvent(event);
+ break;
+ case Qt::Key_C:
+ if (event->modifiers().testFlag(Qt::ControlModifier)) {
+ copySelectedNodeToClipBoard();
+ break;
+ }
+ case Qt::Key_V:
+ if (event->modifiers().testFlag(Qt::ControlModifier)) {
+ pasteClipBoard();
+ break;
+ }
+ case Qt::Key_X:
+ if (event->modifiers().testFlag(Qt::ControlModifier)) {
+ cutSelectedNodeToClipBoard();
+ break;
+ }
+ }
+}
+
+void SelectionTool::keyReleaseEvent(QKeyEvent * /*keyEvent*/)
+{
+
+}
+
+void SelectionTool::copySelectedNodeToClipBoard()
+{
+ // QClipboard *clipboard = QApplication::clipboard();
+}
+
+void SelectionTool::cutSelectedNodeToClipBoard()
+{
+ // QClipboard *clipboard = QApplication::clipboard();
+}
+
+void SelectionTool::pasteClipBoard()
+{
+ // QClipboard *clipboard = QApplication::clipboard();
+}
+
+void SelectionTool::itemsAboutToRemoved(const QList<FormEditorItem*> &/*itemList*/)
+{
+
+}
+
+//QVariant SelectionTool::itemChange(const QList<QGraphicsItem*> &itemList,
+// QGraphicsItem::GraphicsItemChange change,
+// const QVariant &value )
+//{
+// qDebug() << Q_FUNC_INFO;
+// return QVariant();
+//}
+
+//void SelectionTool::update()
+//{
+//
+//}
+
+
+void SelectionTool::clear()
+{
+ m_rubberbandSelectionManipulator.clear(),
+ m_singleSelectionManipulator.clear();
+ m_selectionIndicator.clear();
+ m_resizeIndicator.clear();
+}
+
+void SelectionTool::selectedItemsChanged(const QList<FormEditorItem*> &itemList)
+{
+ m_selectionIndicator.setItems(itemList);
+ m_resizeIndicator.setItems(itemList);
+}
+
+void SelectionTool::formEditorItemsChanged(const QList<FormEditorItem*> &itemList)
+{
+ m_selectionIndicator.updateItems(itemList);
+ m_resizeIndicator.updateItems(itemList);
+}
+
+void SelectionTool::selectUnderPoint(QGraphicsSceneMouseEvent *event)
+{
+ m_singleSelectionManipulator.begin(event->scenePos());
+
+ if (event->modifiers().testFlag(Qt::ControlModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::RemoveFromSelection);
+ else if (event->modifiers().testFlag(Qt::ShiftModifier))
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::AddToSelection);
+ else
+ m_singleSelectionManipulator.select(SingleSelectionManipulator::ReplaceSelection);
+
+ m_singleSelectionManipulator.end(event->scenePos());
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.h b/src/plugins/qmldesigner/components/formeditor/selectiontool.h
new file mode 100644
index 0000000000..062eb20fbc
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.h
@@ -0,0 +1,93 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SELECTIONTOOL_H
+#define SELECTIONTOOL_H
+
+
+#include "abstractformeditortool.h"
+#include "movemanipulator.h"
+#include "rubberbandselectionmanipulator.h"
+#include "singleselectionmanipulator.h"
+#include "selectionindicator.h"
+#include "resizeindicator.h"
+
+#include <QHash>
+#include <QTime>
+
+namespace QmlDesigner {
+
+
+class SelectionTool : public AbstractFormEditorTool
+{
+public:
+ SelectionTool(FormEditorView* editorView);
+ ~SelectionTool();
+
+ void mousePressEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseReleaseEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void mouseDoubleClickEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void hoverMoveEvent(const QList<QGraphicsItem*> &itemList,
+ QGraphicsSceneMouseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *keyEvent);
+
+ void itemsAboutToRemoved(const QList<FormEditorItem*> &itemList);
+ // QVariant itemChange(const QList<QGraphicsItem*> &itemList,
+// QGraphicsItem::GraphicsItemChange change,
+// const QVariant &value );
+
+// void update();
+
+ void clear();
+
+ void selectedItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void formEditorItemsChanged(const QList<FormEditorItem*> &itemList);
+
+ void selectUnderPoint(QGraphicsSceneMouseEvent *event);
+
+ void copySelectedNodeToClipBoard();
+ void cutSelectedNodeToClipBoard();
+ void pasteClipBoard();
+private:
+ RubberBandSelectionManipulator m_rubberbandSelectionManipulator;
+ SingleSelectionManipulator m_singleSelectionManipulator;
+ SelectionIndicator m_selectionIndicator;
+ ResizeIndicator m_resizeIndicator;
+ QTime m_mousePressTimer;
+};
+
+}
+#endif // SELECTIONTOOL_H
diff --git a/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp
new file mode 100644
index 0000000000..43625eb955
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.cpp
@@ -0,0 +1,132 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "singleselectionmanipulator.h"
+
+#include "model.h"
+#include "nodemetainfo.h"
+#include "formeditorscene.h"
+#include "formeditorview.h"
+#include <QtDebug>
+
+namespace QmlDesigner {
+
+SingleSelectionManipulator::SingleSelectionManipulator(FormEditorView *editorView)
+ : m_editorView(editorView),
+ m_isActive(false)
+{
+}
+
+
+void SingleSelectionManipulator::begin(const QPointF &beginPoint)
+{
+ m_beginPoint = beginPoint;
+ m_isActive = true;
+ m_oldSelectionList = m_editorView->selectedQmlItemNodes();
+}
+
+void SingleSelectionManipulator::update(const QPointF &/*updatePoint*/)
+{
+ m_oldSelectionList.clear();
+}
+
+void SingleSelectionManipulator::clear()
+{
+ m_beginPoint = QPointF();
+ m_oldSelectionList.clear();
+}
+
+
+void SingleSelectionManipulator::end(const QPointF &/*updatePoint*/)
+{
+ m_oldSelectionList.clear();
+ m_isActive = false;
+}
+
+void SingleSelectionManipulator::select(SelectionType selectionType)
+{
+ QList<QGraphicsItem*> itemList = m_editorView->scene()->items(m_beginPoint);
+
+ QmlItemNode selectedNode;
+
+ foreach(QGraphicsItem* item, itemList)
+ {
+ FormEditorItem *formEditorItem = FormEditorItem::fromQGraphicsItem(item);
+
+ if (formEditorItem
+ && !formEditorItem->qmlItemNode().isRootNode()
+ && (formEditorItem->qmlItemNode().hasShowContent()))
+ {
+ selectedNode = formEditorItem->qmlItemNode();
+ break;
+ }
+ }
+
+ QList<QmlItemNode> nodeList;
+
+ switch(selectionType) {
+ case AddToSelection: {
+ nodeList.append(m_oldSelectionList);
+ if (selectedNode.isValid())
+ nodeList.append(selectedNode);
+ }
+ break;
+ case ReplaceSelection: {
+ if (selectedNode.isValid())
+ nodeList.append(selectedNode);
+ }
+ break;
+ case RemoveFromSelection: {
+ nodeList.append(m_oldSelectionList);
+ if (selectedNode.isValid())
+ nodeList.removeAll(selectedNode);
+ }
+ break;
+ case InvertSelection: {
+ if (selectedNode.isValid()
+ && !m_oldSelectionList.contains(selectedNode))
+ nodeList.append(selectedNode);
+ }
+ }
+
+ m_editorView->setSelectedQmlItemNodes(nodeList);
+}
+
+
+bool SingleSelectionManipulator::isActive() const
+{
+ return m_isActive;
+}
+
+QPointF SingleSelectionManipulator::beginPoint() const
+{
+ return m_beginPoint;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h
new file mode 100644
index 0000000000..a97abaa145
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/singleselectionmanipulator.h
@@ -0,0 +1,72 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SINGLESELECTIONMANIPULATOR_H
+#define SINGLESELECTIONMANIPULATOR_H
+
+#include "selectionrectangle.h"
+#include "formeditorview.h"
+
+namespace QmlDesigner {
+
+class SingleSelectionManipulator
+{
+public:
+ SingleSelectionManipulator(FormEditorView *editorView);
+
+// void setItems(const QList<FormEditorItem*> &itemList);
+
+ enum SelectionType {
+ ReplaceSelection,
+ AddToSelection,
+ RemoveFromSelection,
+ InvertSelection
+ };
+
+ void begin(const QPointF& beginPoint);
+ void update(const QPointF& updatePoint);
+ void end(const QPointF& updatePoint);
+
+ void select(SelectionType selectionType);
+
+ void clear();
+
+ QPointF beginPoint() const;
+
+ bool isActive() const;
+
+private:
+ QList<QmlItemNode> m_oldSelectionList;
+ QPointF m_beginPoint;
+ FormEditorView *m_editorView;
+ bool m_isActive;
+};
+
+}
+#endif // SINGLESELECTIONMANIPULATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/snapper.cpp b/src/plugins/qmldesigner/components/formeditor/snapper.cpp
new file mode 100644
index 0000000000..506146836c
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/snapper.cpp
@@ -0,0 +1,626 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "snapper.h"
+
+#include <QtDebug>
+
+#include <limits>
+#include <cmath>
+#include <QLineF>
+#include <QPen>
+#include <QApplication>
+
+namespace QmlDesigner {
+
+Snapper::Snapper()
+ : m_containerFormEditorItem(0),
+ m_transformtionSpaceFormEditorItem(0),
+ m_snappingDistance(5.0)
+{
+}
+
+void Snapper::updateSnappingLines(const QList<FormEditorItem*> &exceptionList)
+{
+ if (m_containerFormEditorItem)
+ m_containerFormEditorItem->updateSnappingLines(exceptionList, m_transformtionSpaceFormEditorItem);
+}
+
+void Snapper::updateSnappingLines(FormEditorItem* exceptionItem)
+{
+ QList<FormEditorItem*> exceptionList;
+ exceptionList.append(exceptionItem);
+ updateSnappingLines(exceptionList);
+}
+
+
+void Snapper::setContainerFormEditorItem(FormEditorItem *formEditorItem)
+{
+ m_containerFormEditorItem = formEditorItem;
+}
+
+
+void Snapper::setTransformtionSpaceFormEditorItem(FormEditorItem *formEditorItem)
+{
+ m_transformtionSpaceFormEditorItem = formEditorItem;
+}
+
+FormEditorItem *Snapper::transformtionSpaceFormEditorItem() const
+{
+ return m_transformtionSpaceFormEditorItem;
+}
+
+double Snapper::snappedVerticalOffset(const QRectF &boundingRect) const
+{
+ double offset = std::numeric_limits<double>::max();
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->leftSnappingLines(),
+ boundingRect.left()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->rightSnappingOffsets(),
+ Qt::Vertical,
+ boundingRect.left(),
+ boundingRect.top(),
+ boundingRect.bottom()));
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->rightSnappingLines(),
+ boundingRect.right()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->leftSnappingOffsets(),
+ Qt::Vertical,
+ boundingRect.right(),
+ boundingRect.top(),
+ boundingRect.bottom()));
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->verticalCenterSnappingLines(),
+ boundingRect.center().x()));
+
+ return offset;
+}
+
+double Snapper::snappedHorizontalOffset(const QRectF &boundingRect) const
+{
+ double offset = std::numeric_limits<double>::max();
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->topSnappingLines(),
+ boundingRect.top()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->bottomSnappingOffsets(),
+ Qt::Horizontal,
+ boundingRect.top(),
+ boundingRect.left(),
+ boundingRect.right()));
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->bottomSnappingLines(),
+ boundingRect.bottom()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->topSnappingOffsets(),
+ Qt::Horizontal,
+ boundingRect.bottom(),
+ boundingRect.left(),
+ boundingRect.right()));
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->horizontalCenterSnappingLines(),
+ boundingRect.center().y()));
+ return offset;
+}
+
+
+double Snapper::snapTopOffset(const QRectF &boundingRect) const
+{
+ double offset = std::numeric_limits<double>::max();
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->topSnappingLines(),
+ boundingRect.top()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->bottomSnappingOffsets(),
+ Qt::Horizontal,
+ boundingRect.top(),
+ boundingRect.left(),
+ boundingRect.right()));
+ return offset;
+}
+
+double Snapper::snapRightOffset(const QRectF &boundingRect) const
+{
+ double offset = std::numeric_limits<double>::max();
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->rightSnappingLines(),
+ boundingRect.right()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->leftSnappingOffsets(),
+ Qt::Vertical,
+ boundingRect.right(),
+ boundingRect.top(),
+ boundingRect.bottom()));
+ return offset;
+}
+
+double Snapper::snapLeftOffset(const QRectF &boundingRect) const
+{
+ double offset = std::numeric_limits<double>::max();
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->leftSnappingLines(),
+ boundingRect.left()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->rightSnappingOffsets(),
+ Qt::Vertical,
+ boundingRect.left(),
+ boundingRect.top(),
+ boundingRect.bottom()));
+ return offset;
+}
+
+double Snapper::snapBottomOffset(const QRectF &boundingRect) const
+{
+ double offset = std::numeric_limits<double>::max();
+
+ offset = qMin(offset, snappedOffsetForLines(containerFormEditorItem()->bottomSnappingLines(),
+ boundingRect.bottom()));
+
+ offset = qMin(offset, snappedOffsetForOffsetLines(containerFormEditorItem()->topSnappingOffsets(),
+ Qt::Horizontal,
+ boundingRect.bottom(),
+ boundingRect.left(),
+ boundingRect.right()));
+ return offset;
+
+}
+
+
+QList<QLineF> Snapper::verticalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects) const
+{
+ QList<QLineF> lineList = findSnappingLines(containerFormEditorItem()->leftSnappingLines(),
+ Qt::Vertical,
+ boundingRect.left(),
+ boundingRect.top(),
+ boundingRect.bottom(),
+ boundingRects);
+
+ lineList += findSnappingOffsetLines(containerFormEditorItem()->rightSnappingOffsets(),
+ Qt::Vertical,
+ boundingRect.left(),
+ boundingRect.top(),
+ boundingRect.bottom(),
+ boundingRects);
+
+
+ lineList += findSnappingLines(containerFormEditorItem()->rightSnappingLines(),
+ Qt::Vertical,
+ boundingRect.right(),
+ boundingRect.top(),
+ boundingRect.bottom(),
+ boundingRects);
+
+ lineList += findSnappingOffsetLines(containerFormEditorItem()->leftSnappingOffsets(),
+ Qt::Vertical,
+ boundingRect.right(),
+ boundingRect.top(),
+ boundingRect.bottom(),
+ boundingRects);
+
+ lineList += findSnappingLines(containerFormEditorItem()->verticalCenterSnappingLines(),
+ Qt::Vertical,
+ boundingRect.center().x(),
+ boundingRect.top(),
+ boundingRect.bottom(),
+ boundingRects);
+
+ return lineList;
+}
+
+QList<QLineF> Snapper::horizontalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects) const
+{
+ QList<QLineF> lineList = findSnappingLines(containerFormEditorItem()->topSnappingLines(),
+ Qt::Horizontal,
+ boundingRect.top(),
+ boundingRect.left(),
+ boundingRect.right());
+
+ lineList += findSnappingOffsetLines(containerFormEditorItem()->bottomSnappingOffsets(),
+ Qt::Horizontal,
+ boundingRect.top(),
+ boundingRect.left(),
+ boundingRect.right(),
+ boundingRects);
+
+
+ lineList += findSnappingLines(containerFormEditorItem()->bottomSnappingLines(),
+ Qt::Horizontal,
+ boundingRect.bottom(),
+ boundingRect.left(),
+ boundingRect.right(),
+ boundingRects);
+
+ lineList += findSnappingOffsetLines(containerFormEditorItem()->topSnappingOffsets(),
+ Qt::Horizontal,
+ boundingRect.bottom(),
+ boundingRect.left(),
+ boundingRect.right(),
+ boundingRects);
+
+ lineList += findSnappingLines(containerFormEditorItem()->horizontalCenterSnappingLines(),
+ Qt::Horizontal,
+ boundingRect.center().y(),
+ boundingRect.left(),
+ boundingRect.right(),
+ boundingRects);
+
+ return lineList;
+}
+
+
+
+FormEditorItem *Snapper::containerFormEditorItem() const
+{
+ return m_containerFormEditorItem;
+}
+
+QLineF Snapper::createSnapLine(Qt::Orientation orientation,
+ double snapLine,
+ double lowerLimit,
+ double upperLimit,
+ const QRectF &itemRect) const
+{
+ if (orientation == Qt::Horizontal) {
+ double lowerX(qMin(lowerLimit, itemRect.left()));
+ double upperX(qMax(upperLimit, itemRect.right()));
+ return QLineF(lowerX, snapLine, upperX, snapLine);
+ } else {
+ double lowerY(qMin(lowerLimit, itemRect.top()));
+ double upperY(qMax(upperLimit, itemRect.bottom()));
+ return QLineF(snapLine, lowerY, snapLine, upperY);
+ }
+}
+
+static bool compareLines(double snapLine, double lineToSnap)
+{
+// if (qAbs(snapLine - lineToSnap) < 1.0)
+// return true;
+//
+// return false;
+ return qFuzzyCompare(snapLine, lineToSnap);
+}
+
+QList<QLineF> Snapper::findSnappingLines(const SnapLineMap &snappingLineMap,
+ Qt::Orientation orientation,
+ double snapLine,
+ double lowerLimit,
+ double upperLimit,
+ QList<QRectF> *boundingRects) const
+{
+ QList<QLineF> lineList;
+
+ SnapLineMapIterator snappingLineIterator(snappingLineMap);
+ while (snappingLineIterator.hasNext()) {
+ snappingLineIterator.next();
+
+ if (compareLines(snapLine, snappingLineIterator.key())) { // near distance snapping lines
+ lineList += createSnapLine(orientation,
+ snappingLineIterator.key(),
+ lowerLimit,
+ upperLimit,
+ snappingLineIterator.value().first);
+ if (boundingRects != 0)
+ boundingRects->append(snappingLineIterator.value().first);
+ }
+ }
+
+ return lineList;
+}
+
+
+QList<QLineF> Snapper::findSnappingOffsetLines(const SnapLineMap &snappingOffsetMap,
+ Qt::Orientation orientation,
+ double snapLine,
+ double lowerLimit,
+ double upperLimit,
+ QList<QRectF> *boundingRects) const
+{
+ QList<QLineF> lineList;
+
+ SnapLineMapIterator snappingOffsetIterator(snappingOffsetMap);
+ while (snappingOffsetIterator.hasNext()) {
+ snappingOffsetIterator.next();
+
+ const QRectF &formEditorItemRect(snappingOffsetIterator.value().first);
+ double formEditorItemRectLowerLimit;
+ double formEditorItemRectUpperLimit;
+ if (orientation == Qt::Horizontal) {
+ formEditorItemRectLowerLimit = formEditorItemRect.left();
+ formEditorItemRectUpperLimit = formEditorItemRect.right();
+ } else {
+ formEditorItemRectLowerLimit = formEditorItemRect.top();
+ formEditorItemRectUpperLimit = formEditorItemRect.bottom();
+ }
+
+
+ if (qFuzzyCompare(snapLine, snappingOffsetIterator.key()) &&
+ !(lowerLimit > formEditorItemRectUpperLimit ||
+ upperLimit < formEditorItemRectLowerLimit)) {
+ lineList += createSnapLine(orientation,
+ snapLine,
+ lowerLimit,
+ upperLimit,
+ formEditorItemRect);
+ if (boundingRects != 0)
+ boundingRects->append(snappingOffsetIterator.value().first);
+ }
+ }
+
+
+ return lineList;
+}
+
+double Snapper::snappedOffsetForLines(const SnapLineMap &snappingLineMap,
+ double value) const
+{
+ QMultiMap<double, double> minimumSnappingLineMap;
+
+ SnapLineMapIterator snappingLineIterator(snappingLineMap);
+ while (snappingLineIterator.hasNext()) {
+ snappingLineIterator.next();
+ double snapLine = snappingLineIterator.key();
+ double offset = value - snapLine;
+ double distance = qAbs(offset);
+
+ if (distance < snappingDistance()) {
+ minimumSnappingLineMap.insert(distance, offset);
+ }
+ }
+
+ if (!minimumSnappingLineMap.isEmpty()) {
+ return minimumSnappingLineMap.begin().value();
+ }
+
+ return std::numeric_limits<double>::max();
+}
+
+
+double Snapper::snappedOffsetForOffsetLines(const SnapLineMap &snappingOffsetMap,
+ Qt::Orientation orientation,
+ double value,
+ double lowerLimit,
+ double upperLimit) const
+{
+ QMultiMap<double, double> minimumSnappingLineMap;
+
+ SnapLineMapIterator snappingOffsetIterator(snappingOffsetMap);
+ while (snappingOffsetIterator.hasNext()) {
+ snappingOffsetIterator.next();
+ double snapLine = snappingOffsetIterator.key();
+ const QRectF &formEditorItemRect(snappingOffsetIterator.value().first);
+ double formEditorItemRectLowerLimit;
+ double formEditorItemRectUpperLimit;
+ if (orientation == Qt::Horizontal) {
+ formEditorItemRectLowerLimit = formEditorItemRect.left();
+ formEditorItemRectUpperLimit = formEditorItemRect.right();
+ } else {
+ formEditorItemRectLowerLimit = formEditorItemRect.top();
+ formEditorItemRectUpperLimit = formEditorItemRect.bottom();
+ }
+
+ double offset = value - snapLine;
+ double distance = qAbs(offset);
+
+ if (distance < snappingDistance() &&
+ !(lowerLimit > formEditorItemRectUpperLimit ||
+ upperLimit < formEditorItemRectLowerLimit)) {
+
+ minimumSnappingLineMap.insert(distance, offset);
+ }
+ }
+
+ if (!minimumSnappingLineMap.isEmpty()) {
+ return minimumSnappingLineMap.begin().value();
+ }
+
+ return std::numeric_limits<double>::max();
+}
+
+
+void Snapper::setSnappingDistance(double snappingDistance)
+{
+ m_snappingDistance = snappingDistance;
+}
+
+double Snapper::snappingDistance() const
+{
+ return m_snappingDistance;
+}
+
+static bool lineXLessThan(const QLineF &firstLine, const QLineF &secondLine)
+{
+ return firstLine.x1() < secondLine.x2();
+}
+
+static bool lineYLessThan(const QLineF &firstLine, const QLineF &secondLine)
+{
+ return firstLine.y1() < secondLine.y2();
+}
+
+
+static QLineF mergedHorizontalLine(const QList<QLineF> &lineList)
+{
+ if (lineList.count() == 1)
+ return lineList.first();
+
+ double minimumX = std::numeric_limits<double>::max();
+ double maximumX = std::numeric_limits<double>::min();
+ foreach(const QLineF &line, lineList) {
+ minimumX = qMin(minimumX, line.x1());
+ minimumX = qMin(minimumX, line.x2());
+ maximumX = qMax(maximumX, line.x1());
+ maximumX = qMax(maximumX, line.x2());
+ }
+
+ double y(lineList.first().y1());
+ return QLineF(minimumX, y, maximumX, y);;
+}
+
+static QLineF mergedVerticalLine(const QList<QLineF> &lineList)
+{
+ if (lineList.count() == 1)
+ return lineList.first();
+
+ double minimumY = std::numeric_limits<double>::max();
+ double maximumY = std::numeric_limits<double>::min();
+ foreach(const QLineF &line, lineList) {
+ minimumY = qMin(minimumY, line.y1());
+ minimumY = qMin(minimumY, line.y2());
+ maximumY = qMax(maximumY, line.y1());
+ maximumY = qMax(maximumY, line.y2());
+ }
+
+ double x(lineList.first().x1());
+ return QLineF(x, minimumY, x, maximumY);;
+}
+
+static QList<QLineF> mergedHorizontalLines(const QList<QLineF> &lineList)
+{
+ QList<QLineF> mergedLineList;
+
+ QList<QLineF> sortedLineList(lineList);
+ qSort(sortedLineList.begin(), sortedLineList.end(), lineYLessThan);
+
+ QList<QLineF> lineWithTheSameY;
+ QListIterator<QLineF> sortedLineListIterator(sortedLineList);
+ while (sortedLineListIterator.hasNext()) {
+ QLineF line = sortedLineListIterator.next();
+ lineWithTheSameY.append(line);
+
+ if (sortedLineListIterator.hasNext()) {
+ QLineF nextLine = sortedLineListIterator.peekNext();
+ if (!qFuzzyCompare(line.y1(), nextLine.y1())) {
+ mergedLineList.append(mergedHorizontalLine(lineWithTheSameY));
+ lineWithTheSameY.clear();
+ }
+ } else {
+ mergedLineList.append(mergedHorizontalLine(lineWithTheSameY));
+ }
+ }
+
+ return mergedLineList;
+}
+
+
+
+
+
+
+static QList<QLineF> mergedVerticalLines(const QList<QLineF> &lineList)
+{
+ QList<QLineF> mergedLineList;
+
+ QList<QLineF> sortedLineList(lineList);
+ qSort(sortedLineList.begin(), sortedLineList.end(), lineXLessThan);
+
+ QList<QLineF> lineWithTheSameX;
+ QListIterator<QLineF> sortedLineListIterator(sortedLineList);
+ while (sortedLineListIterator.hasNext()) {
+ QLineF line = sortedLineListIterator.next();
+ lineWithTheSameX.append(line);
+
+ if (sortedLineListIterator.hasNext()) {
+ QLineF nextLine = sortedLineListIterator.peekNext();
+ if (!qFuzzyCompare(line.x1(), nextLine.x1())) {
+ mergedLineList.append(mergedVerticalLine(lineWithTheSameX));
+ lineWithTheSameX.clear();
+ }
+ } else {
+ mergedLineList.append(mergedVerticalLine(lineWithTheSameX));
+ }
+ }
+
+ return mergedLineList;
+}
+
+QList<QGraphicsItem*> Snapper::generateSnappingLines(const QRectF &boundingRect,
+ QGraphicsItem *layerItem,
+ const QTransform &transform)
+{
+ QList<QRectF> boundingRectList;
+ boundingRectList.append(boundingRect);
+
+ return generateSnappingLines(boundingRectList, layerItem, transform);
+}
+
+static void alignLine(QLineF &line)
+{
+ line.setP1(QPointF(std::floor(line.p1().x()) + 0.5,
+ std::floor(line.p1().y()) + 0.5));
+ line.setP2(QPointF(std::floor(line.p2().x()) + 0.5,
+ std::floor(line.p2().y()) + 0.5));
+}
+
+QList<QGraphicsItem*> Snapper::generateSnappingLines(const QList<QRectF> &boundingRectList,
+ QGraphicsItem *layerItem,
+ const QTransform &transform)
+{
+ QList<QGraphicsItem*> graphicsItemList;
+ QList<QLineF> lineList;
+ foreach(const QRectF &boundingRect, boundingRectList) {
+ QList<QRectF> snappedBoundingRectList;
+ lineList += mergedHorizontalLines(horizontalSnappedLines(boundingRect, &snappedBoundingRectList));
+ lineList += mergedVerticalLines(verticalSnappedLines(boundingRect, &snappedBoundingRectList));
+
+// snappedBoundingRectList.append(boundingRect);
+// foreach(const QRectF &snappedBoundingRect, snappedBoundingRectList) {
+// QPolygonF rect = transform.map(snappedBoundingRect);
+// alignVertices(rect);
+// QGraphicsPolygonItem * item = new QGraphicsPolygonItem(rect, layerItem);
+// item->setZValue(20);
+
+// QColor brushColor(QApplication::palette().highlight().color());
+// QColor brushColor(Qt::gray);
+// brushColor.setAlphaF(0.25);
+// QBrush brush(brushColor);
+// item->setBrush(brush);
+// item->setPen(Qt::NoPen);
+// graphicsItemList.append(item);
+// }
+ }
+
+ foreach(const QLineF &line, lineList) {
+ QLineF lineInTransformationSpace = transform.map(line);
+ alignLine(lineInTransformationSpace);
+ QGraphicsLineItem * lineItem = new QGraphicsLineItem(lineInTransformationSpace, layerItem);
+ lineItem->setZValue(40);
+ QPen linePen;
+// linePen.setStyle(Qt::DashLine);
+ linePen.setColor("#5d2dd7");
+ lineItem->setPen(linePen);
+
+ graphicsItemList.append(lineItem);
+ }
+
+ return graphicsItemList;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/snapper.h b/src/plugins/qmldesigner/components/formeditor/snapper.h
new file mode 100644
index 0000000000..a176b4e6e1
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/snapper.h
@@ -0,0 +1,112 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SNAPPER_H
+#define SNAPPER_H
+
+#include "formeditoritem.h"
+
+class QLineF;
+
+namespace QmlDesigner {
+
+
+class Snapper
+{
+public:
+ Snapper();
+
+ void setContainerFormEditorItem(FormEditorItem *formEditorItem);
+ FormEditorItem *containerFormEditorItem() const;
+
+ void setTransformtionSpaceFormEditorItem(FormEditorItem *formEditorItem);
+ FormEditorItem *transformtionSpaceFormEditorItem() const;
+
+ double snappedVerticalOffset(const QRectF &boundingRect) const;
+ double snappedHorizontalOffset(const QRectF &boundingRect) const;
+
+ double snapTopOffset(const QRectF &boundingRect) const;
+ double snapRightOffset(const QRectF &boundingRect) const;
+ double snapLeftOffset(const QRectF &boundingRect) const;
+ double snapBottomOffset(const QRectF &boundingRect) const;
+
+ QList<QLineF> horizontalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects = 0) const;
+ QList<QLineF> verticalSnappedLines(const QRectF &boundingRect, QList<QRectF> *boundingRects = 0) const;
+
+ void setSnappingDistance(double snappingDistance);
+ double snappingDistance() const;
+
+ void updateSnappingLines(const QList<FormEditorItem*> &exceptionList);
+ void updateSnappingLines(FormEditorItem* exceptionItem);
+
+ QList<QGraphicsItem*> generateSnappingLines(const QList<QRectF> &boundingRectList,
+ QGraphicsItem *layerItem,
+ const QTransform &transform);
+ QList<QGraphicsItem*> generateSnappingLines(const QRectF &boundingRect,
+ QGraphicsItem *layerItem,
+ const QTransform &transform);
+protected:
+ double snappedOffsetForLines(const SnapLineMap &snappingLineMap,
+ double value) const;
+
+ double snappedOffsetForOffsetLines(const SnapLineMap &snappingOffsetMap,
+ Qt::Orientation orientation,
+ double value,
+ double lowerLimit,
+ double upperLimit) const;
+
+ QList<QLineF> findSnappingLines(const SnapLineMap &snappingLineMap,
+ Qt::Orientation orientation,
+ double snapLine,
+ double lowerLimit,
+ double upperLimit,
+ QList<QRectF> *boundingRects = 0) const;
+
+ QList<QLineF> findSnappingOffsetLines(const SnapLineMap &snappingOffsetMap,
+ Qt::Orientation orientation,
+ double snapLine,
+ double lowerLimit,
+ double upperLimit,
+ QList<QRectF> *boundingRects = 0) const;
+
+ QLineF createSnapLine(Qt::Orientation orientation,
+ double snapLine,
+ double lowerEdge,
+ double upperEdge,
+ const QRectF &itemRect) const;
+
+// bool canSnap(QList<double> snappingLineList, double value) const;
+private:
+ FormEditorItem *m_containerFormEditorItem;
+ FormEditorItem *m_transformtionSpaceFormEditorItem;
+ double m_snappingDistance;
+};
+
+}
+#endif // SNAPPER_H
diff --git a/src/plugins/qmldesigner/components/formeditor/snapping.png b/src/plugins/qmldesigner/components/formeditor/snapping.png
new file mode 100644
index 0000000000..ceee8b94bb
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/snapping.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp
new file mode 100644
index 0000000000..7c3b9e36a3
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.cpp
@@ -0,0 +1,190 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "snappinglinecreator.h"
+
+#include <QGraphicsItem>
+#include "onedimensionalcluster.h"
+#include "formeditoritem.h"
+#include "formeditorview.h"
+
+namespace QmlDesigner {
+
+SnappingLineCreator::SnappingLineCreator(FormEditorItem *formEditorItem)
+ : m_formEditorItem(formEditorItem),
+ m_topOffset(formEditorItem->formEditorView()->spacing()),
+ m_bottomOffset(formEditorItem->formEditorView()->spacing()),
+ m_leftOffset(formEditorItem->formEditorView()->spacing()),
+ m_rightOffset(formEditorItem->formEditorView()->spacing()),
+ m_topMargin(formEditorItem->formEditorView()->margins()),
+ m_bottomMargin(formEditorItem->formEditorView()->margins()),
+ m_leftMargin(formEditorItem->formEditorView()->margins()),
+ m_rightMargin(formEditorItem->formEditorView()->margins())
+{
+ Q_ASSERT(m_formEditorItem);
+}
+
+void SnappingLineCreator::clearLines()
+{
+ m_topLineMap.clear();
+ m_bottomLineMap.clear();
+ m_leftLineMap.clear();
+ m_rightLineMap.clear();
+ m_horizontalCenterLineMap.clear();
+ m_verticalCenterLineMap.clear();
+
+ m_topOffsetMap.clear();
+ m_bottomOffsetMap.clear();
+ m_leftOffsetMap.clear();
+ m_rightOffsetMap.clear();
+
+}
+
+void SnappingLineCreator::addLines(const QRectF &rectInSceneSpace, FormEditorItem *item)
+{
+ m_topLineMap.insert(rectInSceneSpace.top(), qMakePair(rectInSceneSpace, item));
+ m_bottomLineMap.insert(rectInSceneSpace.bottom(), qMakePair(rectInSceneSpace, item));
+ m_leftLineMap.insert(rectInSceneSpace.left(), qMakePair(rectInSceneSpace, item));
+ m_rightLineMap.insert(rectInSceneSpace.right(), qMakePair(rectInSceneSpace, item));
+ QPointF centerPoint(rectInSceneSpace.center());
+ m_horizontalCenterLineMap.insert(centerPoint.y(), qMakePair(rectInSceneSpace, item));
+ m_verticalCenterLineMap.insert(centerPoint.x(), qMakePair(rectInSceneSpace, item));
+}
+
+void SnappingLineCreator::addOffsets(const QRectF &rectInSceneSpace, FormEditorItem *item)
+{
+ m_topOffsetMap.insert(rectInSceneSpace.top() - m_topOffset, qMakePair(rectInSceneSpace, item));
+ m_bottomOffsetMap.insert(rectInSceneSpace.bottom() + m_bottomOffset, qMakePair(rectInSceneSpace, item));
+ m_leftOffsetMap.insert(rectInSceneSpace.left() - m_leftOffset, qMakePair(rectInSceneSpace, item));
+ m_rightOffsetMap.insert(rectInSceneSpace.right() + m_rightOffset, qMakePair(rectInSceneSpace, item));
+}
+
+void SnappingLineCreator::generateLines(const QList<FormEditorItem*> &exceptionList,
+ FormEditorItem *transformationSpaceItem)
+{
+ Q_ASSERT(transformationSpaceItem);
+ {
+ QRectF containerBoundingRectInTransformationSpace = m_formEditorItem->mapRectToItem(transformationSpaceItem,
+ m_formEditorItem->boundingRect());
+
+ addLines(containerBoundingRectInTransformationSpace, m_formEditorItem);
+ containerBoundingRectInTransformationSpace.adjust(m_leftMargin, m_topMargin, -m_rightMargin, -m_rightMargin);
+ addLines(containerBoundingRectInTransformationSpace, m_formEditorItem);
+ }
+
+ foreach (FormEditorItem *item, m_formEditorItem->childFormEditorItems()) {
+ if (exceptionList.contains(item))
+ continue;
+ QRectF boundingRectInContainerSpace;
+
+ boundingRectInContainerSpace = item->mapRectToItem(transformationSpaceItem, item->boundingRect());
+
+ boundingRectInContainerSpace = boundingRectInContainerSpace.toRect(); // round to integer
+
+ addLines(boundingRectInContainerSpace, item);
+ addOffsets(boundingRectInContainerSpace, item);
+ }
+}
+
+void SnappingLineCreator::setMargins(double margin)
+{
+ m_topMargin = margin;
+ m_bottomMargin = margin;
+ m_leftMargin = margin;
+ m_rightMargin = margin;
+}
+
+void SnappingLineCreator::setSpacing(double spacing)
+{
+ m_topOffset = spacing;
+ m_bottomOffset = spacing;
+ m_leftOffset = spacing;
+ m_rightOffset = spacing;
+}
+
+void SnappingLineCreator::update(const QList<FormEditorItem*> &exceptionList,
+ FormEditorItem *transformationSpaceItem)
+{
+ clearLines();
+ setMargins(m_formEditorItem->formEditorView()->margins());
+ setSpacing(m_formEditorItem->formEditorView()->spacing());
+ generateLines(exceptionList, transformationSpaceItem);
+}
+
+SnapLineMap SnappingLineCreator::topLines() const
+{
+ return m_topLineMap;
+}
+
+SnapLineMap SnappingLineCreator::bottomLines() const
+{
+ return m_bottomLineMap;
+}
+
+SnapLineMap SnappingLineCreator::leftLines() const
+{
+ return m_leftLineMap;
+}
+
+SnapLineMap SnappingLineCreator::rightLines() const
+{
+ return m_rightLineMap;
+}
+
+SnapLineMap SnappingLineCreator::horizontalCenterLines() const
+{
+ return m_horizontalCenterLineMap;
+}
+
+SnapLineMap SnappingLineCreator::verticalCenterLines() const
+{
+ return m_verticalCenterLineMap;
+}
+
+SnapLineMap SnappingLineCreator::topOffsets() const
+{
+ return m_topOffsetMap;
+}
+
+SnapLineMap SnappingLineCreator::bottomOffsets() const
+{
+ return m_bottomOffsetMap;
+}
+
+SnapLineMap SnappingLineCreator::leftOffsets() const
+{
+ return m_leftOffsetMap;
+}
+
+SnapLineMap SnappingLineCreator::rightOffsets() const
+{
+ return m_rightOffsetMap;
+}
+
+}
diff --git a/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h
new file mode 100644
index 0000000000..7d8eb3b51b
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/snappinglinecreator.h
@@ -0,0 +1,102 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SNAPPINGLINECREATOR_H
+#define SNAPPINGLINECREATOR_H
+
+#include "layeritem.h"
+#include <QPair>
+
+namespace QmlDesigner {
+
+class FormEditorItem;
+
+typedef QMultiMap<double, QPair<QRectF, FormEditorItem*> > SnapLineMap;
+typedef QMapIterator<double, QPair<QRectF, FormEditorItem*> > SnapLineMapIterator;
+
+class FormEditorItem;
+
+class SnappingLineCreator
+{
+public:
+ SnappingLineCreator(FormEditorItem *formEditorItem);
+
+ void update(const QList<FormEditorItem*> &exceptionList,
+ FormEditorItem *transformationSpaceItem);
+
+
+ SnapLineMap topLines() const;
+ SnapLineMap bottomLines() const;
+ SnapLineMap leftLines() const;
+ SnapLineMap rightLines() const;
+ SnapLineMap horizontalCenterLines() const;
+ SnapLineMap verticalCenterLines() const;
+
+ SnapLineMap topOffsets() const;
+ SnapLineMap bottomOffsets() const;
+ SnapLineMap leftOffsets() const;
+ SnapLineMap rightOffsets() const;
+
+ void setMargins(double margin);
+ void setSpacing(double spacing);
+
+protected:
+ void addLines(const QRectF &rectInSceneSpace, FormEditorItem *item);
+ void addOffsets(const QRectF &rectInSceneSpace, FormEditorItem *item);
+
+ void clearLines();
+ void generateLines(const QList<FormEditorItem*> &exceptionList,
+ FormEditorItem *transformationSpaceItem);
+
+private:
+ SnapLineMap m_topLineMap;
+ SnapLineMap m_bottomLineMap;
+ SnapLineMap m_leftLineMap;
+ SnapLineMap m_rightLineMap;
+ SnapLineMap m_horizontalCenterLineMap;
+ SnapLineMap m_verticalCenterLineMap;
+
+ SnapLineMap m_topOffsetMap;
+ SnapLineMap m_bottomOffsetMap;
+ SnapLineMap m_leftOffsetMap;
+ SnapLineMap m_rightOffsetMap;
+
+ FormEditorItem *m_formEditorItem;
+ double m_topOffset;
+ double m_bottomOffset;
+ double m_leftOffset;
+ double m_rightOffset;
+ double m_topMargin;
+ double m_bottomMargin;
+ double m_leftMargin;
+ double m_rightMargin;
+};
+
+}
+#endif // SNAPPINGLINECREATOR_H
diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
new file mode 100644
index 0000000000..04d4486b78
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
@@ -0,0 +1,81 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "toolbox.h"
+
+#include <QToolBar>
+#include <QHBoxLayout>
+#include <QPainter>
+#include <QtDebug>
+#include <QFile>
+
+namespace QmlDesigner {
+
+ToolBox::ToolBox(QWidget *parentWidget)
+ : QWidget(parentWidget),
+ m_toolBar(new QToolBar("Sidebar", this))
+{
+ QHBoxLayout *fillLayout = new QHBoxLayout(this);
+ fillLayout->setMargin(0);
+ setLayout(fillLayout);
+ //setContentsMargins(4, 12, 4, 4);
+
+ m_toolBar->setFloatable(true);
+ m_toolBar->setMovable(true);
+ m_toolBar->setOrientation(Qt::Horizontal);
+ m_toolBar->setIconSize(QSize(24, 24));
+ fillLayout->addWidget(m_toolBar);
+
+
+// QPalette toolPalette(palette());
+// QColor newColor(palette().color(QPalette::Window));
+// newColor.setAlphaF(0.7);
+// toolPalette.setColor(QPalette::Window, newColor);
+// setPalette(toolPalette);
+// setBackgroundRole(QPalette::Window);
+// setAutoFillBackground(true);
+// setAttribute(Qt::WA_NoSystemBackground, true);
+
+}
+
+
+
+void ToolBox::setActions(const QList<QAction*> &actions)
+{
+ m_toolBar->clear();
+ m_toolBar->addActions(actions);
+ resize(sizeHint());
+}
+
+void ToolBox::addAction(QAction *action)
+{
+ m_toolBar->addAction(action);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.h b/src/plugins/qmldesigner/components/formeditor/toolbox.h
new file mode 100644
index 0000000000..98fed3a271
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/toolbox.h
@@ -0,0 +1,52 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef TOOLBOX_H
+#define TOOLBOX_H
+
+#include <QWidget>
+
+class QToolBar;
+
+namespace QmlDesigner {
+
+class ToolBox : public QWidget
+{
+public:
+ ToolBox(QWidget *parentWidget);
+ void setActions(const QList<QAction*> &actions);
+ void addAction(QAction *action);
+
+private:
+ QToolBar *m_toolBar;
+};
+
+} // namespace QmlDesigner
+
+#endif // TOOLBOX_H
diff --git a/src/plugins/qmldesigner/components/formeditor/transform.png b/src/plugins/qmldesigner/components/formeditor/transform.png
new file mode 100644
index 0000000000..e9e7662b3a
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/transform.png
Binary files differ
diff --git a/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp b/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp
new file mode 100644
index 0000000000..9a6560927f
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/zoomaction.cpp
@@ -0,0 +1,116 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "zoomaction.h"
+
+#include <QComboBox>
+#include <QLineEdit>
+#include <QEvent>
+#include <QCoreApplication>
+
+namespace QmlDesigner {
+
+
+ZoomAction::ZoomAction(QObject *parent)
+ : QWidgetAction(parent),
+ m_zoomLevel(1.0),
+ m_currentComboBoxIndex(-1)
+{
+
+}
+
+double ZoomAction::zoomLevel() const
+{
+ return m_zoomLevel;
+}
+
+void ZoomAction::zoomIn()
+{
+ if (m_currentComboBoxIndex > 0)
+ emit indexChanged(m_currentComboBoxIndex - 1);
+}
+
+void ZoomAction::zoomOut()
+{
+ if (m_currentComboBoxIndex < (m_comboBoxModel->rowCount() - 1))
+ emit indexChanged(m_currentComboBoxIndex + 1);
+}
+
+void ZoomAction::setZoomLevel(double zoomLevel)
+{
+ if (zoomLevel < .1) {
+ m_zoomLevel = 0.1;
+ } else if (zoomLevel > 16.0) {
+ m_zoomLevel = 16.0;
+ } else {
+ m_zoomLevel = zoomLevel;
+ }
+
+ emit zoomLevelChanged(m_zoomLevel);
+}
+
+
+QWidget *ZoomAction::createWidget(QWidget *parent)
+{
+ QComboBox *comboBox = new QComboBox(parent);
+
+ if (m_comboBoxModel.isNull()) {
+ m_comboBoxModel = comboBox->model();
+ comboBox->addItem("10 %", 0.1);
+ comboBox->addItem("25 %", 0.25);
+ comboBox->addItem("50 %", 0.5);
+ comboBox->addItem("100 %", 1.0);
+ comboBox->addItem("200 %", 2.0);
+ comboBox->addItem("400 %", 4.0);
+ comboBox->addItem("800 %", 8.0);
+ comboBox->addItem("1600 %", 16.0);
+
+ } else {
+ comboBox->setModel(m_comboBoxModel.data());
+ }
+
+ comboBox->setCurrentIndex(3);
+ connect(comboBox, SIGNAL(currentIndexChanged(int)), SLOT(emitZoomLevelChanged(int)));
+ connect(this, SIGNAL(indexChanged(int)), comboBox, SLOT(setCurrentIndex(int)));
+
+ return comboBox;
+}
+
+void ZoomAction::emitZoomLevelChanged(int index)
+{
+ m_currentComboBoxIndex = index;
+
+ if (index == -1)
+ return;
+
+ QModelIndex modelIndex(m_comboBoxModel.data()->index(index, 0));
+ setZoomLevel(m_comboBoxModel.data()->data(modelIndex, Qt::UserRole).toDouble());
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/formeditor/zoomaction.h b/src/plugins/qmldesigner/components/formeditor/zoomaction.h
new file mode 100644
index 0000000000..02ceb9acc0
--- /dev/null
+++ b/src/plugins/qmldesigner/components/formeditor/zoomaction.h
@@ -0,0 +1,68 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef ZOOMACTION_H
+#define ZOOMACTION_H
+
+#include <QWidgetAction>
+
+class QAbstractItemModel;
+
+namespace QmlDesigner {
+
+class ZoomAction : public QWidgetAction
+{
+ Q_OBJECT
+
+public:
+ ZoomAction(QObject *parent);
+
+ double zoomLevel() const;
+
+ void zoomIn();
+ void zoomOut();
+
+protected:
+ QWidget *createWidget(QWidget *parent);
+ void setZoomLevel(double zoomLevel);
+signals:
+ void zoomLevelChanged(double zoom);
+ void indexChanged(int);
+private slots:
+ void emitZoomLevelChanged(int index);
+
+private:
+ QWeakPointer<QAbstractItemModel> m_comboBoxModel;
+ double m_zoomLevel;
+ int m_currentComboBoxIndex;
+};
+
+} // namespace QmlDesigner
+
+#endif // ZOOMACTION_H