qmlgraphicsitemnodeinstance.cpp 20 KB
Newer Older
1
2
3
4
/**************************************************************************
**
** This file is part of Qt Creator
**
con's avatar
con committed
5
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6
7
8
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
con's avatar
con committed
9
** No Commercial Usage
10
**
con's avatar
con committed
11
12
13
14
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
15
16
17
18
19
20
21
22
23
24
**
** 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.
**
con's avatar
con committed
25
26
27
28
29
30
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
31
32
33
34
35
36
37
38
39
40
**
**************************************************************************/

#include "qmlgraphicsitemnodeinstance.h"

#include <invalidnodeinstanceexception.h>

#include "bindingproperty.h"
#include "variantproperty.h"

41
42
43
44
#include <QDeclarativeExpression>

#include <private/qdeclarativeanchors_p.h>
#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
53
54
55
56
57
58

#include <cmath>

#include <QHash>

namespace QmlDesigner {
namespace Internal {

59
60
QmlGraphicsItemNodeInstance::QmlGraphicsItemNodeInstance(QDeclarativeItem *item)
   : GraphicsObjectNodeInstance(item),
61
     m_hasHeight(false),
62
     m_hasWidth(false),
63
64
65
66
67
     m_isResizable(true),
     m_x(0.0),
     m_y(0.0),
     m_width(0.0),
     m_height(0.0)
68
69
70
71
72
73
74
{
}

QmlGraphicsItemNodeInstance::~QmlGraphicsItemNodeInstance()
{
}

75
76
77
78
79
80
81
82
83
84
85
86
87
bool anyItemHasContent(QGraphicsItem *graphicsItem)
{
    if (!graphicsItem->flags().testFlag(QGraphicsItem::ItemHasNoContents))
        return true;

    foreach (QGraphicsItem *childItem, graphicsItem->childItems()) {
        if (anyItemHasContent(childItem))
            return true;
    }

    return false;
}

88
QmlGraphicsItemNodeInstance::Pointer QmlGraphicsItemNodeInstance::create(QObject *object)
89
{
90
    QDeclarativeItem *qmlGraphicsItem = dynamic_cast<QDeclarativeItem*>(object);
91
92
93
94

    if (qmlGraphicsItem == 0)
        throw InvalidNodeInstanceException(__LINE__, __FUNCTION__, __FILE__);

95
96
    Pointer instance(new QmlGraphicsItemNodeInstance(qmlGraphicsItem));

97
    instance->setHasContent(anyItemHasContent(qmlGraphicsItem));
98
    qmlGraphicsItem->setFlag(QGraphicsItem::ItemHasNoContents, false);
99

100
101
102
    if (qmlGraphicsItem->inherits("QDeclarativeText"))
        instance->setResizable(false);

103
104
    static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem)->classBegin();

105
106
107
108
109
110
111
112
113
114
115
116
    instance->populateResetValueHash();

    return instance;
}

bool QmlGraphicsItemNodeInstance::isQmlGraphicsItem() const
{
    return true;
}

QSizeF QmlGraphicsItemNodeInstance::size() const
{
117
118
119
120
    if (isValid()) {
        double implicitWidth = qmlGraphicsItem()->implicitWidth();
        if (!m_hasWidth
            && implicitWidth // WORKAROUND
121
            && qmlGraphicsItem()->width() <= 0
122
            && implicitWidth != qmlGraphicsItem()->width()
123
            && !hasBindingForProperty("width")) {
124
125
126
127
128
129
130
131
            qmlGraphicsItem()->blockSignals(true);
            qmlGraphicsItem()->setWidth(implicitWidth);
            qmlGraphicsItem()->blockSignals(false);
        }

        double implicitHeight = qmlGraphicsItem()->implicitHeight();
        if (!m_hasHeight
            && implicitWidth // WORKAROUND
132
            && qmlGraphicsItem()->height() <= 0
133
            && implicitHeight != qmlGraphicsItem()->height()
134
            && !hasBindingForProperty("height")) {
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
            qmlGraphicsItem()->blockSignals(true);
            qmlGraphicsItem()->setHeight(implicitHeight);
            qmlGraphicsItem()->blockSignals(false);
        }

    }

    if (isRootNodeInstance()) {
        if (!m_hasWidth) {
            qmlGraphicsItem()->blockSignals(true);
            if (qmlGraphicsItem()->width() < 10.)
                qmlGraphicsItem()->setWidth(100.);
            qmlGraphicsItem()->blockSignals(false);
        }

        if (!m_hasHeight) {
            qmlGraphicsItem()->blockSignals(true);
            if (qmlGraphicsItem()->height() < 10.)
                qmlGraphicsItem()->setHeight(100.);
            qmlGraphicsItem()->blockSignals(false);
        }
    }
157

158
159
160
161
162
    return QSizeF(qmlGraphicsItem()->width(), qmlGraphicsItem()->height());
}

QRectF QmlGraphicsItemNodeInstance::boundingRect() const
{
163
164
165
166
    if (isValid()) {
        double implicitWidth = qmlGraphicsItem()->implicitWidth();
        if (!m_hasWidth
            && implicitWidth // WORKAROUND
167
            && qmlGraphicsItem()->width() <= 0
168
            && implicitWidth != qmlGraphicsItem()->width()
169
            && !hasBindingForProperty("width")) {
170
171
172
173
174
175
176
177
            qmlGraphicsItem()->blockSignals(true);
            qmlGraphicsItem()->setWidth(implicitWidth);
            qmlGraphicsItem()->blockSignals(false);
        }

        double implicitHeight = qmlGraphicsItem()->implicitHeight();
        if (!m_hasHeight
            && implicitWidth // WORKAROUND
178
            && qmlGraphicsItem()->height() <= 0
179
            && implicitHeight != qmlGraphicsItem()->height()
180
            && !hasBindingForProperty("height")) {
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
            qmlGraphicsItem()->blockSignals(true);
            qmlGraphicsItem()->setHeight(implicitHeight);
            qmlGraphicsItem()->blockSignals(false);
        }

    }

    if (isRootNodeInstance()) {
        if (!m_hasWidth) {
            qmlGraphicsItem()->blockSignals(true);
            if (qmlGraphicsItem()->width() < 10.)
                qmlGraphicsItem()->setWidth(100.);
            qmlGraphicsItem()->blockSignals(false);
        }

        if (!m_hasHeight) {
            qmlGraphicsItem()->blockSignals(true);
            if (qmlGraphicsItem()->height() < 10.)
                qmlGraphicsItem()->setHeight(100.);
            qmlGraphicsItem()->blockSignals(false);
        }
    }
203

Thomas Hartmann's avatar
Thomas Hartmann committed
204
205
206
207
    if (qmlGraphicsItem())
        return qmlGraphicsItem()->boundingRect();

    return QRectF();
208
209
210
211
}

void QmlGraphicsItemNodeInstance::setPropertyVariant(const QString &name, const QVariant &value)
{
Marco Bubke's avatar
Marco Bubke committed
212
213
214
    if (name == "state")
        return; // states are only set by us

215
    if (name == "height") {
216
        m_height = value.toDouble();
217
218
219
220
221
222
223
       if (value.isValid())
           m_hasHeight = true;
       else
           m_hasHeight = false;
    }

    if (name == "width") {
224
       m_width = value.toDouble();
225
226
227
228
229
230
       if (value.isValid())
           m_hasWidth = true;
       else
           m_hasWidth = false;
    }

231
232
233
234
235
236
    if (name == "x")
        m_x = value.toDouble();

    if (name == "y")
        m_y = value.toDouble();

237
    GraphicsObjectNodeInstance::setPropertyVariant(name, value);
238
239

    refresh();
240
241
242
243
}

void QmlGraphicsItemNodeInstance::setPropertyBinding(const QString &name, const QString &expression)
{
Marco Bubke's avatar
Marco Bubke committed
244
245
246
    if (name == "state")
        return; // states are only set by us

247
248
249
250
251
    GraphicsObjectNodeInstance::setPropertyBinding(name, expression);
}

QVariant QmlGraphicsItemNodeInstance::property(const QString &name) const
{
252
   if (name == "width" && !hasBindingForProperty("width")) {
253
254
255
        double implicitWidth = qmlGraphicsItem()->implicitWidth();
        if (!m_hasWidth
            && implicitWidth // WORKAROUND
256
            && qmlGraphicsItem()->width() <= 0
257
258
259
260
261
262
263
            && implicitWidth != qmlGraphicsItem()->width()) {
                qmlGraphicsItem()->blockSignals(true);
                qmlGraphicsItem()->setWidth(implicitWidth);
                qmlGraphicsItem()->blockSignals(false);
        }
    }

264
    if (name == "height" && !hasBindingForProperty("height")) {
265
266
267
        double implicitHeight = qmlGraphicsItem()->implicitHeight();
        if (!m_hasHeight
            && implicitHeight // WORKAROUND
268
            && qmlGraphicsItem()->width() <= 0
269
270
271
272
273
274
            && implicitHeight != qmlGraphicsItem()->height()) {
                qmlGraphicsItem()->blockSignals(true);
                qmlGraphicsItem()->setHeight(implicitHeight);
                qmlGraphicsItem()->blockSignals(false);
            }
    }
275
276
277
278
279
280

    return GraphicsObjectNodeInstance::property(name);
}

void QmlGraphicsItemNodeInstance::resetHorizontal()
 {
281
282
283
284
285
286
    setPropertyVariant("x", m_x);
    if (m_width > 0.0) {
        setPropertyVariant("width", m_width);
    } else {
        setPropertyVariant("width", qmlGraphicsItem()->implicitWidth());
    }
287
288
289
290
}

void QmlGraphicsItemNodeInstance::resetVertical()
 {
291
292
293
294
295
296
    setPropertyVariant("y", m_y);
    if (m_height > 0.0) {
        setPropertyVariant("height", m_height);
    } else {
        setPropertyVariant("height", qmlGraphicsItem()->implicitWidth());
    }
297
298
}

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
static void repositioning(QDeclarativeItem *item)
{
    if (!item)
        return;

//    QDeclarativeBasePositioner *positioner = qobject_cast<QDeclarativeBasePositioner*>(item);
//    if (positioner)
//        positioner->rePositioning();

    if (item->parentObject())
        repositioning(qobject_cast<QDeclarativeItem*>(item->parentObject()));
}

void QmlGraphicsItemNodeInstance::refresh()
{
    repositioning(qmlGraphicsItem());
}

317
318
void QmlGraphicsItemNodeInstance::doComponentComplete()
{
319
320
321
    if (qmlGraphicsItem()) {
        if (static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem()))->componentComplete)
            return;
322
        static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem())->componentComplete();
323
        QGraphicsItemPrivate::get(qmlGraphicsItem())->sendParentChangeNotification = 1;
324
    }
325
326

    graphicsObject()->update();
327
328
}

329
330
331
332
333
334
335
336
337
338
bool QmlGraphicsItemNodeInstance::isResizable() const
{
    return m_isResizable && qmlGraphicsItem() && qmlGraphicsItem()->parentItem();
}

void QmlGraphicsItemNodeInstance::setResizable(bool resizeable)
{
    m_isResizable = resizeable;
}

Marco Bubke's avatar
Marco Bubke committed
339
340
int QmlGraphicsItemNodeInstance::penWidth() const
{
341
342
343
    QDeclarativeRectangle *rectangle = qobject_cast<QDeclarativeRectangle*>(object());
    if (rectangle)
        return rectangle->border()->width();
Marco Bubke's avatar
Marco Bubke committed
344
345
346

    return GraphicsObjectNodeInstance::penWidth();
}
347
348
349

void QmlGraphicsItemNodeInstance::resetProperty(const QString &name)
{
350
    if (name == "height") {
351
        m_hasHeight = false;
352
353
        m_height = 0.0;
    }
354

355
    if (name == "width") {
356
        m_hasWidth = false;
357
358
359
360
361
362
363
364
        m_width = 0.0;
    }

    if (name == "x")
        m_x = 0.0;

    if (name == "y")
        m_y = 0.0;
365
366


367
    if (name == "anchors.fill") {
368
        anchors()->resetFill();
369
370
371
        resetHorizontal();
        resetVertical();
    } else if (name == "anchors.centerIn") {
372
        anchors()->resetCenterIn();
373
374
375
        resetHorizontal();
        resetVertical();
    } else if (name == "anchors.top") {
376
        anchors()->resetTop();
377
378
        resetVertical();
    } else if (name == "anchors.left") {
379
        anchors()->resetLeft();
380
381
        resetHorizontal();
    } else if (name == "anchors.right") {
382
        anchors()->resetRight();
383
384
        resetHorizontal();
    } else if (name == "anchors.bottom") {
385
        anchors()->resetBottom();
386
387
        resetVertical();
    } else if (name == "anchors.horizontalCenter") {
388
        anchors()->resetHorizontalCenter();
389
390
        resetHorizontal();
    } else if (name == "anchors.verticalCenter") {
391
        anchors()->resetVerticalCenter();
392
393
        resetVertical();
    } else if (name == "anchors.baseline") {
394
        anchors()->resetBaseline();
395
396
        resetVertical();
    }
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
405
406
407
        setInPositioner(false);
        setMovable(true);
    }

408
    GraphicsObjectNodeInstance::reparent(oldParentInstance, oldParentProperty, newParentInstance, newParentProperty);
409

410
    if (newParentInstance && newParentInstance->isPositioner()) {
411
412
413
414
        setInPositioner(true);
        setMovable(false);
    }

415
416
417
418
419
420
421
422
    if (oldParentInstance && oldParentInstance->isPositioner() && !(newParentInstance && newParentInstance->isPositioner())) {
        if (!hasBindingForProperty("x"))
            setPropertyVariant("x", m_x);

        if (!hasBindingForProperty("y"))
            setPropertyVariant("y", m_y);
    }

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
458
459
460
461
462
463
464
        case QDeclarativeAnchorLine::Left: return "left";
        case QDeclarativeAnchorLine::Right: return "right";
        case QDeclarativeAnchorLine::Top: return "top";
        case QDeclarativeAnchorLine::Bottom: return "bottom";
        case QDeclarativeAnchorLine::HCenter: return "horizontalCenter";
        case QDeclarativeAnchorLine::VCenter: return "verticalCenter";
        case QDeclarativeAnchorLine::Baseline: return "baseline";
        case QDeclarativeAnchorLine::Invalid:
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
        default: return QString();
    }
}

bool isValidAnchorName(const QString &name)
{
    static QStringList anchorNameList(QStringList() << "anchors.top"
                                                    << "anchors.left"
                                                    << "anchors.right"
                                                    << "anchors.bottom"
                                                    << "anchors.verticalCenter"
                                                    << "anchors.horizontalCenter"
                                                    << "anchors.fill"
                                                    << "anchors.centerIn"
                                                    << "anchors.baseline");

    return anchorNameList.contains(name);
}

484
QPair<QString, ServerNodeInstance> QmlGraphicsItemNodeInstance::anchor(const QString &name) const
485
486
487
488
489
490
491
492
{
    if (!isValidAnchorName(name) || !hasAnchor(name))
        return GraphicsObjectNodeInstance::anchor(name);

    QObject *targetObject = 0;
    QString targetName;

    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());
Marco Bubke's avatar
Marco Bubke committed
498
499
500
        if (!metaProperty.isValid())
            return GraphicsObjectNodeInstance::anchor(name);

501
502
        QDeclarativeAnchorLine anchorLine = metaProperty.read().value<QDeclarativeAnchorLine>();
        if (anchorLine.anchorLine != QDeclarativeAnchorLine::Invalid) {
503
504
505
506
507
508
            targetObject = anchorLine.item;
            targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
        }

    }

509
510
    if (targetObject && nodeInstanceServer()->hasInstanceForObject(targetObject)) {
        return qMakePair(targetName, nodeInstanceServer()->instanceForObject(targetObject));
511
512
513
514
515
    } else {
        return GraphicsObjectNodeInstance::anchor(name);
    }
}

516
517
518
519
520
521
522
523
524
525
526
527
528
QList<ServerNodeInstance> QmlGraphicsItemNodeInstance::stateInstances() const
{
    QList<ServerNodeInstance> instanceList;
    QList<QDeclarativeState *> stateList = QDeclarativeItemPrivate::get(qmlGraphicsItem())->_states()->states();
    foreach(QDeclarativeState *state, stateList)
    {
        if (state && nodeInstanceServer()->hasInstanceForObject(state))
            instanceList.append(nodeInstanceServer()->instanceForObject(state));
    }

    return instanceList;
}

529
530
531
532
533
534
bool QmlGraphicsItemNodeInstance::hasAnchor(const QString &name) const
{
    if (!isValidAnchorName(name))
        return false;

    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
567
568
569
570
571
572
573
574
575
576
577
    Q_ASSERT(dynamic_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(fromItem)));
    QDeclarativeItemPrivate *fromItemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(fromItem));
    QDeclarativeAnchors *anchors = fromItemPrivate->anchors();
    return anchors->fill() == toItem
            || anchors->centerIn() == toItem
            || anchors->bottom().item == toItem
            || anchors->top().item == toItem
            || anchors->left().item == toItem
            || anchors->right().item == toItem
            || anchors->verticalCenter().item == toItem
            || anchors->horizontalCenter().item == toItem
            || anchors->baseline().item == toItem;
578
579
}

580
bool areChildrenAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
581
{
582
583
    foreach(QGraphicsItem *childGraphicsItem, fromItem->childItems()) {
        QDeclarativeItem *childItem = qobject_cast<QDeclarativeItem*>(childGraphicsItem->toGraphicsObject());
584
585
586
587
588
589
590
591
592
593
594
595
        if (childItem) {
            if (isAnchoredTo(childItem, toItem))
                return true;

            if (areChildrenAnchoredTo(childItem, toItem))
                return true;
        }
    }

    return false;
}

596
bool QmlGraphicsItemNodeInstance::isAnchoredBySibling() const
597
{
598
599
600
    if (qmlGraphicsItem()->parentItem()) {
        foreach(QGraphicsItem *siblingGraphicsItem, qmlGraphicsItem()->parentItem()->childItems()) { // search in siblings for a anchor to this item
            QDeclarativeItem *siblingItem = qobject_cast<QDeclarativeItem*>(siblingGraphicsItem->toGraphicsObject());
601
602
603
604
605
606
607
608
609
610
            if (siblingItem) {
                if (isAnchoredTo(siblingItem, qmlGraphicsItem()))
                    return true;
            }
        }
    }

    return false;
}

611
612
613
614
615
616
617
618
bool QmlGraphicsItemNodeInstance::isAnchoredByChildren() const
{
    if (areChildrenAnchoredTo(qmlGraphicsItem(), qmlGraphicsItem())) // search in children for a anchor to this item
        return true;

    return false;
}

619
QDeclarativeItem *QmlGraphicsItemNodeInstance::qmlGraphicsItem() const
620
621
622
623
{
    if (object() == 0)
        return 0;

624
625
    Q_ASSERT(qobject_cast<QDeclarativeItem*>(object()));
    return static_cast<QDeclarativeItem*>(object());
626
}
627
628
629
630
631
632

QDeclarativeAnchors *QmlGraphicsItemNodeInstance::anchors() const
{
    Q_ASSERT(dynamic_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem())));
    QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem()));
    return itemPrivate->anchors();
633
}
634
635
636

} // namespace Internal
} // namespace QmlDesigner