OSDN Git Service

Update license.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / components / formeditor / movemanipulator.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
8 **
9 **
10 ** GNU Lesser General Public License Usage
11 **
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 **
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 **
23 ** Other Usage
24 **
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **************************************************************************/
32
33 #include "movemanipulator.h"
34 #include "itemutilfunctions.h"
35 #include "layeritem.h"
36 #include "formeditoritem.h"
37 #include "formeditorscene.h"
38
39 #include <QPointF>
40 #include <QtDebug>
41 #include <QColor>
42 #include <QPen>
43 #include <QApplication>
44
45 #include <limits>
46 #include <model.h>
47 #include <qmlanchors.h>
48 #include <variantproperty.h>
49 #include <nodeabstractproperty.h>
50
51
52 namespace QmlDesigner {
53
54 MoveManipulator::MoveManipulator(LayerItem *layerItem, FormEditorView *view)
55     : m_layerItem(layerItem),
56     m_view(view),
57     m_isActive(false)
58 {
59 }
60
61 MoveManipulator::~MoveManipulator()
62 {
63     deleteSnapLines();
64 }
65
66 QPointF MoveManipulator::beginPoint() const
67 {
68     return m_beginPoint;
69 }
70
71 void MoveManipulator::setItem(FormEditorItem* item)
72 {
73     QList<FormEditorItem*> itemList;
74     itemList.append(item);
75
76     setItems(itemList);
77 }
78
79 void MoveManipulator::setItems(const QList<FormEditorItem*> &itemList)
80 {
81     m_itemList = itemList;
82     if (!m_itemList.isEmpty()) {
83         if (m_itemList.first()->parentItem())
84             m_snapper.setContainerFormEditorItem(m_itemList.first()->parentItem());
85         else
86             m_snapper.setContainerFormEditorItem(m_itemList.first());
87         m_snapper.setTransformtionSpaceFormEditorItem(m_snapper.containerFormEditorItem());
88     }
89 }
90
91 void MoveManipulator::updateHashes()
92 {
93 //    foreach (FormEditorItem* item, m_itemList)
94 //        m_beginItemRectHash[item] = item->mapRectToParent(item->qmlItemNode().instanceBoundingRect());
95
96     foreach (FormEditorItem* item, m_itemList) {
97         QPointF positionInParentSpace = m_snapper.containerFormEditorItem()->mapFromScene(m_beginPositionInSceneSpaceHash.value(item));
98         m_beginItemRectHash[item].translate(positionInParentSpace - m_beginPositionHash.value(item));
99         m_beginPositionHash.insert(item, positionInParentSpace);
100     }
101 }
102
103 bool MoveManipulator::itemsCanReparented() const
104 {
105     foreach (FormEditorItem* item, m_itemList) {
106         if (item
107             && item->qmlItemNode().isValid()
108             && !item->qmlItemNode().canReparent())
109             return false;
110     }
111
112     return true;
113 }
114
115 void MoveManipulator::begin(const QPointF &beginPoint)
116 {
117     m_isActive = true;
118
119     m_snapper.updateSnappingLines(m_itemList);
120
121
122     foreach (FormEditorItem* item, m_itemList) {
123         if (item && item->qmlItemNode().isValid())
124             m_beginItemRectHash.insert(item, m_snapper.containerFormEditorItem()->mapRectFromItem(item, item->qmlItemNode().instanceBoundingRect()));
125     }
126
127     foreach (FormEditorItem* item, m_itemList) {
128         if (item && item->qmlItemNode().isValid()) {
129             QPointF positionInParentSpace(item->qmlItemNode().instancePosition());
130             QPointF positionInScenesSpace = m_snapper.containerFormEditorItem()->mapToScene(positionInParentSpace);
131             m_beginPositionInSceneSpaceHash.insert(item, positionInScenesSpace);
132         }
133     }
134
135     foreach (FormEditorItem* item, m_itemList) {
136         if (item && item->qmlItemNode().isValid()) {
137             QPointF positionInParentSpace = m_snapper.containerFormEditorItem()->mapFromScene(m_beginPositionInSceneSpaceHash.value(item));
138             m_beginPositionHash.insert(item, positionInParentSpace);
139
140             QmlAnchors anchors(item->qmlItemNode().anchors());
141             m_beginTopMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Top));
142             m_beginLeftMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Left));
143             m_beginRightMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Right));
144             m_beginBottomMarginHash.insert(item, anchors.instanceMargin(AnchorLine::Bottom));
145             m_beginHorizontalCenterHash.insert(item, anchors.instanceMargin(AnchorLine::HorizontalCenter));
146             m_beginVerticalCenterHash.insert(item, anchors.instanceMargin(AnchorLine::VerticalCenter));
147         }
148     }
149
150     m_beginPoint = beginPoint;
151
152 //    setOpacityForAllElements(0.62);
153
154     m_rewriterTransaction = m_view->beginRewriterTransaction();
155 }
156
157
158
159
160
161 QPointF MoveManipulator::findSnappingOffset(const QHash<FormEditorItem*, QRectF> &boundingRectHash)
162 {
163     QPointF offset;
164
165     QMap<double, double> verticalOffsetMap;
166     QMap<double, double> horizontalOffsetMap;
167
168     QHashIterator<FormEditorItem*, QRectF> hashIterator(boundingRectHash);
169     while(hashIterator.hasNext()) {
170         hashIterator.next();
171         FormEditorItem *formEditorItem = hashIterator.key();
172         QRectF boundingRect = hashIterator.value();
173
174         if (!formEditorItem || !formEditorItem->qmlItemNode().isValid())
175             continue;
176
177         if (!formEditorItem->qmlItemNode().hasBindingProperty("x")) {
178             double verticalOffset = m_snapper.snappedVerticalOffset(boundingRect);
179             if (verticalOffset < std::numeric_limits<double>::max())
180                 verticalOffsetMap.insert(qAbs(verticalOffset), verticalOffset);
181         }
182
183         if (!formEditorItem->qmlItemNode().hasBindingProperty("y")) {
184             double horizontalOffset = m_snapper.snappedHorizontalOffset(boundingRect);
185             if (horizontalOffset < std::numeric_limits<double>::max())
186                 horizontalOffsetMap.insert(qAbs(horizontalOffset), horizontalOffset);
187         }
188     }
189
190
191     if (!verticalOffsetMap.isEmpty())
192         offset.rx() = verticalOffsetMap.begin().value();
193
194
195     if (!horizontalOffsetMap.isEmpty())
196         offset.ry() = horizontalOffsetMap.begin().value();
197
198     return offset;
199 }
200
201
202 void MoveManipulator::generateSnappingLines(const QHash<FormEditorItem*, QRectF> &boundingRectHash)
203 {
204     m_graphicsLineList = m_snapper.generateSnappingLines(boundingRectHash.values(),
205                                                          m_layerItem.data(),
206                                                          m_snapper.transformtionSpaceFormEditorItem()->sceneTransform());
207 }
208
209
210
211 QHash<FormEditorItem*, QRectF> MoveManipulator::tanslatedBoundingRects(const QHash<FormEditorItem*, QRectF> &boundingRectHash, const QPointF& offsetVector)
212 {
213     QHash<FormEditorItem*, QRectF> translatedBoundingRectHash;
214
215     QHashIterator<FormEditorItem*, QRectF> hashIterator(boundingRectHash);
216     while(hashIterator.hasNext()) {
217         QPointF alignedOffset(offsetVector);
218         hashIterator.next();
219         FormEditorItem *formEditorItem = hashIterator.key();
220         QRectF boundingRect = hashIterator.value();
221
222         if (!formEditorItem || !formEditorItem->qmlItemNode().isValid())
223             continue;
224
225         if (formEditorItem->qmlItemNode().hasBindingProperty("x"))
226             alignedOffset.setX(0);
227         if (formEditorItem->qmlItemNode().hasBindingProperty("y"))
228             alignedOffset.setY(0);
229         translatedBoundingRectHash.insert(formEditorItem, boundingRect.translated(offsetVector));
230     }
231
232     return translatedBoundingRectHash;
233 }
234
235
236
237 /*
238   /brief updates the position of the items.
239 */
240 void MoveManipulator::update(const QPointF& updatePoint, Snapping useSnapping, State stateToBeManipulated)
241 {
242     deleteSnapLines(); //Since they position is changed and the item is moved the snapping lines are
243                        //are obsolete. The new updated snapping lines (color and visibility) will be
244                        //calculated in snapPoint() called in moveNode() later
245
246     if (m_itemList.isEmpty()) {
247         return;
248     } else {
249         QPointF updatePointInContainerSpace(m_snapper.containerFormEditorItem()->mapFromScene(updatePoint));
250         QPointF beginPointInContainerSpace(m_snapper.containerFormEditorItem()->mapFromScene(m_beginPoint));
251
252         QPointF offsetVector(updatePointInContainerSpace - beginPointInContainerSpace);
253
254         if (useSnapping == UseSnappingAndAnchoring)
255         {
256
257         }
258
259         if (useSnapping == UseSnapping || useSnapping == UseSnappingAndAnchoring) {
260             offsetVector -= findSnappingOffset(tanslatedBoundingRects(m_beginItemRectHash, offsetVector));
261             generateSnappingLines(tanslatedBoundingRects(m_beginItemRectHash, offsetVector));
262         }
263
264         foreach (FormEditorItem* item, m_itemList) {
265             QPointF positionInContainerSpace(m_beginPositionHash.value(item) + offsetVector);
266
267             if (!item || !item->qmlItemNode().isValid())
268                 continue;
269
270             // don't support anchors for base state because it is not needed by the droptool
271             if (stateToBeManipulated == UseActualState) {
272                 QmlAnchors anchors(item->qmlItemNode().anchors());
273
274                 if (anchors.instanceHasAnchor(AnchorLine::Top)) {
275                     anchors.setMargin(AnchorLine::Top, m_beginTopMarginHash.value(item) + offsetVector.y());
276                 }
277
278                 if (anchors.instanceHasAnchor(AnchorLine::Left)) {
279                     anchors.setMargin(AnchorLine::Left, m_beginLeftMarginHash.value(item) + offsetVector.x());
280                 }
281
282                 if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
283                     anchors.setMargin(AnchorLine::Bottom, m_beginBottomMarginHash.value(item) - offsetVector.y());
284                 }
285
286                 if (anchors.instanceHasAnchor(AnchorLine::Right)) {
287                     anchors.setMargin(AnchorLine::Right, m_beginRightMarginHash.value(item) - offsetVector.x());
288                 }
289
290                 if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
291                     anchors.setMargin(AnchorLine::HorizontalCenter, m_beginHorizontalCenterHash.value(item) + offsetVector.x());
292                 }
293
294                 if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
295                     anchors.setMargin(AnchorLine::VerticalCenter, m_beginVerticalCenterHash.value(item) + offsetVector.y());
296                 }
297
298             setPosition(item->qmlItemNode(), positionInContainerSpace);
299             } else {
300                 item->qmlItemNode().modelNode().variantProperty("x").setValue(qRound(positionInContainerSpace.x()));
301                 item->qmlItemNode().modelNode().variantProperty("y").setValue(qRound(positionInContainerSpace.y()));
302             }
303         }
304     }
305 }
306
307 void MoveManipulator::clear()
308 {
309     deleteSnapLines();
310     m_beginItemRectHash.clear();
311     m_beginPositionHash.clear();
312     m_beginPositionInSceneSpaceHash.clear();
313     m_itemList.clear();
314
315     m_rewriterTransaction.commit();
316
317     m_beginTopMarginHash.clear();
318     m_beginLeftMarginHash.clear();
319     m_beginRightMarginHash.clear();
320     m_beginBottomMarginHash.clear();
321     m_beginHorizontalCenterHash.clear();
322     m_beginVerticalCenterHash.clear();
323 }
324
325 void MoveManipulator::reparentTo(FormEditorItem *newParent)
326 {
327     deleteSnapLines();
328
329     if (!newParent)
330         return;
331
332     if (!itemsCanReparented())
333         return;
334
335     foreach (FormEditorItem* item, m_itemList) {
336         if (!item || !item->qmlItemNode().isValid())
337             continue;
338
339         QmlItemNode parent(newParent->qmlItemNode());
340         if (parent.isValid()) {
341             if (parent.hasDefaultProperty())
342                 item->qmlItemNode().setParentProperty(parent.nodeAbstractProperty(parent.defaultProperty()));
343             else
344                 item->qmlItemNode().setParentProperty(parent.nodeAbstractProperty("data"));
345         }
346     }
347
348     if (m_view->model()) {
349         m_snapper.setContainerFormEditorItem(newParent);
350         m_snapper.setTransformtionSpaceFormEditorItem(m_snapper.containerFormEditorItem());
351         m_snapper.updateSnappingLines(m_itemList);
352         updateHashes();
353     }
354 }
355
356
357 void MoveManipulator::end(const QPointF &/*endPoint*/)
358 {
359     m_isActive = false;
360     deleteSnapLines();
361 //    setOpacityForAllElements(1.0);
362     clear();
363 }
364
365 void MoveManipulator::moveBy(double deltaX, double deltaY)
366 {
367     foreach (FormEditorItem* item, m_itemList) {
368         if (!item || !item->qmlItemNode().isValid())
369             continue;
370
371         QmlAnchors anchors(item->qmlItemNode().anchors());
372
373         if (anchors.instanceHasAnchor(AnchorLine::Top)) {
374             anchors.setMargin(AnchorLine::Top, anchors.instanceMargin(AnchorLine::Top) + deltaY);
375         }
376
377         if (anchors.instanceHasAnchor(AnchorLine::Left)) {
378             anchors.setMargin(AnchorLine::Left, anchors.instanceMargin(AnchorLine::Left) + deltaX);
379         }
380
381         if (anchors.instanceHasAnchor(AnchorLine::Bottom)) {
382             anchors.setMargin(AnchorLine::Bottom, anchors.instanceMargin(AnchorLine::Bottom) - deltaY);
383         }
384
385         if (anchors.instanceHasAnchor(AnchorLine::Right)) {
386             anchors.setMargin(AnchorLine::Right, anchors.instanceMargin(AnchorLine::Right) - deltaX);
387         }
388
389         if (anchors.instanceHasAnchor(AnchorLine::HorizontalCenter)) {
390             anchors.setMargin(AnchorLine::HorizontalCenter, anchors.instanceMargin(AnchorLine::HorizontalCenter) + deltaX);
391         }
392
393         if (anchors.instanceHasAnchor(AnchorLine::VerticalCenter)) {
394             anchors.setMargin(AnchorLine::VerticalCenter, anchors.instanceMargin(AnchorLine::VerticalCenter) + deltaY);
395         }
396
397         setPosition(item->qmlItemNode(), QPointF(item->qmlItemNode().instanceValue("x").toDouble() + deltaX,
398                                                   item->qmlItemNode().instanceValue("y").toDouble() + deltaY));
399     }
400 }
401
402 void MoveManipulator::beginRewriterTransaction()
403 {
404     m_rewriterTransaction = m_view->beginRewriterTransaction();
405 }
406
407 void MoveManipulator::endRewriterTransaction()
408 {
409     m_rewriterTransaction.commit();
410 }
411
412 void MoveManipulator::setOpacityForAllElements(qreal opacity)
413 {
414     foreach (FormEditorItem* item, m_itemList)
415         item->setOpacity(opacity);
416 }
417
418 void MoveManipulator::deleteSnapLines()
419 {
420     if (m_layerItem) {
421         foreach (QGraphicsItem *item, m_graphicsLineList) {
422             m_layerItem->scene()->removeItem(item);
423             delete item;
424         }
425     }
426     m_graphicsLineList.clear();
427     m_view->scene()->update();
428 }
429
430 bool MoveManipulator::isActive() const
431 {
432     return m_isActive;
433 }
434
435 void MoveManipulator::setPosition(QmlItemNode itemNode, const QPointF &position)
436 {
437     if (!itemNode.hasBindingProperty("x"))
438         itemNode.setVariantProperty("x", qRound(position.x()));
439
440     if (!itemNode.hasBindingProperty("y"))
441         itemNode.setVariantProperty("y", qRound(position.y()));
442 }
443
444 }