OSDN Git Service

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