OSDN Git Service

cb9f0c88a6b34adfa46633124a47bbfdfb5200fb
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / instances / qmlgraphicsitemnodeinstance.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 (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "qmlgraphicsitemnodeinstance.h"
35
36 #include <invalidnodeinstanceexception.h>
37
38 #include "bindingproperty.h"
39 #include "variantproperty.h"
40
41 #include <QDeclarativeExpression>
42
43 #include <private/qdeclarativeanchors_p.h>
44 #include <private/qdeclarativeanchors_p_p.h>
45 #include <private/qdeclarativeitem_p.h>
46 #include <private/qdeclarativeproperty_p.h>
47 #include <private/qdeclarativerectangle_p.h>
48 #include <private/qdeclarativepositioners_p.h>
49 #include <private/qdeclarativestategroup_p.h>
50
51
52 #include <cmath>
53
54 #include <QHash>
55
56 namespace QmlDesigner {
57 namespace Internal {
58
59 QmlGraphicsItemNodeInstance::QmlGraphicsItemNodeInstance(QDeclarativeItem *item)
60    : GraphicsObjectNodeInstance(item),
61      m_hasHeight(false),
62      m_hasWidth(false),
63      m_isResizable(true),
64      m_x(0.0),
65      m_y(0.0),
66      m_width(0.0),
67      m_height(0.0)
68 {
69 }
70
71 QmlGraphicsItemNodeInstance::~QmlGraphicsItemNodeInstance()
72 {
73 }
74
75 bool anyItemHasContent(QGraphicsItem *graphicsItem)
76 {
77     if (!graphicsItem->flags().testFlag(QGraphicsItem::ItemHasNoContents))
78         return true;
79
80     foreach (QGraphicsItem *childItem, graphicsItem->childItems()) {
81         if (anyItemHasContent(childItem))
82             return true;
83     }
84
85     return false;
86 }
87
88 QmlGraphicsItemNodeInstance::Pointer QmlGraphicsItemNodeInstance::create(QObject *object)
89 {
90     QDeclarativeItem *qmlGraphicsItem = dynamic_cast<QDeclarativeItem*>(object);
91
92     if (qmlGraphicsItem == 0)
93         throw InvalidNodeInstanceException(__LINE__, __FUNCTION__, __FILE__);
94
95     Pointer instance(new QmlGraphicsItemNodeInstance(qmlGraphicsItem));
96
97     instance->setHasContent(anyItemHasContent(qmlGraphicsItem));
98     qmlGraphicsItem->setFlag(QGraphicsItem::ItemHasNoContents, false);
99
100     if (qmlGraphicsItem->inherits("QDeclarativeText"))
101         instance->setResizable(false);
102
103     static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem)->classBegin();
104
105     instance->populateResetValueHash();
106
107     return instance;
108 }
109
110 bool QmlGraphicsItemNodeInstance::isQmlGraphicsItem() const
111 {
112     return true;
113 }
114
115 QSizeF QmlGraphicsItemNodeInstance::size() const
116 {
117     if (isValid()) {
118         double implicitWidth = qmlGraphicsItem()->implicitWidth();
119         if (!m_hasWidth
120             && implicitWidth // WORKAROUND
121             && qmlGraphicsItem()->width() <= 0
122             && implicitWidth != qmlGraphicsItem()->width()
123             && !hasBindingForProperty("width")) {
124             qmlGraphicsItem()->blockSignals(true);
125             qmlGraphicsItem()->setWidth(implicitWidth);
126             qmlGraphicsItem()->blockSignals(false);
127         }
128
129         double implicitHeight = qmlGraphicsItem()->implicitHeight();
130         if (!m_hasHeight
131             && implicitWidth // WORKAROUND
132             && qmlGraphicsItem()->height() <= 0
133             && implicitHeight != qmlGraphicsItem()->height()
134             && !hasBindingForProperty("height")) {
135             qmlGraphicsItem()->blockSignals(true);
136             qmlGraphicsItem()->setHeight(implicitHeight);
137             qmlGraphicsItem()->blockSignals(false);
138         }
139
140     }
141
142     if (isRootNodeInstance()) {
143         if (!m_hasWidth) {
144             qmlGraphicsItem()->blockSignals(true);
145             if (qmlGraphicsItem()->width() < 10.)
146                 qmlGraphicsItem()->setWidth(100.);
147             qmlGraphicsItem()->blockSignals(false);
148         }
149
150         if (!m_hasHeight) {
151             qmlGraphicsItem()->blockSignals(true);
152             if (qmlGraphicsItem()->height() < 10.)
153                 qmlGraphicsItem()->setHeight(100.);
154             qmlGraphicsItem()->blockSignals(false);
155         }
156     }
157
158     return QSizeF(qmlGraphicsItem()->width(), qmlGraphicsItem()->height());
159 }
160
161 QRectF QmlGraphicsItemNodeInstance::boundingRect() const
162 {
163     if (isValid()) {
164         double implicitWidth = qmlGraphicsItem()->implicitWidth();
165         if (!m_hasWidth
166             && implicitWidth // WORKAROUND
167             && qmlGraphicsItem()->width() <= 0
168             && implicitWidth != qmlGraphicsItem()->width()
169             && !hasBindingForProperty("width")) {
170             qmlGraphicsItem()->blockSignals(true);
171             qmlGraphicsItem()->setWidth(implicitWidth);
172             qmlGraphicsItem()->blockSignals(false);
173         }
174
175         double implicitHeight = qmlGraphicsItem()->implicitHeight();
176         if (!m_hasHeight
177             && implicitWidth // WORKAROUND
178             && qmlGraphicsItem()->height() <= 0
179             && implicitHeight != qmlGraphicsItem()->height()
180             && !hasBindingForProperty("height")) {
181             qmlGraphicsItem()->blockSignals(true);
182             qmlGraphicsItem()->setHeight(implicitHeight);
183             qmlGraphicsItem()->blockSignals(false);
184         }
185
186     }
187
188     if (isRootNodeInstance()) {
189         if (!m_hasWidth) {
190             qmlGraphicsItem()->blockSignals(true);
191             if (qmlGraphicsItem()->width() < 10.)
192                 qmlGraphicsItem()->setWidth(100.);
193             qmlGraphicsItem()->blockSignals(false);
194         }
195
196         if (!m_hasHeight) {
197             qmlGraphicsItem()->blockSignals(true);
198             if (qmlGraphicsItem()->height() < 10.)
199                 qmlGraphicsItem()->setHeight(100.);
200             qmlGraphicsItem()->blockSignals(false);
201         }
202     }
203
204     if (qmlGraphicsItem())
205         return qmlGraphicsItem()->boundingRect();
206
207     return QRectF();
208 }
209
210 void QmlGraphicsItemNodeInstance::setPropertyVariant(const QString &name, const QVariant &value)
211 {
212     if (name == "state")
213         return; // states are only set by us
214
215     if (name == "height") {
216         m_height = value.toDouble();
217        if (value.isValid())
218            m_hasHeight = true;
219        else
220            m_hasHeight = false;
221     }
222
223     if (name == "width") {
224        m_width = value.toDouble();
225        if (value.isValid())
226            m_hasWidth = true;
227        else
228            m_hasWidth = false;
229     }
230
231     if (name == "x")
232         m_x = value.toDouble();
233
234     if (name == "y")
235         m_y = value.toDouble();
236
237     GraphicsObjectNodeInstance::setPropertyVariant(name, value);
238
239     refresh();
240 }
241
242 void QmlGraphicsItemNodeInstance::setPropertyBinding(const QString &name, const QString &expression)
243 {
244     if (name == "state")
245         return; // states are only set by us
246
247     GraphicsObjectNodeInstance::setPropertyBinding(name, expression);
248 }
249
250 QVariant QmlGraphicsItemNodeInstance::property(const QString &name) const
251 {
252    if (name == "width" && !hasBindingForProperty("width")) {
253         double implicitWidth = qmlGraphicsItem()->implicitWidth();
254         if (!m_hasWidth
255             && implicitWidth // WORKAROUND
256             && qmlGraphicsItem()->width() <= 0
257             && implicitWidth != qmlGraphicsItem()->width()) {
258                 qmlGraphicsItem()->blockSignals(true);
259                 qmlGraphicsItem()->setWidth(implicitWidth);
260                 qmlGraphicsItem()->blockSignals(false);
261         }
262     }
263
264     if (name == "height" && !hasBindingForProperty("height")) {
265         double implicitHeight = qmlGraphicsItem()->implicitHeight();
266         if (!m_hasHeight
267             && implicitHeight // WORKAROUND
268             && qmlGraphicsItem()->width() <= 0
269             && implicitHeight != qmlGraphicsItem()->height()) {
270                 qmlGraphicsItem()->blockSignals(true);
271                 qmlGraphicsItem()->setHeight(implicitHeight);
272                 qmlGraphicsItem()->blockSignals(false);
273             }
274     }
275
276     return GraphicsObjectNodeInstance::property(name);
277 }
278
279 void QmlGraphicsItemNodeInstance::resetHorizontal()
280  {
281     setPropertyVariant("x", m_x);
282     if (m_width > 0.0) {
283         setPropertyVariant("width", m_width);
284     } else {
285         setPropertyVariant("width", qmlGraphicsItem()->implicitWidth());
286     }
287 }
288
289 void QmlGraphicsItemNodeInstance::resetVertical()
290  {
291     setPropertyVariant("y", m_y);
292     if (m_height > 0.0) {
293         setPropertyVariant("height", m_height);
294     } else {
295         setPropertyVariant("height", qmlGraphicsItem()->implicitWidth());
296     }
297 }
298
299 static void repositioning(QDeclarativeItem *item)
300 {
301     if (!item)
302         return;
303
304 //    QDeclarativeBasePositioner *positioner = qobject_cast<QDeclarativeBasePositioner*>(item);
305 //    if (positioner)
306 //        positioner->rePositioning();
307
308     if (item->parentObject())
309         repositioning(qobject_cast<QDeclarativeItem*>(item->parentObject()));
310 }
311
312 void QmlGraphicsItemNodeInstance::refresh()
313 {
314     repositioning(qmlGraphicsItem());
315 }
316
317 void QmlGraphicsItemNodeInstance::doComponentComplete()
318 {
319     if (qmlGraphicsItem()) {
320         if (static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem()))->componentComplete)
321             return;
322         static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem())->componentComplete();
323         QGraphicsItemPrivate::get(qmlGraphicsItem())->sendParentChangeNotification = 1;
324     }
325
326     graphicsObject()->update();
327 }
328
329 bool QmlGraphicsItemNodeInstance::isResizable() const
330 {
331     return m_isResizable && qmlGraphicsItem() && qmlGraphicsItem()->parentItem();
332 }
333
334 void QmlGraphicsItemNodeInstance::setResizable(bool resizeable)
335 {
336     m_isResizable = resizeable;
337 }
338
339 int QmlGraphicsItemNodeInstance::penWidth() const
340 {
341     QDeclarativeRectangle *rectangle = qobject_cast<QDeclarativeRectangle*>(object());
342     if (rectangle)
343         return rectangle->border()->width();
344
345     return GraphicsObjectNodeInstance::penWidth();
346 }
347
348 void QmlGraphicsItemNodeInstance::resetProperty(const QString &name)
349 {
350     if (name == "height") {
351         m_hasHeight = false;
352         m_height = 0.0;
353     }
354
355     if (name == "width") {
356         m_hasWidth = false;
357         m_width = 0.0;
358     }
359
360     if (name == "x")
361         m_x = 0.0;
362
363     if (name == "y")
364         m_y = 0.0;
365
366
367     if (name == "anchors.fill") {
368         anchors()->resetFill();
369         resetHorizontal();
370         resetVertical();
371     } else if (name == "anchors.centerIn") {
372         anchors()->resetCenterIn();
373         resetHorizontal();
374         resetVertical();
375     } else if (name == "anchors.top") {
376         anchors()->resetTop();
377         resetVertical();
378     } else if (name == "anchors.left") {
379         anchors()->resetLeft();
380         resetHorizontal();
381     } else if (name == "anchors.right") {
382         anchors()->resetRight();
383         resetHorizontal();
384     } else if (name == "anchors.bottom") {
385         anchors()->resetBottom();
386         resetVertical();
387     } else if (name == "anchors.horizontalCenter") {
388         anchors()->resetHorizontalCenter();
389         resetHorizontal();
390     } else if (name == "anchors.verticalCenter") {
391         anchors()->resetVerticalCenter();
392         resetVertical();
393     } else if (name == "anchors.baseline") {
394         anchors()->resetBaseline();
395         resetVertical();
396     }
397
398     GraphicsObjectNodeInstance::resetProperty(name);
399 }
400
401 void QmlGraphicsItemNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParentInstance, const QString &oldParentProperty, const ObjectNodeInstance::Pointer &newParentInstance, const QString &newParentProperty)
402 {
403     if (oldParentInstance && oldParentInstance->isPositioner()) {
404         setInPositioner(false);
405         setMovable(true);
406     }
407
408     GraphicsObjectNodeInstance::reparent(oldParentInstance, oldParentProperty, newParentInstance, newParentProperty);
409
410     if (newParentInstance && newParentInstance->isPositioner()) {
411         setInPositioner(true);
412         setMovable(false);
413     }
414
415     if (oldParentInstance && oldParentInstance->isPositioner() && !(newParentInstance && newParentInstance->isPositioner())) {
416         if (!hasBindingForProperty("x"))
417             setPropertyVariant("x", m_x);
418
419         if (!hasBindingForProperty("y"))
420             setPropertyVariant("y", m_y);
421     }
422
423     refresh();
424 }
425
426 QDeclarativeAnchors::Anchor anchorLineFlagForName(const QString &name)
427 {
428     if (name == "anchors.top")
429         return QDeclarativeAnchors::TopAnchor;
430
431     if (name == "anchors.left")
432         return QDeclarativeAnchors::LeftAnchor;
433
434     if (name == "anchors.bottom")
435          return QDeclarativeAnchors::BottomAnchor;
436
437     if (name == "anchors.right")
438         return QDeclarativeAnchors::RightAnchor;
439
440     if (name == "anchors.horizontalCenter")
441         return QDeclarativeAnchors::HCenterAnchor;
442
443     if (name == "anchors.verticalCenter")
444          return QDeclarativeAnchors::VCenterAnchor;
445
446     if (name == "anchors.baseline")
447          return QDeclarativeAnchors::BaselineAnchor;
448
449
450     Q_ASSERT_X(false, Q_FUNC_INFO, "wrong anchor name - this should never happen");
451     return QDeclarativeAnchors::LeftAnchor;
452 }
453
454 QString propertyNameForAnchorLine(const QDeclarativeAnchorLine::AnchorLine &anchorLine)
455 {
456     switch(anchorLine) {
457         case QDeclarativeAnchorLine::Left: return "left";
458         case QDeclarativeAnchorLine::Right: return "right";
459         case QDeclarativeAnchorLine::Top: return "top";
460         case QDeclarativeAnchorLine::Bottom: return "bottom";
461         case QDeclarativeAnchorLine::HCenter: return "horizontalCenter";
462         case QDeclarativeAnchorLine::VCenter: return "verticalCenter";
463         case QDeclarativeAnchorLine::Baseline: return "baseline";
464         case QDeclarativeAnchorLine::Invalid:
465         default: return QString();
466     }
467 }
468
469 bool isValidAnchorName(const QString &name)
470 {
471     static QStringList anchorNameList(QStringList() << "anchors.top"
472                                                     << "anchors.left"
473                                                     << "anchors.right"
474                                                     << "anchors.bottom"
475                                                     << "anchors.verticalCenter"
476                                                     << "anchors.horizontalCenter"
477                                                     << "anchors.fill"
478                                                     << "anchors.centerIn"
479                                                     << "anchors.baseline");
480
481     return anchorNameList.contains(name);
482 }
483
484 QPair<QString, ServerNodeInstance> QmlGraphicsItemNodeInstance::anchor(const QString &name) const
485 {
486     if (!isValidAnchorName(name) || !hasAnchor(name))
487         return GraphicsObjectNodeInstance::anchor(name);
488
489     QObject *targetObject = 0;
490     QString targetName;
491
492     if (name == "anchors.fill") {
493         targetObject = anchors()->fill();
494     } else if (name == "anchors.centerIn") {
495         targetObject = anchors()->centerIn();
496     } else {
497         QDeclarativeProperty metaProperty(object(), name, context());
498         if (!metaProperty.isValid())
499             return GraphicsObjectNodeInstance::anchor(name);
500
501         QDeclarativeAnchorLine anchorLine = metaProperty.read().value<QDeclarativeAnchorLine>();
502         if (anchorLine.anchorLine != QDeclarativeAnchorLine::Invalid) {
503             targetObject = anchorLine.item;
504             targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
505         }
506
507     }
508
509     if (targetObject && nodeInstanceServer()->hasInstanceForObject(targetObject)) {
510         return qMakePair(targetName, nodeInstanceServer()->instanceForObject(targetObject));
511     } else {
512         return GraphicsObjectNodeInstance::anchor(name);
513     }
514 }
515
516 QList<ServerNodeInstance> QmlGraphicsItemNodeInstance::stateInstances() const
517 {
518     QList<ServerNodeInstance> instanceList;
519     QList<QDeclarativeState *> stateList = QDeclarativeItemPrivate::get(qmlGraphicsItem())->_states()->states();
520     foreach(QDeclarativeState *state, stateList)
521     {
522         if (state && nodeInstanceServer()->hasInstanceForObject(state))
523             instanceList.append(nodeInstanceServer()->instanceForObject(state));
524     }
525
526     return instanceList;
527 }
528
529 bool QmlGraphicsItemNodeInstance::hasAnchor(const QString &name) const
530 {
531     if (!isValidAnchorName(name))
532         return false;
533
534     if (name == "anchors.fill")
535         return anchors()->fill() != 0;
536
537     if (name == "anchors.centerIn")
538         return anchors()->centerIn() != 0;
539
540     if (name == "anchors.right")
541         return anchors()->right().item != 0;
542
543     if (name == "anchors.top")
544         return anchors()->top().item != 0;
545
546     if (name == "anchors.left")
547         return anchors()->left().item != 0;
548
549     if (name == "anchors.bottom")
550         return anchors()->bottom().item != 0;
551
552     if (name == "anchors.horizontalCenter")
553         return anchors()->horizontalCenter().item != 0;
554
555     if (name == "anchors.verticalCenter")
556         return anchors()->verticalCenter().item != 0;
557
558     if (name == "anchors.baseline")
559         return anchors()->baseline().item != 0;
560
561     return anchors()->usedAnchors().testFlag(anchorLineFlagForName(name));
562 }
563
564 bool isAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
565 {
566     Q_ASSERT(dynamic_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(fromItem)));
567     QDeclarativeItemPrivate *fromItemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(fromItem));
568     QDeclarativeAnchors *anchors = fromItemPrivate->anchors();
569     return anchors->fill() == toItem
570             || anchors->centerIn() == toItem
571             || anchors->bottom().item == toItem
572             || anchors->top().item == toItem
573             || anchors->left().item == toItem
574             || anchors->right().item == toItem
575             || anchors->verticalCenter().item == toItem
576             || anchors->horizontalCenter().item == toItem
577             || anchors->baseline().item == toItem;
578 }
579
580 bool areChildrenAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
581 {
582     foreach(QGraphicsItem *childGraphicsItem, fromItem->childItems()) {
583         QDeclarativeItem *childItem = qobject_cast<QDeclarativeItem*>(childGraphicsItem->toGraphicsObject());
584         if (childItem) {
585             if (isAnchoredTo(childItem, toItem))
586                 return true;
587
588             if (areChildrenAnchoredTo(childItem, toItem))
589                 return true;
590         }
591     }
592
593     return false;
594 }
595
596 bool QmlGraphicsItemNodeInstance::isAnchoredBySibling() const
597 {
598     if (qmlGraphicsItem()->parentItem()) {
599         foreach(QGraphicsItem *siblingGraphicsItem, qmlGraphicsItem()->parentItem()->childItems()) { // search in siblings for a anchor to this item
600             QDeclarativeItem *siblingItem = qobject_cast<QDeclarativeItem*>(siblingGraphicsItem->toGraphicsObject());
601             if (siblingItem) {
602                 if (isAnchoredTo(siblingItem, qmlGraphicsItem()))
603                     return true;
604             }
605         }
606     }
607
608     return false;
609 }
610
611 bool QmlGraphicsItemNodeInstance::isAnchoredByChildren() const
612 {
613     if (areChildrenAnchoredTo(qmlGraphicsItem(), qmlGraphicsItem())) // search in children for a anchor to this item
614         return true;
615
616     return false;
617 }
618
619 QDeclarativeItem *QmlGraphicsItemNodeInstance::qmlGraphicsItem() const
620 {
621     if (object() == 0)
622         return 0;
623
624     Q_ASSERT(qobject_cast<QDeclarativeItem*>(object()));
625     return static_cast<QDeclarativeItem*>(object());
626 }
627
628 QDeclarativeAnchors *QmlGraphicsItemNodeInstance::anchors() const
629 {
630     Q_ASSERT(dynamic_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem())));
631     QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem()));
632     return itemPrivate->anchors();
633 }
634
635 } // namespace Internal
636 } // namespace QmlDesigner