/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** 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 either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** 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.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qmldom.h"
#include "qmldom_p.h"
#include "private/qmlcompiler_p.h"
#include "private/qmlengine_p.h"
#include "qmlcompiledcomponent_p.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qstring.h>

#include "qmlscriptparser_p.h"

QT_BEGIN_NAMESPACE

QmlDomDocumentPrivate::QmlDomDocumentPrivate()
: root(0)
{
}

QmlDomDocumentPrivate::QmlDomDocumentPrivate(const QmlDomDocumentPrivate &other)
: QSharedData(other), root(0)
{
    root = other.root;
    if (root) root->addref();
}

QmlDomDocumentPrivate::~QmlDomDocumentPrivate()
{
    if (root) root->release();
}

/*!
    \class QmlDomDocument
    \brief The QmlDomDocument class represents the root of a QML document

    A QML document is a self-contained snippet of QML, usually contained in a
    single file.  Each document has a version number, accessible through 
    QmlDomDocument::version(),  and a root object, accessible through 
    QmlDomDocument::rootObject().

    The QmlDomDocument class allows the programmer to load a QML document, by
    calling QmlDomDocument::load(), manipulate it and save it to textual form
    by calling QmlDomDocument::save().  By using the QML DOM API, editors can
    non-destructively modify a QML document even if they only understand a 
    subset of the total QML functionality.

    The following example loads a QML file from disk, and prints out its root
    object type and the properties assigned in the root object.
    \code
    QFile file(inputFileName);
    file.open(QIODevice::ReadOnly);
    QByteArray xmlData = file.readAll();

    QDomDocument document;
    document.load(xmlData);

    QDomObject rootObject = document.rootObject();
    qDebug() << rootObject.objectType();
    foreach(QmlDomProperty property, rootObject.properties())
        qDebug() << property.propertyName();
    \endcode
*/

/*!
    Construct an empty QmlDomDocument.
*/
QmlDomDocument::QmlDomDocument()
: d(new QmlDomDocumentPrivate)
{
}

/*!
    Create a copy of \a other QmlDomDocument.
*/
QmlDomDocument::QmlDomDocument(const QmlDomDocument &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomDocument
*/
QmlDomDocument::~QmlDomDocument()
{
}

/*!
    Assign \a other to this QmlDomDocument.
*/
QmlDomDocument &QmlDomDocument::operator=(const QmlDomDocument &other)
{
    d = other.d;
    return *this;
}

/*!
    Return the version number of the Qml document.  Currently only version
    1 exists.
*/
int QmlDomDocument::version() const
{
    return 1;
}

/*!
    Loads a QmlDomDocument from \a data.  \a data should be valid QML XML
    data.  On success, true is returned.  If the \a data is malformed, false
    is returned and QmlDomDocument::loadError() contains an error description.

    \sa QmlDomDocument::save() QmlDomDocument::loadError()
*/
bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data)
{
    Q_UNUSED(engine);

    d->error = QString();

    QmlScriptParser parser;
    if (!parser.parse(data)) {
        d->error = parser.errorDescription();
        return false;
    }

    QmlCompiledComponent component;
    QmlCompiler compiler;

    QmlCompositeTypeData *td = ((QmlEnginePrivate *)QmlEnginePrivate::get(engine))->typeManager.getImmediate(data, QUrl());;

    if(td->status == QmlCompositeTypeData::Error) {
        d->error = td->errorDescription;
        td->release();
        return false;
    } else if(td->status == QmlCompositeTypeData::Waiting) {
        d->error = QLatin1String("QmlDomDocument supports local types only");
        td->release();
        return false;
    } 

    compiler.compile(engine, td, &component);

    if (compiler.isError()) {
        d->error = compiler.errorDescription();
        td->release();
        return false;
    }

    if (td->data.tree()) {
        component.dump(0, parser.tree());
        d->root = parser.tree();
        d->root->addref();
    }

    return true;
}


/*!
    Returns the last load error.  The load error will be reset after a 
    successful call to load().

    \sa load()
*/
QString QmlDomDocument::loadError() const
{
    return d->error;
}

/*!
    Return a saved copy of the QmlDomDocument.  The returned data will be valid
    QML XML data.

    \sa load()
*/
QByteArray QmlDomDocument::save() const
{
    return QByteArray();
}

/*!
    Returns the document's root object, or an invalid QmlDomObject if the
    document has no root.

    In the sample QML below, the root object will be the QFxItem type.
    \code
    <Item>
        <Text text="Hello World" />
    </Item>
    \endcode
*/
QmlDomObject QmlDomDocument::rootObject() const
{
    QmlDomObject rv;
    rv.d->object = d->root;
    if (rv.d->object) rv.d->object->addref();
    return rv;
}

QmlDomPropertyPrivate::QmlDomPropertyPrivate()
: property(0)
{
}

QmlDomPropertyPrivate::QmlDomPropertyPrivate(const QmlDomPropertyPrivate &other)
: QSharedData(other), property(0)
{
    property = other.property;
    if (property) property->addref();
}

QmlDomPropertyPrivate::~QmlDomPropertyPrivate()
{
    if (property) property->release();
}

/*!
    \class QmlDomProperty
    \brief The QmlDomProperty class represents one property assignment in the 
    QML DOM tree

    Properties in QML can be assigned QML \l {QmlDomValue}{values}.

    \sa QmlDomObject
*/

/*!
    Construct an invalid QmlDomProperty.
*/
QmlDomProperty::QmlDomProperty()
: d(new QmlDomPropertyPrivate)
{
}

/*!
    Create a copy of \a other QmlDomProperty.
*/
QmlDomProperty::QmlDomProperty(const QmlDomProperty &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomProperty.
*/
QmlDomProperty::~QmlDomProperty()
{
}

/*!
    Assign \a other to this QmlDomProperty.
*/
QmlDomProperty &QmlDomProperty::operator=(const QmlDomProperty &other)
{
    d = other.d;
    return *this;
}

/*!
    Return the name of this property.  
    
    \code
    <Text x="10" y="10" font.bold="true" />
    \endcode
    
    As illustrated above, a property name can be a simple string, such as "x" or
    "y", or a more complex "dot property", such as "font.bold".  In both cases
    the full name is returned ("x", "y" and "font.bold") by this method.

    For dot properties, a split version of the name can be accessed by calling
    QmlDomProperty::propertyNameParts().

    \sa QmlDomProperty::propertyNameParts()
*/
QByteArray QmlDomProperty::propertyName() const
{
    return d->propertyName;
}

/*!
    Return the name of this property, split into multiple parts in the case
    of dot properties.

    \code
    <Text x="10" y="10" font.bold="true" />
    \endcode

    For each of the properties shown above, this method would return ("x"), 
    ("y") and ("font", "bold").

    \sa QmlDomProperty::propertyName()
*/
QList<QByteArray> QmlDomProperty::propertyNameParts() const
{
    if (d->propertyName.isEmpty()) return QList<QByteArray>();
    else return d->propertyName.split('.');
}

/*!
    Return true if this property is used as a default property in the QML 
    document.

    \code
    <Text text="hello" />
    <Text>hello</Text>
    \endcode

    The above two examples return the same DOM tree, except that the second has
    the default property flag set on the text property.  Observe that whether
    or not a property has isDefaultProperty set is determined by how the 
    property is used, and not only by whether the property is the types default 
    property.
*/
bool QmlDomProperty::isDefaultProperty() const
{
    return d->property && d->property->isDefault;
}

/*!
    Returns the QmlDomValue that is assigned to this property, or an invalid
    QmlDomValue if no value is assigned.
*/
QmlDomValue QmlDomProperty::value() const
{
    QmlDomValue rv;
    if (d->property) {
        rv.d->property = d->property;
        rv.d->value = d->property->values.at(0);
        rv.d->property->addref();
        rv.d->value->addref();
    }
    return rv;
}

/*!
    Sets the QmlDomValue that is assigned to this property to \a value.
*/
void QmlDomProperty::setValue(const QmlDomValue &value)
{
    Q_UNUSED(value);
    qWarning("QmlDomProperty::setValue(const QmlDomValue &): Not Implemented");
}

QmlDomObjectPrivate::QmlDomObjectPrivate()
: object(0), isVirtualComponent(false)
{
}

QmlDomObjectPrivate::QmlDomObjectPrivate(const QmlDomObjectPrivate &other)
: QSharedData(other), object(0), isVirtualComponent(false)
{
    object = other.object;
    if (object) object->addref();
    isVirtualComponent = other.isVirtualComponent;
}

QmlDomObjectPrivate::~QmlDomObjectPrivate()
{
    if (object) object->release();
}

QmlDomObjectPrivate::Properties
QmlDomObjectPrivate::properties() const
{
    Properties rv;

    for (QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = 
            object->properties.begin();
            iter != object->properties.end();
            ++iter) {

        rv << properties(*iter);

    }
    return rv;
}

QmlDomObjectPrivate::Properties
QmlDomObjectPrivate::properties(QmlParser::Property *property) const
{
    Properties rv;

    if (property->value) {

        for (QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = 
                property->value->properties.begin();
                iter != property->value->properties.end();
                ++iter) {

            rv << properties(*iter);

        }

        QByteArray name(property->name + ".");
        for (Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter) 
            iter->second.prepend(name);

    } else {

        // We don't display "id" sets as a property in the dom
        if (property->values.count() != 1 || 
           property->values.at(0)->type != QmlParser::Value::Id)
            rv << qMakePair(property, property->name);

    }

    return rv;
}

/*!
    \class QmlDomObject
    \brief The QmlDomObject class represents an object instantiation.

    Each object instantiated in a QML file has a corresponding QmlDomObject
    node in the QML DOM.
    
    In addition to the type information that determines the object to 
    instantiate, QmlDomObject's also have a set of associated QmlDomProperty's.
    Each QmlDomProperty represents a QML property assignment on the instantiated
    object.  For example,

    \code
    <QGraphicsWidget opacity="0.5" size="100x100" />
    \endcode

    describes a single QmlDomObject - "QGraphicsWidget" - with two properties,
    "opacity" and "size".  Obviously QGraphicsWidget has many more properties than just
    these two, but the QML DOM representation only contains those assigned 
    values (or bindings) in the QML file.

    The DOM tree can be modified to include new property assignments by calling
    QmlDomObject::addProperty().  Existing property assignments can be modified
    through the QmlDomProperty::setValue() method, or removed entirely by 
    calling QmlDomObject::removeProperty().
*/

/*!
    Construct an invalid QmlDomObject.
*/
QmlDomObject::QmlDomObject()
: d(new QmlDomObjectPrivate)
{
}

/*!
    Construct a new QmlDomObject with the specified \a objectType.
*/
QmlDomObject::QmlDomObject(const QByteArray &objectType)
: d(new QmlDomObjectPrivate)
{
    Q_UNUSED(objectType);
    qWarning("QmlDomObject::QmlDomObject(const QByteArray &): Not implemented");
}

/*!
    Create a copy of \a other QmlDomObject.
*/
QmlDomObject::QmlDomObject(const QmlDomObject &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomObject.
*/
QmlDomObject::~QmlDomObject()
{
}

/*!
    Assign \a other to this QmlDomObject.
*/
QmlDomObject &QmlDomObject::operator=(const QmlDomObject &other)
{
    d = other.d;
    return *this;
}

/*!
    Returns true if this is a valid QmlDomObject, false otherwise.
*/
bool QmlDomObject::isValid() const
{
    return d->object != 0;
}

/*!
    Returns the type name of this object.

    For example, the type of this object would be "QGraphicsWidget".
    \code
    <QGraphicsWidget />
    \endcode
*/
QByteArray QmlDomObject::objectType() const
{
    if (d->object) return d->object->typeName;
    else return QByteArray();
}

/*!
    Returns the QML id assigned to this object, or an empty QByteArray if no id
    has been assigned.

    For example, the object id of this object would be "MyText".
    \code
    <Text id="MyText" />
    \endcode
*/
QByteArray QmlDomObject::objectId() const
{
    if (d->object) return d->object->id;
    else return QByteArray();
}

/*!
    Set the object \a id.  If any other object within the DOM tree has the same
    id, the other object's id will be cleared.
*/
void QmlDomObject::setObjectId(const QByteArray &id)
{
    Q_UNUSED(id);
    qWarning("QmlDomObject::setObjectId(const QByteArray &): Not implemented");
}


/*!
    Returns the list of assigned properties on this object. 

    In the following example, "text" and "x" properties would be returned.
    \code
    <Text text="Hello world!" x="100" />
    \endcode
*/
QList<QmlDomProperty> QmlDomObject::properties() const
{
    QList<QmlDomProperty> rv;

    if (!d->object)
        return rv;

    QmlDomObjectPrivate::Properties properties = d->properties();
    for (int ii = 0; ii < properties.count(); ++ii) {

        QmlDomProperty domProperty;
        domProperty.d->property = properties.at(ii).first;
        domProperty.d->property->addref();
        domProperty.d->propertyName = properties.at(ii).second;
        rv << domProperty;

    }

    if (d->object->defaultProperty) {
        QmlDomProperty domProperty;
        domProperty.d->property = d->object->defaultProperty;
        domProperty.d->property->addref();
        domProperty.d->propertyName = d->object->defaultProperty->name;
        rv << domProperty;
    }

    return rv;
}

/*!
    Returns the object's \a name property if a value has been assigned to
    it, or an invalid QmlDomProperty otherwise.

    In the example below, \c {object.property("src")} would return a valid
    QmlDomProperty, and \c {object.property("tile")} an invalid QmlDomProperty.

    \code
    <Image src="sample.jpg" />
    \endcode
*/
QmlDomProperty QmlDomObject::property(const QByteArray &name) const
{
    QList<QmlDomProperty> props = properties();
    for (int ii = 0; ii < props.count(); ++ii)
        if (props.at(ii).propertyName() == name)
            return props.at(ii);
    return QmlDomProperty();
}

/*!
    Remove the property \a name from this object, if it exists.  Otherwise does
    nothing.
*/
void QmlDomObject::removeProperty(const QByteArray &name)
{
    Q_UNUSED(name);
    qWarning("QmlDomObject::removeProperty(const QByteArray &): Not implemented");
}

/*!
    Adds the property \a name with the specified \a value to this object.  If
    a property by \a name already exists, it will be removed.
*/
void QmlDomObject::addProperty(const QByteArray &name, const QmlDomValue &value)
{
    Q_UNUSED(name);
    Q_UNUSED(value);
    qWarning("QmlDomObject::addProperty(const QByteArray &, const QmlDomValue &): Not implemented");
}

/*!
    Returns true if this object is a custom type.  Custom types are special 
    types that allow embeddeding non-QML data, such as SVG or HTML data, 
    directly into QML files.

    \note Currently this method will always return false, and is a placekeeper
    for future functionality.

    \sa QmlDomObject::customTypeData()
*/
bool QmlDomObject::isCustomType() const
{
    return false;
}

/*!
    Sets the custom type \a data.  If this type is not a custom type, this 
    method does nothing.

    \sa QmlDomObject::isCustomType() QmlDomObject::customTypeData()
*/
void QmlDomObject::setCustomTypeData(const QByteArray &data)
{
    Q_UNUSED(data);
    qWarning("QmlDomObject::setCustomTypeData(const QByteArray &): Not implemented");
}

/*!
    If this object represents a custom type, returns the data associated with 
    the custom type, otherwise returns an empty QByteArray().  
    QmlDomObject::isCustomType() can be used to check if this object represents
    a custom type.
*/
QByteArray QmlDomObject::customTypeData() const
{
    return QByteArray();
}

/*!
    Returns true if this object is a sub-component object.  Sub-component 
    objects can be converted into QmlDomComponent instances by calling 
    QmlDomObject::toComponent().

    \sa QmlDomObject::toComponent()
*/
bool QmlDomObject::isComponent() const
{
    return d->isVirtualComponent || 
           (d->object && d->object->typeName == "Component");
}

/*!
    Returns a QmlDomComponent for this object if it is a sub-component, or 
    an invalid QmlDomComponent if not.  QmlDomObject::isComponent() can be used
    to check if this object represents a sub-component.

    \sa QmlDomObject::isComponent()
*/
QmlDomComponent QmlDomObject::toComponent() const
{
    QmlDomComponent rv;
    if (isComponent())
        rv.d = d;
    return rv;
}

QmlDomBasicValuePrivate::QmlDomBasicValuePrivate()
: value(0)
{
}

QmlDomBasicValuePrivate::QmlDomBasicValuePrivate(const QmlDomBasicValuePrivate &other)
: QSharedData(other), value(0)
{
    value = other.value;
    if (value) value->addref();
}

QmlDomBasicValuePrivate::~QmlDomBasicValuePrivate()
{
    if (value) value->release();
}

/*!
    \class QmlDomValueLiteral
    \brief The QmlDomValueLiteral class represents a literal value.

    A literal value is a simple value, written inline with the QML.  In the
    example below, the "x", "y" and "color" properties are being assigned
    literal values.

    \code
    <Rect x="10" y="10" color="red" />
    \endcode
*/

/*!
    Construct an empty QmlDomValueLiteral.
*/
QmlDomValueLiteral::QmlDomValueLiteral():
    d(new QmlDomBasicValuePrivate)
{
}

/*! 
    Create a copy of \a other QmlDomValueLiteral.
*/
QmlDomValueLiteral::QmlDomValueLiteral(const QmlDomValueLiteral &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomValueLiteral.
*/
QmlDomValueLiteral::~QmlDomValueLiteral()
{
}

/*!
    Assign \a other to this QmlDomValueLiteral.
*/
QmlDomValueLiteral &QmlDomValueLiteral::operator=(const QmlDomValueLiteral &other)
{
    d = other.d;
    return *this;
}

/*!
    Return the literal value.

    In the example below, the literal value will be the string "10".
    \code
    <Rect x="10" />
    \endcode
*/
QString QmlDomValueLiteral::literal() const
{
    if (d->value) return d->value->primitive;
    else return QString();
}

/*!
    Sets the literal \a value.
*/
void QmlDomValueLiteral::setLiteral(const QString &value)
{
    Q_UNUSED(value);
    qWarning("QmlDomValueLiteral::setLiteral(const QString &): Not implemented");
}

/*!
    \class QmlDomValueBinding
    \brief The QmlDomValueBinding class represents a property binding.

    A property binding is an ECMAScript expression assigned to a property.  In
    the example below, the "x" property is being assigned a property binding.

    \code
    <Rect x="{Other.x}" />
    \endcode
*/

/*!
    Construct an empty QmlDomValueBinding.
*/
QmlDomValueBinding::QmlDomValueBinding()
{
}

/*!
    Create a copy of \a other QmlDomValueBinding.
*/
QmlDomValueBinding::QmlDomValueBinding(const QmlDomValueBinding &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomValueBinding.
*/
QmlDomValueBinding::~QmlDomValueBinding()
{
}

/*!
    Assign \a other to this QmlDomValueBinding.
*/
QmlDomValueBinding &QmlDomValueBinding::operator=(const QmlDomValueBinding &other)
{
    d = other.d;
    return *this;
}

/*!
    Return the binding expression.

    In the example below, the string "Other.x" will be returned.
    \code
    <Rect x="{Other.x}" />
    \endcode
*/
QString QmlDomValueBinding::binding() const
{
    if (d->value) 
        return d->value->primitive.mid(1, d->value->primitive.length() - 2);
    else 
        return QString();
}

/*!
    Sets the binding \a expression.
*/
void QmlDomValueBinding::setBinding(const QString &expression)
{
    Q_UNUSED(expression);
    qWarning("QmlDomValueBinding::setBinding(const QString &): Not implemented");
}

/*!
    \class QmlDomValueValueSource
    \brief The QmlDomValueValueSource class represents a value source assignment value.

    In QML, value sources are special value generating types that may be 
    assigned to properties.  Value sources inherit the QmlPropertyValueSource
    class.  In the example below, the "x" property is being assigned the 
    NumericAnimation value source.

    \code
    <Rect>
        <x>
            <NumericAnimation from="0" to="100" repeat="true" running="true" />
        </x>
    </Rect>
    \endcode
*/

/*!
    Construct an empty QmlDomValueValueSource.
*/
QmlDomValueValueSource::QmlDomValueValueSource()
{
}

/*!
    Create a copy of \a other QmlDomValueValueSource.
*/
QmlDomValueValueSource::QmlDomValueValueSource(const QmlDomValueValueSource &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomValueValueSource.
*/
QmlDomValueValueSource::~QmlDomValueValueSource()
{
}

/*!
    Assign \a other to this QmlDomValueValueSource.
*/
QmlDomValueValueSource &QmlDomValueValueSource::operator=(const QmlDomValueValueSource &other)
{
    d = other.d;
    return *this;
}

/*!
    Return the value source object.

    In the example below, an object representing the NumericAnimation will be
    returned.
    \code
    <Rect>
        <x>
            <NumericAnimation from="0" to="100" repeat="true" running="true" />
        </x>
    </Rect>
    \endcode
*/
QmlDomObject QmlDomValueValueSource::object() const
{
    QmlDomObject rv;
    if (d->value) {
        rv.d->object = d->value->object;
        rv.d->object->addref();
    } 
    return QmlDomObject();
}

/*!
    Sets the value source \a object.
*/
void QmlDomValueValueSource::setObject(const QmlDomObject &object)
{
    Q_UNUSED(object);
    qWarning("QmlDomValueValueSource::setObject(const QmlDomObject &): Not implemented");
}

QmlDomValuePrivate::QmlDomValuePrivate()
: property(0), value(0)
{
}

QmlDomValuePrivate::QmlDomValuePrivate(const QmlDomValuePrivate &other)
: QSharedData(other), property(0), value(0)
{
    property = other.property;
    value = other.value;
    if (property) property->addref();
    if (value) value->addref();
}

QmlDomValuePrivate::~QmlDomValuePrivate()
{
    if (property) property->release();
    if (value) value->release();
}

/*!
    \class QmlDomValue
    \brief The QmlDomValue class represents a generic Qml value.

    QmlDomValue's can be assigned to QML \l {QmlDomProperty}{properties}.  In 
    QML, properties can be assigned various different values, including basic
    literals, property bindings, property value sources, objects and lists of
    values.  The QmlDomValue class allows a programmer to determine the specific
    value type being assigned and access more detailed information through a 
    corresponding value type class.

    For example, in the following example,

    \code
    <Text text="Hello World!" y="{Other.y}" />
    \endcode

    The text property is being assigned a literal, and the y property a property
    binding.  To output the values assigned to the text and y properties in the
    above example from C++,

    \code
    QmlDomDocument document;
    QmlDomObject root = document.rootObject();

    QmlDomProperty text = root.property("text");
    if (text.value().isLiteral()) {
        QmlDomValueLiteral literal = text.value().toLiteral();
        qDebug() << literal.literal();
    }

    QmlDomProperty y = root.property("y");
    if (y.value().isBinding()) {
        QmlDomValueBinding binding = y.value().toBinding();
        qDebug() << binding.binding();
    }
    \endcode
*/

/*!
    Construct an invalid QmlDomValue.
*/
QmlDomValue::QmlDomValue()
: d(new QmlDomValuePrivate)
{
}

/*!
    Create a copy of \a other QmlDomValue.
*/
QmlDomValue::QmlDomValue(const QmlDomValue &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomValue
*/
QmlDomValue::~QmlDomValue()
{
}

/*!
    Assign \a other to this QmlDomValue.
*/
QmlDomValue &QmlDomValue::operator=(const QmlDomValue &other)
{
    d = other.d;
    return *this;
}

/*!
    \enum QmlDomValue::Type

    The type of the QmlDomValue node.

    \value Invalid The QmlDomValue is invalid.
    \value Literal The QmlDomValue is a literal value assignment.  Use QmlDomValue::toLiteral() to access the type instance.
    \value PropertyBinding The QmlDomValue is a property binding.  Use QmlDomValue::toBinding() to access the type instance.
    \value ValueSource The QmlDomValue is a property value source.  Use QmlDomValue::toValueSource() to access the type instance.
    \value Object The QmlDomValue is an object assignment.  Use QmlDomValue::toObject() to access the type instnace.
    \value List The QmlDomValue is a list of other values.  Use QmlDomValue::toList() to access the type instance.
*/

/*!
    Returns the type of this QmlDomValue.
*/
QmlDomValue::Type QmlDomValue::type() const
{
    if (d->property)
        if (QmlMetaType::isList(d->property->type) || 
           QmlMetaType::isQmlList(d->property->type) ||
           (d->property && d->property->values.count() > 1))
            return List;

    QmlParser::Value *value = d->value;
    if (!value && !d->property)
        return Invalid;

    switch(value->type) {
    case QmlParser::Value::Unknown:
        return Invalid;
    case QmlParser::Value::Literal:
        return Literal;
    case QmlParser::Value::PropertyBinding:
        return PropertyBinding;
    case QmlParser::Value::ValueSource:
        return ValueSource;
    case QmlParser::Value::Component:
    case QmlParser::Value::CreatedObject:
        return Object;
    case QmlParser::Value::SignalObject:
        return Invalid;
    case QmlParser::Value::SignalExpression:
        return Literal;
    case QmlParser::Value::Id:
        return Invalid;
    }
    return Invalid;
}

/*!
    Returns true if this is an invalid value, otherwise false.
*/
bool QmlDomValue::isInvalid() const
{
    return type() == Invalid;
}

/*!
    Returns true if this is a literal value, otherwise false.
*/
bool QmlDomValue::isLiteral() const
{
    return type() == Literal;
}

/*!
    Returns true if this is a property binding value, otherwise false.
*/
bool QmlDomValue::isBinding() const
{
    return type() == PropertyBinding;
}

/*!
    Returns true if this is a value source value, otherwise false.
*/
bool QmlDomValue::isValueSource() const
{
    return type() == ValueSource;
}

/*!
    Returns true if this is an object value, otherwise false.
*/
bool QmlDomValue::isObject() const
{
    return type() == Object;
}

/*!
    Returns true if this is a list value, otherwise false.
*/
bool QmlDomValue::isList() const
{
    return type() == List;
}

/*!
    Returns a QmlDomValueLiteral if this value is a literal type, otherwise
    returns an invalid QmlDomValueLiteral.

    \sa QmlDomValue::type()
*/
QmlDomValueLiteral QmlDomValue::toLiteral() const
{
    QmlDomValueLiteral rv;
    if (type() == Literal) {
        rv.d->value = d->value;
        rv.d->value->addref();
    }
    return rv;
}

/*!
    Returns a QmlDomValueBinding if this value is a property binding type, 
    otherwise returns an invalid QmlDomValueBinding.

    \sa QmlDomValue::type()
*/
QmlDomValueBinding QmlDomValue::toBinding() const
{
    QmlDomValueBinding rv;
    if (type() == PropertyBinding) {
        rv.d->value = d->value;
        rv.d->value->addref();
    }
    return rv;
}

/*!
    Returns a QmlDomValueValueSource if this value is a property value source
    type, otherwise returns an invalid QmlDomValueValueSource.

    \sa QmlDomValue::type()
*/
QmlDomValueValueSource QmlDomValue::toValueSource() const
{
    QmlDomValueValueSource rv;
    if (type() == ValueSource) {
        rv.d->value = d->value;
        rv.d->value->addref();
    }
    return rv;
}

/*!
    Returns a QmlDomObject if this value is an object assignment type, otherwise
    returns an invalid QmlDomObject.

    \sa QmlDomValue::type()
*/
QmlDomObject QmlDomValue::toObject() const
{
    QmlDomObject rv;
    if (type() == Object) {
        rv.d->object = d->value->object;
        rv.d->object->addref();
    }
    return rv;
}

/*!
    Returns a QmlDomList if this value is a list type, otherwise returns an 
    invalid QmlDomList.

    \sa QmlDomValue::type()
*/
QmlDomList QmlDomValue::toList() const
{
    QmlDomList rv;
    if (type() == List) {
        rv.d = d;
    }
    return rv;
}

/*!
    \class QmlDomList
    \brief The QmlDomList class represents a list of values assigned to a QML property.

    Lists of values can be assigned to properties.  For example, the following
    example assigns multiple objects to Item's "children" property
    \code
    <Item>
        <children>
            <Text />
            <Rect />
        </children>
    </Item>
    \endcode

    Lists can also be implicitly created by assigning multiple 
    \l {QmlDomValueValueSource}{value sources} or constants to a property.
    \code
    <Item x="10">
        <x>
            <NumericAnimation running="false" from="0" to="100" />
        </x>
    </Item>
    \endcode
*/

/*!
    Construct an empty QmlDomList.
*/
QmlDomList::QmlDomList()
{
}

/*!
    Create a copy of \a other QmlDomList.
*/
QmlDomList::QmlDomList(const QmlDomList &other)
: d(other.d)
{
}

/*!
    Destroy the QmlDomList.
*/
QmlDomList::~QmlDomList()
{
}

/*!
    Assign \a other to this QmlDomList.
*/
QmlDomList &QmlDomList::operator=(const QmlDomList &other)
{
    d = other.d;
    return *this;
}

/*!
    Returns the list of QmlDomValue's.
*/
QList<QmlDomValue> QmlDomList::values() const
{
    QList<QmlDomValue> rv;
    if (!d->property)
        return rv;

    for (int ii = 0; ii < d->property->values.count(); ++ii) {
        QmlDomValue v;
        v.d->value = d->property->values.at(ii);
        v.d->value->addref();
        rv << v;
    }

    return rv;
}

/*! 
    Set the list of QmlDomValue's to \a values.
*/
void QmlDomList::setValues(const QList<QmlDomValue> &values)
{
    Q_UNUSED(values);
    qWarning("QmlDomList::setValues(const QList<QmlDomValue> &): Not implemented");
}


/*!
    \class QmlDomComponent
    \brief The QmlDomComponent class represents sub-component within a QML document.

    Sub-components are QmlComponents defined within a QML document.  The 
    following example shows the definition of a sub-component with the id 
    "ListDelegate".

    \code
    <Item>
        <Component id="ListDelegate">
            <Text text="{modelData.text}" />
        </Component>
    </Item>
    \endcode

    Like QmlDomDocument's, components contain a single root object.
*/

/*!
    Construct an empty QmlDomComponent.
*/
QmlDomComponent::QmlDomComponent()
{
}

/*!
    Create a copy of \a other QmlDomComponent.
*/
QmlDomComponent::QmlDomComponent(const QmlDomComponent &other)
: QmlDomObject(other)
{
}

/*!
    Destroy the QmlDomComponent.
*/
QmlDomComponent::~QmlDomComponent()
{
}

/*!
    Assign \a other to this QmlDomComponent.
*/
QmlDomComponent &QmlDomComponent::operator=(const QmlDomComponent &other)
{
    static_cast<QmlDomObject &>(*this) = other;
    return *this;
}

/*!
    Returns the component's root object.

    In the example below, the root object is the "Text" object.
    \code
    <Item>
        <Component id="ListDelegate">
            <Text text="{modelData.text}" />
        </Component>
    </Item>
    \endcode
*/
QmlDomObject QmlDomComponent::componentRoot() const
{
    QmlDomObject rv;
    if (d->isVirtualComponent) {
        rv.d->object = d->object;
        rv.d->object->addref();
    } else if (d->object) {
        QmlParser::Object *obj = 0;
        if (d->object->defaultProperty && 
           d->object->defaultProperty->values.count() == 1 &&
           d->object->defaultProperty->values.at(0)->object)
            obj = d->object->defaultProperty->values.at(0)->object;

        if (obj) {
            rv.d->object = obj;
            rv.d->object->addref();
        }
    }

    return rv;
}

/*!
    Set the component's \a root object.
*/
void QmlDomComponent::setComponentRoot(const QmlDomObject &root)
{
    Q_UNUSED(root);
    qWarning("QmlDomComponent::setComponentRoot(const QmlDomObject &): Not implemented");
}

QT_END_NAMESPACE