qmlgraphicsitemnodeinstance.cpp 16.6 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
**
hjk's avatar
hjk committed
7
** Contact: Nokia Corporation (info@qt.nokia.com)
8 9 10 11
**
**
** GNU Lesser General Public License Usage
**
hjk's avatar
hjk committed
12 13 14 15 16 17
** 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.
18
**
con's avatar
con committed
19
** In addition, as a special exception, Nokia gives you certain additional
hjk's avatar
hjk committed
20
** rights. These rights are described in the Nokia Qt LGPL Exception
con's avatar
con committed
21 22
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
23 24 25 26 27
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
con's avatar
con committed
28
** If you have questions regarding the use of this file, please contact
Tobias Hunger's avatar
Tobias Hunger committed
29
** Nokia at info@qt.nokia.com.
30 31 32 33 34
**
**************************************************************************/

#include "qmlgraphicsitemnodeinstance.h"

35 36 37 38
#include <QDeclarativeExpression>

#include <private/qdeclarativeanchors_p.h>
#include <private/qdeclarativeanchors_p_p.h>
39
#include <private/qdeclarativeitem_p.h>
40
#include <private/qdeclarativeproperty_p.h>
41
#include <private/qdeclarativerectangle_p.h>
42
#include <private/qdeclarativepositioners_p.h>
43
#include <private/qdeclarativestategroup_p.h>
44

45 46 47 48 49 50 51 52

#include <cmath>

#include <QHash>

namespace QmlDesigner {
namespace Internal {

53 54
QmlGraphicsItemNodeInstance::QmlGraphicsItemNodeInstance(QDeclarativeItem *item)
   : GraphicsObjectNodeInstance(item),
55
     m_hasHeight(false),
56
     m_hasWidth(false),
57 58 59 60 61
     m_isResizable(true),
     m_x(0.0),
     m_y(0.0),
     m_width(0.0),
     m_height(0.0)
62 63 64 65 66 67 68
{
}

QmlGraphicsItemNodeInstance::~QmlGraphicsItemNodeInstance()
{
}

69 70 71 72 73 74 75 76 77 78 79 80 81
bool anyItemHasContent(QGraphicsItem *graphicsItem)
{
    if (!graphicsItem->flags().testFlag(QGraphicsItem::ItemHasNoContents))
        return true;

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

    return false;
}

82
QmlGraphicsItemNodeInstance::Pointer QmlGraphicsItemNodeInstance::create(QObject *object)
83
{
84
    QDeclarativeItem *qmlGraphicsItem = dynamic_cast<QDeclarativeItem*>(object);
85

86
    Q_ASSERT(qmlGraphicsItem);
87

88 89
    Pointer instance(new QmlGraphicsItemNodeInstance(qmlGraphicsItem));

90
    instance->setHasContent(anyItemHasContent(qmlGraphicsItem));
91
    qmlGraphicsItem->setFlag(QGraphicsItem::ItemHasNoContents, false);
92

93 94
    static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem)->classBegin();

95 96 97 98 99 100 101 102 103 104 105 106
    instance->populateResetValueHash();

    return instance;
}

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

QSizeF QmlGraphicsItemNodeInstance::size() const
{
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
    double width;

    if (QDeclarativeItemPrivate::get(qmlGraphicsItem())->widthValid) {
        width = qmlGraphicsItem()->width();
    } else {
        width = qmlGraphicsItem()->implicitWidth();
    }

    double height;

    if (QDeclarativeItemPrivate::get(qmlGraphicsItem())->heightValid) {
        height = qmlGraphicsItem()->height();
    } else {
        height = qmlGraphicsItem()->implicitHeight();
    }


    return QSizeF(width, height);
125 126 127 128
}

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

132
    if (name == "height") {
133
        m_height = value.toDouble();
134 135 136 137 138 139 140
       if (value.isValid())
           m_hasHeight = true;
       else
           m_hasHeight = false;
    }

    if (name == "width") {
141
       m_width = value.toDouble();
142 143 144 145 146 147
       if (value.isValid())
           m_hasWidth = true;
       else
           m_hasWidth = false;
    }

148 149 150 151 152 153
    if (name == "x")
        m_x = value.toDouble();

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

154
    GraphicsObjectNodeInstance::setPropertyVariant(name, value);
155 156

    refresh();
157 158 159 160
}

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

164 165 166 167 168 169 170 171 172 173
    GraphicsObjectNodeInstance::setPropertyBinding(name, expression);
}

QVariant QmlGraphicsItemNodeInstance::property(const QString &name) const
{
    return GraphicsObjectNodeInstance::property(name);
}

void QmlGraphicsItemNodeInstance::resetHorizontal()
 {
174 175 176 177 178 179
    setPropertyVariant("x", m_x);
    if (m_width > 0.0) {
        setPropertyVariant("width", m_width);
    } else {
        setPropertyVariant("width", qmlGraphicsItem()->implicitWidth());
    }
180 181 182 183
}

void QmlGraphicsItemNodeInstance::resetVertical()
 {
184 185 186 187 188 189
    setPropertyVariant("y", m_y);
    if (m_height > 0.0) {
        setPropertyVariant("height", m_height);
    } else {
        setPropertyVariant("height", qmlGraphicsItem()->implicitWidth());
    }
190 191
}

192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
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());
}

210
void QmlGraphicsItemNodeInstance::recursiveDoComponentComplete(QGraphicsItem *item)
211
{
212 213 214 215
    QGraphicsObject *graphicsObject = item->toGraphicsObject();
    QDeclarativeItem *declarativeItem = qobject_cast<QDeclarativeItem*>(graphicsObject);
    if (declarativeItem && !nodeInstanceServer()->hasInstanceForObject(declarativeItem)) {
        if (QDeclarativeItemPrivate::get(qmlGraphicsItem())->componentComplete)
216
            return;
217
        static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem())->componentComplete();
218 219 220 221 222 223 224 225 226 227

        foreach (QGraphicsItem *childItem, item->childItems())
            recursiveDoComponentComplete(childItem);
    }
}

void QmlGraphicsItemNodeInstance::doComponentComplete()
{
    if (qmlGraphicsItem()) {
        recursiveDoComponentComplete(qmlGraphicsItem());
228
    }
229 230

    graphicsObject()->update();
231 232
}

233 234
bool QmlGraphicsItemNodeInstance::isResizable() const
{
235 236 237
    if (isRootNodeInstance())
        return false;

238 239 240 241 242 243 244 245
    return m_isResizable && qmlGraphicsItem() && qmlGraphicsItem()->parentItem();
}

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

Marco Bubke's avatar
Marco Bubke committed
246 247
int QmlGraphicsItemNodeInstance::penWidth() const
{
248 249 250
    QDeclarativeRectangle *rectangle = qobject_cast<QDeclarativeRectangle*>(object());
    if (rectangle)
        return rectangle->border()->width();
Marco Bubke's avatar
Marco Bubke committed
251 252 253

    return GraphicsObjectNodeInstance::penWidth();
}
254 255 256

void QmlGraphicsItemNodeInstance::resetProperty(const QString &name)
{
257
    if (name == "height") {
258
        m_hasHeight = false;
259 260
        m_height = 0.0;
    }
261

262
    if (name == "width") {
263
        m_hasWidth = false;
264 265 266 267 268 269 270 271
        m_width = 0.0;
    }

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

    if (name == "y")
        m_y = 0.0;
272 273


274
    if (name == "anchors.fill") {
275
        anchors()->resetFill();
276 277 278
        resetHorizontal();
        resetVertical();
    } else if (name == "anchors.centerIn") {
279
        anchors()->resetCenterIn();
280 281 282
        resetHorizontal();
        resetVertical();
    } else if (name == "anchors.top") {
283
        anchors()->resetTop();
284 285
        resetVertical();
    } else if (name == "anchors.left") {
286
        anchors()->resetLeft();
287 288
        resetHorizontal();
    } else if (name == "anchors.right") {
289
        anchors()->resetRight();
290 291
        resetHorizontal();
    } else if (name == "anchors.bottom") {
292
        anchors()->resetBottom();
293 294
        resetVertical();
    } else if (name == "anchors.horizontalCenter") {
295
        anchors()->resetHorizontalCenter();
296 297
        resetHorizontal();
    } else if (name == "anchors.verticalCenter") {
298
        anchors()->resetVerticalCenter();
299 300
        resetVertical();
    } else if (name == "anchors.baseline") {
301
        anchors()->resetBaseline();
302 303
        resetVertical();
    }
304 305

    GraphicsObjectNodeInstance::resetProperty(name);
306 307
}

308
void QmlGraphicsItemNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParentInstance, const QString &oldParentProperty, const ObjectNodeInstance::Pointer &newParentInstance, const QString &newParentProperty)
309
{
310
    if (oldParentInstance && oldParentInstance->isPositioner()) {
311 312 313 314
        setInPositioner(false);
        setMovable(true);
    }

315
    QDeclarativeItemPrivate::get(qmlGraphicsItem())->componentComplete = 1;
316
    GraphicsObjectNodeInstance::reparent(oldParentInstance, oldParentProperty, newParentInstance, newParentProperty);
317
    QDeclarativeItemPrivate::get(qmlGraphicsItem())->componentComplete = 0;
318

319
    if (newParentInstance && newParentInstance->isPositioner()) {
320 321 322 323
        setInPositioner(true);
        setMovable(false);
    }

324 325 326 327 328 329 330 331
    if (oldParentInstance && oldParentInstance->isPositioner() && !(newParentInstance && newParentInstance->isPositioner())) {
        if (!hasBindingForProperty("x"))
            setPropertyVariant("x", m_x);

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

332
    refresh();
333 334
}

335
QDeclarativeAnchors::Anchor anchorLineFlagForName(const QString &name)
336 337
{
    if (name == "anchors.top")
338
        return QDeclarativeAnchors::TopAnchor;
339 340

    if (name == "anchors.left")
341
        return QDeclarativeAnchors::LeftAnchor;
342 343

    if (name == "anchors.bottom")
344
         return QDeclarativeAnchors::BottomAnchor;
345 346

    if (name == "anchors.right")
347
        return QDeclarativeAnchors::RightAnchor;
348 349

    if (name == "anchors.horizontalCenter")
350
        return QDeclarativeAnchors::HCenterAnchor;
351 352

    if (name == "anchors.verticalCenter")
353
         return QDeclarativeAnchors::VCenterAnchor;
354 355

    if (name == "anchors.baseline")
356
         return QDeclarativeAnchors::BaselineAnchor;
357 358 359


    Q_ASSERT_X(false, Q_FUNC_INFO, "wrong anchor name - this should never happen");
360
    return QDeclarativeAnchors::LeftAnchor;
361 362
}

363
QString propertyNameForAnchorLine(const QDeclarativeAnchorLine::AnchorLine &anchorLine)
364 365
{
    switch(anchorLine) {
366 367 368 369 370 371 372 373
        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:
374 375 376 377
        default: return QString();
    }
}

378
static bool isValidAnchorName(const QString &name)
379 380 381 382 383 384 385 386 387 388 389 390 391 392
{
    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);
}

393
QPair<QString, ServerNodeInstance> QmlGraphicsItemNodeInstance::anchor(const QString &name) const
394 395 396 397 398 399 400 401
{
    if (!isValidAnchorName(name) || !hasAnchor(name))
        return GraphicsObjectNodeInstance::anchor(name);

    QObject *targetObject = 0;
    QString targetName;

    if (name == "anchors.fill") {
402
        targetObject = anchors()->fill();
403
    } else if (name == "anchors.centerIn") {
404
        targetObject = anchors()->centerIn();
405
    } else {
406
        QDeclarativeProperty metaProperty(object(), name, context());
Marco Bubke's avatar
Marco Bubke committed
407 408 409
        if (!metaProperty.isValid())
            return GraphicsObjectNodeInstance::anchor(name);

410 411
        QDeclarativeAnchorLine anchorLine = metaProperty.read().value<QDeclarativeAnchorLine>();
        if (anchorLine.anchorLine != QDeclarativeAnchorLine::Invalid) {
412 413 414 415 416 417
            targetObject = anchorLine.item;
            targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
        }

    }

418 419
    if (targetObject && nodeInstanceServer()->hasInstanceForObject(targetObject)) {
        return qMakePair(targetName, nodeInstanceServer()->instanceForObject(targetObject));
420 421 422 423 424
    } else {
        return GraphicsObjectNodeInstance::anchor(name);
    }
}

425 426 427 428 429 430 431 432 433 434 435 436 437
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;
}

438 439 440 441 442 443
bool QmlGraphicsItemNodeInstance::hasAnchor(const QString &name) const
{
    if (!isValidAnchorName(name))
        return false;

    if (name == "anchors.fill")
444
        return anchors()->fill() != 0;
445 446

    if (name == "anchors.centerIn")
447
        return anchors()->centerIn() != 0;
448 449

    if (name == "anchors.right")
450
        return anchors()->right().item != 0;
451 452

    if (name == "anchors.top")
453
        return anchors()->top().item != 0;
454 455

    if (name == "anchors.left")
456
        return anchors()->left().item != 0;
457 458

    if (name == "anchors.bottom")
459
        return anchors()->bottom().item != 0;
460 461

    if (name == "anchors.horizontalCenter")
462
        return anchors()->horizontalCenter().item != 0;
463 464

    if (name == "anchors.verticalCenter")
465
        return anchors()->verticalCenter().item != 0;
466 467

    if (name == "anchors.baseline")
468
        return anchors()->baseline().item != 0;
469

470
    return anchors()->usedAnchors().testFlag(anchorLineFlagForName(name));
471 472
}

473
bool isAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
474
{
475 476 477 478 479 480 481 482 483 484 485 486
    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;
487 488
}

489
bool areChildrenAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
490
{
491 492
    foreach(QGraphicsItem *childGraphicsItem, fromItem->childItems()) {
        QDeclarativeItem *childItem = qobject_cast<QDeclarativeItem*>(childGraphicsItem->toGraphicsObject());
493 494 495 496 497 498 499 500 501 502 503 504
        if (childItem) {
            if (isAnchoredTo(childItem, toItem))
                return true;

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

    return false;
}

505
bool QmlGraphicsItemNodeInstance::isAnchoredBySibling() const
506
{
507 508 509
    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());
510 511 512 513 514 515 516 517 518 519
            if (siblingItem) {
                if (isAnchoredTo(siblingItem, qmlGraphicsItem()))
                    return true;
            }
        }
    }

    return false;
}

520 521 522 523 524 525 526 527
bool QmlGraphicsItemNodeInstance::isAnchoredByChildren() const
{
    if (areChildrenAnchoredTo(qmlGraphicsItem(), qmlGraphicsItem())) // search in children for a anchor to this item
        return true;

    return false;
}

528
QDeclarativeItem *QmlGraphicsItemNodeInstance::qmlGraphicsItem() const
529 530 531 532
{
    if (object() == 0)
        return 0;

533 534
    Q_ASSERT(qobject_cast<QDeclarativeItem*>(object()));
    return static_cast<QDeclarativeItem*>(object());
535
}
536 537 538 539 540 541

QDeclarativeAnchors *QmlGraphicsItemNodeInstance::anchors() const
{
    Q_ASSERT(dynamic_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem())));
    QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem()));
    return itemPrivate->anchors();
542
}
543 544 545

} // namespace Internal
} // namespace QmlDesigner