forked from qt-creator/qt-creator
componentComplete after reparent was null. Change-Id: Ic4705531a38f67e706bc58a27d423d4062f83304 Reviewed-on: http://codereview.qt.nokia.com/1425 Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com> Reviewed-by: Thomas Hartmann <Thomas.Hartmann@nokia.com>
549 lines
17 KiB
C++
549 lines
17 KiB
C++
/**************************************************************************
|
|
**
|
|
** This file is part of Qt Creator
|
|
**
|
|
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
|
**
|
|
** Contact: Nokia Corporation (info@qt.nokia.com)
|
|
**
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
**
|
|
** 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.
|
|
**
|
|
** 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.
|
|
**
|
|
** 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.
|
|
**
|
|
** If you have questions regarding the use of this file, please contact
|
|
** Nokia at info@qt.nokia.com.
|
|
**
|
|
**************************************************************************/
|
|
|
|
#include "qmlgraphicsitemnodeinstance.h"
|
|
|
|
#include <QDeclarativeExpression>
|
|
|
|
#include <private/qdeclarativeanchors_p.h>
|
|
#include <private/qdeclarativeanchors_p_p.h>
|
|
#include <private/qdeclarativeitem_p.h>
|
|
#include <private/qdeclarativeproperty_p.h>
|
|
#include <private/qdeclarativerectangle_p.h>
|
|
#include <private/qdeclarativepositioners_p.h>
|
|
#include <private/qdeclarativestategroup_p.h>
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <QHash>
|
|
|
|
namespace QmlDesigner {
|
|
namespace Internal {
|
|
|
|
QmlGraphicsItemNodeInstance::QmlGraphicsItemNodeInstance(QDeclarativeItem *item)
|
|
: GraphicsObjectNodeInstance(item),
|
|
m_hasHeight(false),
|
|
m_hasWidth(false),
|
|
m_isResizable(true),
|
|
m_x(0.0),
|
|
m_y(0.0),
|
|
m_width(0.0),
|
|
m_height(0.0)
|
|
{
|
|
}
|
|
|
|
QmlGraphicsItemNodeInstance::~QmlGraphicsItemNodeInstance()
|
|
{
|
|
}
|
|
|
|
bool anyItemHasContent(QGraphicsItem *graphicsItem)
|
|
{
|
|
if (!graphicsItem->flags().testFlag(QGraphicsItem::ItemHasNoContents))
|
|
return true;
|
|
|
|
foreach (QGraphicsItem *childItem, graphicsItem->childItems()) {
|
|
if (anyItemHasContent(childItem))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QmlGraphicsItemNodeInstance::Pointer QmlGraphicsItemNodeInstance::create(QObject *object)
|
|
{
|
|
QDeclarativeItem *qmlGraphicsItem = dynamic_cast<QDeclarativeItem*>(object);
|
|
|
|
Q_ASSERT(qmlGraphicsItem);
|
|
|
|
Pointer instance(new QmlGraphicsItemNodeInstance(qmlGraphicsItem));
|
|
|
|
instance->setHasContent(anyItemHasContent(qmlGraphicsItem));
|
|
qmlGraphicsItem->setFlag(QGraphicsItem::ItemHasNoContents, false);
|
|
|
|
static_cast<QDeclarativeParserStatus*>(qmlGraphicsItem)->classBegin();
|
|
|
|
instance->populateResetValueHash();
|
|
|
|
return instance;
|
|
}
|
|
|
|
bool QmlGraphicsItemNodeInstance::isQmlGraphicsItem() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
QSizeF QmlGraphicsItemNodeInstance::size() const
|
|
{
|
|
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);
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::setPropertyVariant(const QString &name, const QVariant &value)
|
|
{
|
|
if (name == "state")
|
|
return; // states are only set by us
|
|
|
|
if (name == "height") {
|
|
m_height = value.toDouble();
|
|
if (value.isValid())
|
|
m_hasHeight = true;
|
|
else
|
|
m_hasHeight = false;
|
|
}
|
|
|
|
if (name == "width") {
|
|
m_width = value.toDouble();
|
|
if (value.isValid())
|
|
m_hasWidth = true;
|
|
else
|
|
m_hasWidth = false;
|
|
}
|
|
|
|
if (name == "x")
|
|
m_x = value.toDouble();
|
|
|
|
if (name == "y")
|
|
m_y = value.toDouble();
|
|
|
|
GraphicsObjectNodeInstance::setPropertyVariant(name, value);
|
|
|
|
refresh();
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::setPropertyBinding(const QString &name, const QString &expression)
|
|
{
|
|
if (name == "state")
|
|
return; // states are only set by us
|
|
|
|
GraphicsObjectNodeInstance::setPropertyBinding(name, expression);
|
|
}
|
|
|
|
QVariant QmlGraphicsItemNodeInstance::property(const QString &name) const
|
|
{
|
|
return GraphicsObjectNodeInstance::property(name);
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::resetHorizontal()
|
|
{
|
|
setPropertyVariant("x", m_x);
|
|
if (m_width > 0.0) {
|
|
setPropertyVariant("width", m_width);
|
|
} else {
|
|
setPropertyVariant("width", qmlGraphicsItem()->implicitWidth());
|
|
}
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::resetVertical()
|
|
{
|
|
setPropertyVariant("y", m_y);
|
|
if (m_height > 0.0) {
|
|
setPropertyVariant("height", m_height);
|
|
} else {
|
|
setPropertyVariant("height", qmlGraphicsItem()->implicitWidth());
|
|
}
|
|
}
|
|
|
|
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());
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::recursiveDoComponentComplete(QDeclarativeItem *declarativeItem)
|
|
{
|
|
if (declarativeItem) {
|
|
if (QDeclarativeItemPrivate::get(declarativeItem)->componentComplete)
|
|
return;
|
|
static_cast<QDeclarativeParserStatus*>(declarativeItem)->componentComplete();
|
|
|
|
foreach (QGraphicsItem *childItem, declarativeItem->childItems()) {
|
|
QGraphicsObject *childGraphicsObject = childItem->toGraphicsObject();
|
|
QDeclarativeItem *childDeclarativeItem = qobject_cast<QDeclarativeItem*>(childGraphicsObject);
|
|
if (childDeclarativeItem && !nodeInstanceServer()->hasInstanceForObject(childDeclarativeItem))
|
|
recursiveDoComponentComplete(childDeclarativeItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::doComponentComplete()
|
|
{
|
|
if (qmlGraphicsItem()) {
|
|
recursiveDoComponentComplete(qmlGraphicsItem());
|
|
}
|
|
|
|
graphicsObject()->update();
|
|
}
|
|
|
|
bool QmlGraphicsItemNodeInstance::isResizable() const
|
|
{
|
|
if (isRootNodeInstance())
|
|
return false;
|
|
|
|
return m_isResizable && qmlGraphicsItem() && qmlGraphicsItem()->parentItem();
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::setResizable(bool resizeable)
|
|
{
|
|
m_isResizable = resizeable;
|
|
}
|
|
|
|
int QmlGraphicsItemNodeInstance::penWidth() const
|
|
{
|
|
QDeclarativeRectangle *rectangle = qobject_cast<QDeclarativeRectangle*>(object());
|
|
if (rectangle)
|
|
return rectangle->border()->width();
|
|
|
|
return GraphicsObjectNodeInstance::penWidth();
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::resetProperty(const QString &name)
|
|
{
|
|
if (name == "height") {
|
|
m_hasHeight = false;
|
|
m_height = 0.0;
|
|
}
|
|
|
|
if (name == "width") {
|
|
m_hasWidth = false;
|
|
m_width = 0.0;
|
|
}
|
|
|
|
if (name == "x")
|
|
m_x = 0.0;
|
|
|
|
if (name == "y")
|
|
m_y = 0.0;
|
|
|
|
|
|
if (name == "anchors.fill") {
|
|
anchors()->resetFill();
|
|
resetHorizontal();
|
|
resetVertical();
|
|
} else if (name == "anchors.centerIn") {
|
|
anchors()->resetCenterIn();
|
|
resetHorizontal();
|
|
resetVertical();
|
|
} else if (name == "anchors.top") {
|
|
anchors()->resetTop();
|
|
resetVertical();
|
|
} else if (name == "anchors.left") {
|
|
anchors()->resetLeft();
|
|
resetHorizontal();
|
|
} else if (name == "anchors.right") {
|
|
anchors()->resetRight();
|
|
resetHorizontal();
|
|
} else if (name == "anchors.bottom") {
|
|
anchors()->resetBottom();
|
|
resetVertical();
|
|
} else if (name == "anchors.horizontalCenter") {
|
|
anchors()->resetHorizontalCenter();
|
|
resetHorizontal();
|
|
} else if (name == "anchors.verticalCenter") {
|
|
anchors()->resetVerticalCenter();
|
|
resetVertical();
|
|
} else if (name == "anchors.baseline") {
|
|
anchors()->resetBaseline();
|
|
resetVertical();
|
|
}
|
|
|
|
GraphicsObjectNodeInstance::resetProperty(name);
|
|
}
|
|
|
|
void QmlGraphicsItemNodeInstance::reparent(const ObjectNodeInstance::Pointer &oldParentInstance, const QString &oldParentProperty, const ObjectNodeInstance::Pointer &newParentInstance, const QString &newParentProperty)
|
|
{
|
|
if (oldParentInstance && oldParentInstance->isPositioner()) {
|
|
setInPositioner(false);
|
|
setMovable(true);
|
|
}
|
|
|
|
bool componentComplete = QDeclarativeItemPrivate::get(qmlGraphicsItem())->componentComplete;
|
|
QDeclarativeItemPrivate::get(qmlGraphicsItem())->componentComplete = 1;
|
|
GraphicsObjectNodeInstance::reparent(oldParentInstance, oldParentProperty, newParentInstance, newParentProperty);
|
|
QDeclarativeItemPrivate::get(qmlGraphicsItem())->componentComplete = componentComplete;
|
|
|
|
if (newParentInstance && newParentInstance->isPositioner()) {
|
|
setInPositioner(true);
|
|
setMovable(false);
|
|
}
|
|
|
|
if (oldParentInstance && oldParentInstance->isPositioner() && !(newParentInstance && newParentInstance->isPositioner())) {
|
|
if (!hasBindingForProperty("x"))
|
|
setPropertyVariant("x", m_x);
|
|
|
|
if (!hasBindingForProperty("y"))
|
|
setPropertyVariant("y", m_y);
|
|
}
|
|
|
|
refresh();
|
|
}
|
|
|
|
QDeclarativeAnchors::Anchor anchorLineFlagForName(const QString &name)
|
|
{
|
|
if (name == "anchors.top")
|
|
return QDeclarativeAnchors::TopAnchor;
|
|
|
|
if (name == "anchors.left")
|
|
return QDeclarativeAnchors::LeftAnchor;
|
|
|
|
if (name == "anchors.bottom")
|
|
return QDeclarativeAnchors::BottomAnchor;
|
|
|
|
if (name == "anchors.right")
|
|
return QDeclarativeAnchors::RightAnchor;
|
|
|
|
if (name == "anchors.horizontalCenter")
|
|
return QDeclarativeAnchors::HCenterAnchor;
|
|
|
|
if (name == "anchors.verticalCenter")
|
|
return QDeclarativeAnchors::VCenterAnchor;
|
|
|
|
if (name == "anchors.baseline")
|
|
return QDeclarativeAnchors::BaselineAnchor;
|
|
|
|
|
|
Q_ASSERT_X(false, Q_FUNC_INFO, "wrong anchor name - this should never happen");
|
|
return QDeclarativeAnchors::LeftAnchor;
|
|
}
|
|
|
|
QString propertyNameForAnchorLine(const QDeclarativeAnchorLine::AnchorLine &anchorLine)
|
|
{
|
|
switch(anchorLine) {
|
|
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:
|
|
default: return QString();
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
QPair<QString, ServerNodeInstance> QmlGraphicsItemNodeInstance::anchor(const QString &name) const
|
|
{
|
|
if (!isValidAnchorName(name) || !hasAnchor(name))
|
|
return GraphicsObjectNodeInstance::anchor(name);
|
|
|
|
QObject *targetObject = 0;
|
|
QString targetName;
|
|
|
|
if (name == "anchors.fill") {
|
|
targetObject = anchors()->fill();
|
|
} else if (name == "anchors.centerIn") {
|
|
targetObject = anchors()->centerIn();
|
|
} else {
|
|
QDeclarativeProperty metaProperty(object(), name, context());
|
|
if (!metaProperty.isValid())
|
|
return GraphicsObjectNodeInstance::anchor(name);
|
|
|
|
QDeclarativeAnchorLine anchorLine = metaProperty.read().value<QDeclarativeAnchorLine>();
|
|
if (anchorLine.anchorLine != QDeclarativeAnchorLine::Invalid) {
|
|
targetObject = anchorLine.item;
|
|
targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
|
|
}
|
|
|
|
}
|
|
|
|
if (targetObject && nodeInstanceServer()->hasInstanceForObject(targetObject)) {
|
|
return qMakePair(targetName, nodeInstanceServer()->instanceForObject(targetObject));
|
|
} else {
|
|
return GraphicsObjectNodeInstance::anchor(name);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool QmlGraphicsItemNodeInstance::hasAnchor(const QString &name) const
|
|
{
|
|
if (!isValidAnchorName(name))
|
|
return false;
|
|
|
|
if (name == "anchors.fill")
|
|
return anchors()->fill() != 0;
|
|
|
|
if (name == "anchors.centerIn")
|
|
return anchors()->centerIn() != 0;
|
|
|
|
if (name == "anchors.right")
|
|
return anchors()->right().item != 0;
|
|
|
|
if (name == "anchors.top")
|
|
return anchors()->top().item != 0;
|
|
|
|
if (name == "anchors.left")
|
|
return anchors()->left().item != 0;
|
|
|
|
if (name == "anchors.bottom")
|
|
return anchors()->bottom().item != 0;
|
|
|
|
if (name == "anchors.horizontalCenter")
|
|
return anchors()->horizontalCenter().item != 0;
|
|
|
|
if (name == "anchors.verticalCenter")
|
|
return anchors()->verticalCenter().item != 0;
|
|
|
|
if (name == "anchors.baseline")
|
|
return anchors()->baseline().item != 0;
|
|
|
|
return anchors()->usedAnchors().testFlag(anchorLineFlagForName(name));
|
|
}
|
|
|
|
bool isAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool areChildrenAnchoredTo(QDeclarativeItem *fromItem, QDeclarativeItem *toItem)
|
|
{
|
|
foreach(QGraphicsItem *childGraphicsItem, fromItem->childItems()) {
|
|
QDeclarativeItem *childItem = qobject_cast<QDeclarativeItem*>(childGraphicsItem->toGraphicsObject());
|
|
if (childItem) {
|
|
if (isAnchoredTo(childItem, toItem))
|
|
return true;
|
|
|
|
if (areChildrenAnchoredTo(childItem, toItem))
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QmlGraphicsItemNodeInstance::isAnchoredBySibling() const
|
|
{
|
|
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());
|
|
if (siblingItem) {
|
|
if (isAnchoredTo(siblingItem, qmlGraphicsItem()))
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool QmlGraphicsItemNodeInstance::isAnchoredByChildren() const
|
|
{
|
|
if (areChildrenAnchoredTo(qmlGraphicsItem(), qmlGraphicsItem())) // search in children for a anchor to this item
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
QDeclarativeItem *QmlGraphicsItemNodeInstance::qmlGraphicsItem() const
|
|
{
|
|
if (object() == 0)
|
|
return 0;
|
|
|
|
Q_ASSERT(qobject_cast<QDeclarativeItem*>(object()));
|
|
return static_cast<QDeclarativeItem*>(object());
|
|
}
|
|
|
|
QDeclarativeAnchors *QmlGraphicsItemNodeInstance::anchors() const
|
|
{
|
|
Q_ASSERT(dynamic_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem())));
|
|
QDeclarativeItemPrivate *itemPrivate = static_cast<QDeclarativeItemPrivate*>(QGraphicsItemPrivate::get(qmlGraphicsItem()));
|
|
return itemPrivate->anchors();
|
|
}
|
|
|
|
} // namespace Internal
|
|
} // namespace QmlDesigner
|