diff options
Diffstat (limited to 'src/declarative')
70 files changed, 1787 insertions, 1237 deletions
diff --git a/src/declarative/debugger/qmldebugger.cpp b/src/declarative/debugger/qmldebugger.cpp index aad11de..78c4090 100644 --- a/src/declarative/debugger/qmldebugger.cpp +++ b/src/declarative/debugger/qmldebugger.cpp @@ -50,6 +50,7 @@ #include <private/qmlboundsignal_p.h> #include <private/qmlcontext_p.h> #include <private/qmlengine_p.h> +#include <private/qmlexpression_p.h> #include <private/qmlobjecttree_p.h> #include <QtCore/qdebug.h> #include <QtCore/qfile.h> @@ -262,7 +263,7 @@ bool QmlDebugger::makeItem(QObject *obj, QmlDebuggerItem *item) delete item; return false; - } else if(QmlBoundSignal *bs = qobject_cast<QmlBoundSignal *>(obj)) { + } else if(qobject_cast<QmlBoundSignal *>(obj)) { delete item; return false; } else { diff --git a/src/declarative/debugger/qpacketprotocol.cpp b/src/declarative/debugger/qpacketprotocol.cpp index 7be23b7..d109836 100644 --- a/src/declarative/debugger/qpacketprotocol.cpp +++ b/src/declarative/debugger/qpacketprotocol.cpp @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE /*! \class QPacketProtocol + \internal \brief The QPacketProtocol class encapsulates communicating discrete packets across fragmented IO channels, such as TCP sockets. @@ -354,7 +355,7 @@ QIODevice * QPacketProtocol::device() /*! \class QPacket - \inpublicgroup QtBaseModule + \internal \brief The QPacket class encapsulates an unfragmentable packet of data to be transmitted by QPacketProtocol. @@ -476,7 +477,7 @@ void QPacket::clear() /*! \class QPacketAutoSend - \inpublicgroup QtBaseModule + \internal \internal */ diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro index 9f555fe..4bf267c 100644 --- a/src/declarative/declarative.pro +++ b/src/declarative/declarative.pro @@ -19,7 +19,6 @@ include(util/util.pri) include(fx/fx.pri) include(canvas/canvas.pri) include(qml/qml.pri) -include(timeline/timeline.pri) include(extra/extra.pri) include(widgets/widgets.pri) include(test/test.pri) diff --git a/src/declarative/extra/qfxflowview.cpp b/src/declarative/extra/qfxflowview.cpp index 254e423..412cbc8 100644 --- a/src/declarative/extra/qfxflowview.cpp +++ b/src/declarative/extra/qfxflowview.cpp @@ -199,8 +199,6 @@ void QFxFlowView::reflowDrag(const QPointF &dp) qreal maxY = 0; qreal x = 0; - int flowedItems = 0; - clearTimeLine(); QList<QFxItem *> items; @@ -316,6 +314,7 @@ QRectF QFxFlowView::rectForItem(int idx) const void QFxFlowView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { + Q_UNUSED(event); if (m_dragItem) { m_dragItem->setZ(0); diff --git a/src/declarative/extra/qfxflowview.h b/src/declarative/extra/qfxflowview.h index 2bec6a1..126f567 100644 --- a/src/declarative/extra/qfxflowview.h +++ b/src/declarative/extra/qfxflowview.h @@ -42,7 +42,7 @@ #ifndef QFXFLOWVIEW_H #define QFXFLOWVIEW_H -#include <QtDeclarative/QmlTimeLine> +#include <private/qmltimeline_p.h> #include <QtDeclarative/qfxitem.h> QT_BEGIN_HEADER diff --git a/src/declarative/extra/qfxparticles.cpp b/src/declarative/extra/qfxparticles.cpp index 62fe4c1..3130f06 100644 --- a/src/declarative/extra/qfxparticles.cpp +++ b/src/declarative/extra/qfxparticles.cpp @@ -54,7 +54,7 @@ #define INT_MAX 2147483647 #endif #include <qfxpixmap.h> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <private/qmlanimation_p.h> #include "qfxparticles.h" diff --git a/src/declarative/extra/qmlfolderlistmodel.cpp b/src/declarative/extra/qmlfolderlistmodel.cpp index 8b008a5..acee5e1 100644 --- a/src/declarative/extra/qmlfolderlistmodel.cpp +++ b/src/declarative/extra/qmlfolderlistmodel.cpp @@ -51,7 +51,7 @@ class QmlFolderListModelPrivate : public QObjectPrivate public: QmlFolderListModelPrivate() : count(0) { folder = QDir::currentPath(); - nameFilters << "*"; + nameFilters << QLatin1String("*"); } QDirModel model; @@ -81,6 +81,7 @@ QmlFolderListModel::~QmlFolderListModel() QHash<int,QVariant> QmlFolderListModel::data(int index, const QList<int> &roles) const { + Q_UNUSED(roles); Q_D(const QmlFolderListModel); QHash<int,QVariant> folderData; QModelIndex modelIndex = d->model.index(index, 0, d->folderIndex); diff --git a/src/declarative/extra/qmlxmllistmodel.cpp b/src/declarative/extra/qmlxmllistmodel.cpp index 48949b3..95c3de6 100644 --- a/src/declarative/extra/qmlxmllistmodel.cpp +++ b/src/declarative/extra/qmlxmllistmodel.cpp @@ -289,11 +289,11 @@ class QmlXmlListModelPrivate : public QObjectPrivate Q_DECLARE_PUBLIC(QmlXmlListModel) public: QmlXmlListModelPrivate() - : isClassComplete(false), size(-1), highestRole(Qt::UserRole) + : isComponentComplete(true), size(-1), highestRole(Qt::UserRole) , reply(0), status(QmlXmlListModel::Idle), progress(0.0) , queryId(-1), roleObjects(this) {} - bool isClassComplete; + bool isComponentComplete; QUrl src; QString query; QString namespaces; @@ -549,10 +549,16 @@ qreal QmlXmlListModel::progress() const return d->progress; } -void QmlXmlListModel::classComplete() +void QmlXmlListModel::classBegin() { Q_D(QmlXmlListModel); - d->isClassComplete = true; + d->isComponentComplete = false; +} + +void QmlXmlListModel::componentComplete() +{ + Q_D(QmlXmlListModel); + d->isComponentComplete = true; reload(); } @@ -566,7 +572,7 @@ void QmlXmlListModel::reload() { Q_D(QmlXmlListModel); - if (!d->isClassComplete) + if (!d->isComponentComplete) return; d->qmlXmlQuery.abort(); diff --git a/src/declarative/extra/qmlxmllistmodel.h b/src/declarative/extra/qmlxmllistmodel.h index 804f13f..d9871ab 100644 --- a/src/declarative/extra/qmlxmllistmodel.h +++ b/src/declarative/extra/qmlxmllistmodel.h @@ -124,7 +124,8 @@ public: Status status() const; qreal progress() const; - virtual void classComplete(); + virtual void classBegin(); + virtual void componentComplete(); signals: void statusChanged(Status); diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri index fd6e480..0c26356 100644 --- a/src/declarative/fx/fx.pri +++ b/src/declarative/fx/fx.pri @@ -4,8 +4,6 @@ HEADERS += \ fx/qfxblurfilter.h \ fx/qfxcomponentinstance.h \ fx/qfxcomponentinstance_p.h \ - fx/qfxcontentwrapper.h \ - fx/qfxcontentwrapper_p.h \ fx/qfxevents_p.h \ fx/qfxflickable.h \ fx/qfxflickable_p.h \ @@ -51,7 +49,6 @@ SOURCES += \ fx/qfxanchors.cpp \ fx/qfxblurfilter.cpp \ fx/qfxcomponentinstance.cpp \ - fx/qfxcontentwrapper.cpp \ fx/qfxevents.cpp \ fx/qfxflickable.cpp \ fx/qfxflipable.cpp \ diff --git a/src/declarative/fx/qfxcomponentinstance.cpp b/src/declarative/fx/qfxcomponentinstance.cpp index d3f7061..6cf8e74 100644 --- a/src/declarative/fx/qfxcomponentinstance.cpp +++ b/src/declarative/fx/qfxcomponentinstance.cpp @@ -41,8 +41,7 @@ #include "qfxcomponentinstance.h" #include "qfxcomponentinstance_p.h" -#include <qfxperf.h> -#include <qfxcontentwrapper.h> +#include <private/qfxperf_p.h> #include <QtDeclarative/qmlinfo.h> diff --git a/src/declarative/fx/qfxcontentwrapper.cpp b/src/declarative/fx/qfxcontentwrapper.cpp deleted file mode 100644 index 482442b..0000000 --- a/src/declarative/fx/qfxcontentwrapper.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/**************************************************************************** -** -** 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 "qfxcontentwrapper.h" -#include "qfxcontentwrapper_p.h" - - -QT_BEGIN_NAMESPACE -QML_DEFINE_TYPE(QFxContentWrapper,ContentWrapper) - -/*! - \qmlclass ContentWrapper QFxContentWrapper - \ingroup group_utility - \brief ContentWrapper provides a component which contains content. - \inherits Item - - In some cases the content of a component is not defined by the component itself. - For example, the items placed in a group box need to be specified external to - group box component definition itself. - In cases like these \l Content can be used to specify at what location in the component - the content should be placed. It is used in conjuntion with the \e content property of - ContentWrapper: any items listed as content will be placed in the location - specified by Content. The component containing the Content must be of type - ContentWrapper. - - GroupBox component definition: - \quotefile doc/src/snippets/declarative/GroupBox.qml - - \bold Note that in the above component definition ContentWrapper's \e children - property is specified explicitly since \e content is the default property. - - Component use: - \table - \row \o \image content.png - \o \quotefile doc/src/snippets/declarative/content.qml - \endtable - - \sa Content -*/ - -QFxContentWrapper::QFxContentWrapper(QFxItem *parent) -: QFxItem(*(new QFxContentWrapperPrivate), parent) -{ -} - -QFxContentWrapper::QFxContentWrapper(QFxContentWrapperPrivate &dd, QFxItem *parent) - : QFxItem(dd, parent) -{ -} - -/*! - \qmlproperty list<Item> ContentWrapper::content - - Contains the list of elements to replace the \l Content - placeholder. - - \sa Content -*/ -QList<QFxItem *> *QFxContentWrapper::content() -{ - Q_D(QFxContentWrapper); - return &(d->_content); -} - -void QFxContentWrapper::componentComplete() -{ - QFxItem::componentComplete(); - if (content()->size() < 1) - return; - - QList<QSimpleCanvasItem *> nodes; - nodes.append(this); - QFxItem *target = findContent(nodes); - if (!target) - return; - target = target->itemParent(); - - QList<QFxItem*> myContent(*content()); - for (int ii = 0; ii < myContent.count(); ++ii) - myContent.at(ii)->setParent(target); -} - -QFxItem *QFxContentWrapper::findContent(QList<QSimpleCanvasItem *> &nodes) -{ - QSimpleCanvasItem *item = nodes.takeFirst(); - if (qobject_cast<QFxContent*>(item)) - return static_cast<QFxItem *>(item); - nodes << item->children(); - if (nodes.isEmpty()) - return 0; - return findContent(nodes); -} - -QML_DEFINE_TYPE(QFxContent,Content) - -/*! - \qmlclass Content QFxContent - \ingroup group_utility - \brief Content is used as a placeholder for the content of a component. - \inherits Item - - The Content element is used to place content within a component. - See \l ContentWrapper for usage. -*/ - -QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxcontentwrapper.h b/src/declarative/fx/qfxcontentwrapper.h deleted file mode 100644 index 9a9a89c..0000000 --- a/src/declarative/fx/qfxcontentwrapper.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QFXCONTENTWRAPPER_H -#define QFXCONTENTWRAPPER_H - -#include <QtDeclarative/qfxitem.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QFxContentWrapperPrivate; -class Q_DECLARATIVE_EXPORT QFxContentWrapper : public QFxItem -{ - Q_OBJECT - - Q_PROPERTY(QList<QFxItem *>* content READ content DESIGNABLE false) - Q_CLASSINFO("DefaultProperty", "content") -public: - QFxContentWrapper(QFxItem *parent=0); - - QList<QFxItem *> *content(); - -private: - void create(); - QFxItem *findContent(QList<QSimpleCanvasItem *> &nodes); - -protected: - void componentComplete(); - QFxContentWrapper(QFxContentWrapperPrivate &dd, QFxItem *parent); - -private: - Q_DECLARE_PRIVATE(QFxContentWrapper) -}; - -class Q_DECLARATIVE_EXPORT QFxContent : public QFxItem -{ - Q_OBJECT -public: - QFxContent(QFxItem *parent=0) : QFxItem(parent) {} -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QFxContentWrapper) -QML_DECLARE_TYPE(QFxContent) - -QT_END_HEADER - -#endif // QFXCONTENTWRAPPER_H diff --git a/src/declarative/fx/qfxflickable_p.h b/src/declarative/fx/qfxflickable_p.h index a3b1500..28ec6d8 100644 --- a/src/declarative/fx/qfxflickable_p.h +++ b/src/declarative/fx/qfxflickable_p.h @@ -57,7 +57,7 @@ #include "qfxflickable.h" #include "qfxitem_p.h" #include "qml.h" -#include "qmltimelinevalueproxy.h" +#include "private/qmltimeline_p.h" #include "private/qmlanimation_p.h" QT_BEGIN_NAMESPACE diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 58d597a..539ad02 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -41,7 +41,7 @@ #include "qfximage.h" #include "qfximage_p.h" -#include <qfxperf.h> +#include <private/qfxperf_p.h> #if defined(QFX_RENDER_OPENGL) #include <glsave.h> #endif diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index b5c2c0e..bd4def4 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -47,7 +47,7 @@ #include <QNetworkRequest> #include <QGraphicsSceneMouseEvent> #include <QtScript/qscriptengine.h> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include "qmlengine.h" #include "qmlstate.h" diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h index 2b45f73..5fb4eff 100644 --- a/src/declarative/fx/qfxitem.h +++ b/src/declarative/fx/qfxitem.h @@ -103,9 +103,9 @@ class Q_DECLARATIVE_EXPORT QFxItem : public QSimpleCanvasItem, public QmlParserS Q_PROPERTY(QString id READ id WRITE setId) Q_PROPERTY(QmlList<QFxItem *>* children READ children DESIGNABLE false) Q_PROPERTY(QmlList<QObject *>* resources READ resources DESIGNABLE false) - Q_PROPERTY(QFxAnchors * anchors READ anchors DESIGNABLE false) + Q_PROPERTY(QFxAnchors * anchors READ anchors DESIGNABLE false CONSTANT) Q_PROPERTY(QmlList<QObject *> *data READ data DESIGNABLE false) - Q_PROPERTY(QFxContents * contents READ contents DESIGNABLE false) + Q_PROPERTY(QFxContents * contents READ contents DESIGNABLE false CONSTANT) Q_PROPERTY(QmlList<QmlState *>* states READ states DESIGNABLE false) Q_PROPERTY(QmlList<QmlTransition *>* transitions READ transitions DESIGNABLE false) Q_PROPERTY(QString state READ state WRITE setState NOTIFY stateChanged) @@ -116,13 +116,13 @@ class Q_DECLARATIVE_EXPORT QFxItem : public QSimpleCanvasItem, public QmlParserS Q_PROPERTY(qreal z READ z WRITE setZ) Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY widthChanged) Q_PROPERTY(qreal height READ height WRITE setHeight NOTIFY heightChanged) - Q_PROPERTY(QFxAnchorLine left READ left) - Q_PROPERTY(QFxAnchorLine right READ right) - Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter) - Q_PROPERTY(QFxAnchorLine top READ top) - Q_PROPERTY(QFxAnchorLine bottom READ bottom) - Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter) - Q_PROPERTY(QFxAnchorLine baseline READ baseline) + Q_PROPERTY(QFxAnchorLine left READ left CONSTANT) + Q_PROPERTY(QFxAnchorLine right READ right CONSTANT) + Q_PROPERTY(QFxAnchorLine horizontalCenter READ horizontalCenter CONSTANT) + Q_PROPERTY(QFxAnchorLine top READ top CONSTANT) + Q_PROPERTY(QFxAnchorLine bottom READ bottom CONSTANT) + Q_PROPERTY(QFxAnchorLine verticalCenter READ verticalCenter CONSTANT) + Q_PROPERTY(QFxAnchorLine baseline READ baseline CONSTANT) Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged) Q_PROPERTY(bool flipVertically READ flipVertically WRITE setFlipVertically) Q_PROPERTY(bool flipHorizontally READ flipHorizontally WRITE setFlipHorizontally) diff --git a/src/declarative/fx/qfxlayouts.cpp b/src/declarative/fx/qfxlayouts.cpp index af51318..20e7c7c 100644 --- a/src/declarative/fx/qfxlayouts.cpp +++ b/src/declarative/fx/qfxlayouts.cpp @@ -45,7 +45,7 @@ #include "qmlstate.h" #include "qmlstategroup.h" #include "qmlstateoperations.h" -#include "qfxperf.h" +#include "private/qfxperf_p.h" #include "qfxlayouts.h" #include "qfxlayouts_p.h" diff --git a/src/declarative/fx/qfxpath.cpp b/src/declarative/fx/qfxpath.cpp index be731b1..4c241d3 100644 --- a/src/declarative/fx/qfxpath.cpp +++ b/src/declarative/fx/qfxpath.cpp @@ -41,7 +41,7 @@ #include "qfxpath.h" #include "qfxpath_p.h" -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <private/qbezier_p.h> diff --git a/src/declarative/fx/qfxpathview_p.h b/src/declarative/fx/qfxpathview_p.h index b5c5ba2..b77c2a0 100644 --- a/src/declarative/fx/qfxpathview_p.h +++ b/src/declarative/fx/qfxpathview_p.h @@ -58,7 +58,6 @@ #include "qfxitem_p.h" #include "qfxvisualitemmodel.h" #include "qml.h" -#include "qmltimelinevalueproxy.h" #include "private/qmlanimation_p.h" QT_BEGIN_NAMESPACE diff --git a/src/declarative/fx/qfxpixmap.cpp b/src/declarative/fx/qfxpixmap.cpp index 0ea94f5..5ee6528 100644 --- a/src/declarative/fx/qfxpixmap.cpp +++ b/src/declarative/fx/qfxpixmap.cpp @@ -43,7 +43,7 @@ #include <QHash> #include <QNetworkReply> #include <QPixmapCache> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <QtDeclarative/qmlengine.h> #include <QFile> diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp index d1e118d..57897ed 100644 --- a/src/declarative/fx/qfxtext.cpp +++ b/src/declarative/fx/qfxtext.cpp @@ -48,7 +48,7 @@ #include "glbasicshaders.h" #endif -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <QTextLayout> #include <QTextLine> #include <QTextDocument> @@ -162,7 +162,7 @@ void QFxText::setText(const QString &n) if (d->text == n) return; - d->richText = Qt::mightBeRichText(n); // ### what's the cost? + d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n)); if (d->richText) { if (!d->doc) { @@ -170,7 +170,7 @@ void QFxText::setText(const QString &n) d->control->setTextInteractionFlags(Qt::TextBrowserInteraction); d->doc = d->control->document(); d->doc->setDocumentMargin(0); - } + } d->doc->setHtml(n); } @@ -377,6 +377,77 @@ void QFxText::setWrap(bool w) } /*! + \qmlproperty enumeration Text::textFormat + + The way the text property should be displayed. + + Supported text formats are \c AutoText, \c PlainText and \c RichText. + + The default is AutoText. If the text format is AutoText the text element + will automatically determine whether the text should be treated as + rich text. This determination is made using Qt::mightBeRichText(). + + \table + \row + \o + \qml +VerticalLayout { + TextEdit { + font.size: 24 + text: "<b>Hello</b> <i>World!</i>" + } + TextEdit { + font.size: 24 + textFormat: "RichText" + text: "<b>Hello</b> <i>World!</i>" + } + TextEdit { + font.size: 24 + textFormat: "PlainText" + text: "<b>Hello</b> <i>World!</i>" + } +} + \endqml + \o \image declarative-textformat.png + \endtable +*/ + +QFxText::TextFormat QFxText::textFormat() const +{ + Q_D(const QFxText); + return d->format; +} + +void QFxText::setTextFormat(TextFormat format) +{ + Q_D(QFxText); + if (format == d->format) + return; + bool wasRich = d->richText; + d->richText = format == RichText || (format == AutoText && Qt::mightBeRichText(d->text)); + + if (wasRich && !d->richText) { + //### delete control? (and vice-versa below) + d->imgDirty = true; + d->updateSize(); + update(); + } else if (!wasRich && d->richText) { + if (!d->doc) + { + d->control = new QTextControl(this); + d->control->setTextInteractionFlags(Qt::TextBrowserInteraction); + d->doc = d->control->document(); + d->doc->setDocumentMargin(0); + } + d->doc->setHtml(d->text); + d->imgDirty = true; + d->updateSize(); + update(); + } + d->format = format; +} + +/*! \qmlproperty Qt::TextElideMode Text::elide Set this property to elide parts of the text fit to the Text item's width. diff --git a/src/declarative/fx/qfxtext.h b/src/declarative/fx/qfxtext.h index 104d18c..bd91f0e 100644 --- a/src/declarative/fx/qfxtext.h +++ b/src/declarative/fx/qfxtext.h @@ -58,15 +58,17 @@ class Q_DECLARATIVE_EXPORT QFxText : public QFxItem Q_ENUMS(HAlignment) Q_ENUMS(VAlignment) Q_ENUMS(TextStyle) + Q_ENUMS(TextFormat) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) - Q_PROPERTY(QmlFont *font READ font) + Q_PROPERTY(QmlFont *font READ font CONSTANT) Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(TextStyle style READ style WRITE setStyle) Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor) Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign) Q_PROPERTY(VAlignment vAlign READ vAlign WRITE setVAlign) Q_PROPERTY(bool wrap READ wrap WRITE setWrap) + Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat) Q_PROPERTY(Qt::TextElideMode elide READ elideMode WRITE setElideMode) Q_PROPERTY(QString activeLink READ activeLink) Q_PROPERTY(bool smooth READ smoothTransform WRITE setSmoothTransform) @@ -85,6 +87,9 @@ public: Outline, Raised, Sunken }; + enum TextFormat { AutoText, + PlainText, + RichText }; QString text() const; void setText(const QString &); @@ -109,6 +114,9 @@ public: bool wrap() const; void setWrap(bool w); + TextFormat textFormat() const; + void setTextFormat(TextFormat format); + Qt::TextElideMode elideMode() const; void setElideMode(Qt::TextElideMode); diff --git a/src/declarative/fx/qfxtext_p.h b/src/declarative/fx/qfxtext_p.h index c58705c..670b685 100644 --- a/src/declarative/fx/qfxtext_p.h +++ b/src/declarative/fx/qfxtext_p.h @@ -75,7 +75,8 @@ public: QFxTextPrivate() : _font(0), color((QRgb)0), style(QFxText::Normal), imgDirty(true), hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(Qt::ElideNone), - dirty(false), wrap(false), smooth(false), richText(false), singleline(false), control(0), doc(0) + dirty(false), wrap(false), smooth(false), richText(false), singleline(false), control(0), doc(0), + format(QFxText::AutoText) { } @@ -132,6 +133,7 @@ public: QTextDocument *doc; QTextLayout layout; QSize cachedLayoutSize; + QFxText::TextFormat format; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 03dd63f..87a27d9 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -48,7 +48,7 @@ #include "glbasicshaders.h" #endif -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include "qfxevents_p.h" #include <QTextLayout> #include <QTextLine> @@ -179,7 +179,7 @@ void QFxTextEdit::setText(const QString &text) Supported text formats are \c AutoText, \c PlainText and \c RichText. The default is AutoText. If the text format is AutoText the text edit - edit will automatically determine whether the text should be treated as + will automatically determine whether the text should be treated as rich text. This determination is made using Qt::mightBeRichText(). \table @@ -324,6 +324,36 @@ void QFxTextEdit::setHighlightColor(const QColor &color) } /*! + \qmlproperty color TextEdit::highlightedTextColor + + The highlighted text color, used in selections. +*/ + +/*! + \property QFxTextEdit::highlightedTextColor + \brief the text edit's default highlighted text color +*/ +QColor QFxTextEdit::highlightedTextColor() const +{ + Q_D(const QFxTextEdit); + return d->highlightColor; +} + +void QFxTextEdit::setHighlightedTextColor(const QColor &color) +{ + Q_D(QFxTextEdit); + if (d->highlightedTextColor == color) + return; + + clearCache(); + d->highlightedTextColor = color; + QPalette pal = d->control->palette(); + pal.setColor(QPalette::HighlightedText, color); + d->control->setPalette(pal); + update(); +} + +/*! \qmlproperty enumeration TextEdit::hAlign \qmlproperty enumeration TextEdit::vAlign @@ -410,7 +440,7 @@ void QFxTextEdit::setWrap(bool w) } /*! - \property QFxTextEdit::cursorVisible + \qmlproperty TextEdit::cursorVisible \brief If true the text edit shows a cursor. This property is set and unset when the text edit gets focus, but it can also @@ -435,6 +465,162 @@ void QFxTextEdit::setCursorVisible(bool on) } /*! + \qmlproperty TextEdit::cursorPosition + \brief The position of the cursor in the TextEdit. +*/ +int QFxTextEdit::cursorPosition() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().position(); +} + +void QFxTextEdit::setCursorPosition(int pos) +{ + Q_D(QFxTextEdit); + QTextCursor cursor = d->control->textCursor(); + if (cursor.position() == pos) + return; + cursor.setPosition(pos); + d->control->setTextCursor(cursor); +} + +/*! + \qmlproperty TextEdit::cursorDelegate + \brief The delegate for the cursor in the TextEdit. + + If you set a cursorDelegate for a TextEdit, this delegate will be used for + drawing the cursor instead of the standard cursor. An instance of the + delegate will be created and managed by the text edit when a cursor is + needed, and the x and y properties of delegate instance will be set so as + to be one pixel before the top left of the current character. + + Note that the root item of the delegate component must be a QFxItem or + QFxItem derived item. +*/ +QmlComponent* QFxTextEdit::cursorDelegate() const +{ + Q_D(const QFxTextEdit); + return d->cursorComponent; +} + +void QFxTextEdit::setCursorDelegate(QmlComponent* c) +{ + Q_D(QFxTextEdit); + if(d->cursorComponent){ + delete d->cursorComponent; + if(d->cursor){ + disconnect(d->control, SIGNAL(cursorPositionChanged()), + this, SLOT(moveCursorDelegate())); + d->control->setCursorWidth(-1); + dirtyCache(cursorRect()); + delete d->cursor; + d->cursor = 0; + } + } + d->cursorComponent = c; + if(c && c->isReady()){ + loadCursorDelegate(); + }else{ + connect(c, SIGNAL(statusChanged()), + this, SLOT(loadCursorDelegate())); + } +} + +void QFxTextEdit::loadCursorDelegate() +{ + Q_D(QFxTextEdit); + if(d->cursorComponent->isLoading()) + return; + d->cursor = qobject_cast<QFxItem*>(d->cursorComponent->create(qmlContext(this))); + if(d->cursor){ + connect(d->control, SIGNAL(cursorPositionChanged()), + this, SLOT(moveCursorDelegate())); + d->control->setCursorWidth(0); + dirtyCache(cursorRect()); + d->cursor->setItemParent(this); + moveCursorDelegate(); + }else{ + qWarning() << "Error loading cursor delegate for TextEdit:" + objectName(); + } +} + +/*! + \qmlproperty int TextEdit::selectionStart + + The cursor position before the first character in the current selection. + Setting this and selectionEnd allows you to specify a selection in the + text edit. + + Note that if selectionStart == selectionEnd then there is no current + selection. If you attempt to set selectionStart to a value outside of + the current text, selectionStart will not be changed. + + \sa selectionEnd, cursorPosition, selectedText +*/ +int QFxTextEdit::selectionStart() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().selectionStart(); +} + +void QFxTextEdit::setSelectionStart(int s) +{ + Q_D(QFxTextEdit); + if(d->lastSelectionStart == s || s < 0 || s > text().length()) + return; + d->lastSelectionStart = s; + d->updateSelection();// Will emit the relevant signals +} + +/*! + \qmlproperty int TextEdit::selectionEnd + + The cursor position after the last character in the current selection. + Setting this and selectionStart allows you to specify a selection in the + text edit. + + Note that if selectionStart == selectionEnd then there is no current + selection. If you attempt to set selectionEnd to a value outside of + the current text, selectionEnd will not be changed. + + \sa selectionStart, cursorPosition, selectedText +*/ +int QFxTextEdit::selectionEnd() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().selectionEnd(); +} + +void QFxTextEdit::setSelectionEnd(int s) +{ + Q_D(QFxTextEdit); + if(d->lastSelectionEnd == s || s < 0 || s > text().length()) + return; + d->lastSelectionEnd = s; + d->updateSelection();// Will emit the relevant signals +} + +/*! + \qmlproperty string TextEdit::selectedText + + This read-only property provides the text currently selected in the + text edit. + + It is equivalent to the following snippet, but is faster and easier + to use. + \code + //myTextEdit is the id of the TextEdit + myTextEdit.text.toString().substring(myTextEdit.selectionStart, + myTextEdit.selectionEnd); + \endcode +*/ +QString QFxTextEdit::selectedText() const +{ + Q_D(const QFxTextEdit); + return d->control->textCursor().selectedText(); +} + +/*! \qmlproperty bool TextEdit::focusOnPress Whether the TextEdit should gain focus on a mouse press. By default this is @@ -860,6 +1046,9 @@ void QFxTextEditPrivate::init() QObject::connect(control, SIGNAL(updateRequest(QRectF)), q, SLOT(updateImgCache(QRectF))); QObject::connect(control, SIGNAL(textChanged()), q, SLOT(q_textChanged())); + QObject::connect(control, SIGNAL(selectionChanged()), q, SIGNAL(selectionChanged())); + QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); + QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); document = control->document(); @@ -877,6 +1066,51 @@ void QFxTextEdit::q_textChanged() emit textChanged(text()); } +void QFxTextEdit::moveCursorDelegate() +{ + Q_D(QFxTextEdit); + if(!d->cursor) + return; + QRectF cursorRect = d->control->cursorRect(); + d->cursor->setX(cursorRect.x()); + d->cursor->setY(cursorRect.y()); +} + +void QFxTextEditPrivate::updateSelection() +{ + Q_Q(QFxTextEdit); + QTextCursor cursor = control->textCursor(); + bool startChange = (lastSelectionStart != cursor.selectionStart()); + bool endChange = (lastSelectionEnd != cursor.selectionEnd()); + //### Is it worth calculating a more minimal set of movements? + cursor.beginEditBlock(); + cursor.setPosition(lastSelectionStart, QTextCursor::MoveAnchor); + cursor.setPosition(lastSelectionEnd, QTextCursor::KeepAnchor); + cursor.endEditBlock(); + control->setTextCursor(cursor); + if(startChange) + q->selectionStartChanged(); + if(endChange) + q->selectionEndChanged(); + startChange = (lastSelectionStart != control->textCursor().selectionStart()); + endChange = (lastSelectionEnd != control->textCursor().selectionEnd()); + if(startChange || endChange) + qWarning() << "QFxTextEditPrivate::updateSelection() has failed you."; +} + +void QFxTextEdit::updateSelectionMarkers() +{ + Q_D(QFxTextEdit); + if(d->lastSelectionStart != d->control->textCursor().selectionStart()){ + d->lastSelectionStart = d->control->textCursor().selectionStart(); + emit selectionStartChanged(); + } + if(d->lastSelectionEnd != d->control->textCursor().selectionEnd()){ + d->lastSelectionEnd = d->control->textCursor().selectionEnd(); + emit selectionEndChanged(); + } +} + //### we should perhaps be a bit smarter here -- depending on what has changed, we shouldn't // need to do all the calculations each time void QFxTextEdit::updateSize() diff --git a/src/declarative/fx/qfxtextedit.h b/src/declarative/fx/qfxtextedit.h index 24ba3fe..80636e2 100644 --- a/src/declarative/fx/qfxtextedit.h +++ b/src/declarative/fx/qfxtextedit.h @@ -70,6 +70,7 @@ class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor) + Q_PROPERTY(QColor highlightedTextColor READ highlightedTextColor WRITE setHighlightedTextColor) Q_PROPERTY(QmlFont * font READ font) Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign) Q_PROPERTY(VAlignment vAlign READ vAlign WRITE setVAlign) @@ -77,6 +78,11 @@ class Q_DECLARATIVE_EXPORT QFxTextEdit : public QFxPaintedItem Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat) Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible) + Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) + Q_PROPERTY(QmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate) + Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged) + Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged) + Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectionChanged) Q_PROPERTY(bool focusOnPress READ focusOnPress WRITE setFocusOnPress) Q_PROPERTY(bool preserveSelection READ preserveSelection WRITE setPreserveSelection) Q_PROPERTY(qreal textMargin READ textMargin WRITE setTextMargin) @@ -117,6 +123,9 @@ public: QColor highlightColor() const; void setHighlightColor(const QColor &c); + QColor highlightedTextColor() const; + void setHighlightedTextColor(const QColor &c); + HAlignment hAlign() const; void setHAlign(HAlignment align); @@ -129,6 +138,20 @@ public: bool isCursorVisible() const; void setCursorVisible(bool on); + int cursorPosition() const; + void setCursorPosition(int pos); + + QmlComponent* cursorDelegate() const; + void setCursorDelegate(QmlComponent*); + + int selectionStart() const; + void setSelectionStart(int); + + int selectionEnd() const; + void setSelectionEnd(int); + + QString selectedText() const; + bool focusOnPress() const; void setFocusOnPress(bool on); @@ -164,6 +187,9 @@ public: Q_SIGNALS: void textChanged(const QString &); void cursorPositionChanged(); + void selectionStartChanged(); + void selectionEndChanged(); + void selectionChanged(); public Q_SLOTS: void selectAll(); @@ -172,6 +198,9 @@ private Q_SLOTS: void fontChanged(); void updateImgCache(const QRectF &rect); void q_textChanged(); + void updateSelectionMarkers(); + void moveCursorDelegate(); + void loadCursorDelegate(); private: void updateSize(); diff --git a/src/declarative/fx/qfxtextedit_p.h b/src/declarative/fx/qfxtextedit_p.h index f733a4c..b7d667e 100644 --- a/src/declarative/fx/qfxtextedit_p.h +++ b/src/declarative/fx/qfxtextedit_p.h @@ -69,8 +69,9 @@ class QFxTextEditPrivate : public QFxPaintedItemPrivate public: QFxTextEditPrivate() : font(0), color("black"), imgDirty(true), hAlign(QFxTextEdit::AlignLeft), vAlign(QFxTextEdit::AlignTop), - dirty(false), wrap(false), richText(false), cursorVisible(false), focusOnPress(false), preserveSelection(true), - textMargin(0.0), format(QFxTextEdit::AutoText), document(0) + dirty(false), wrap(false), richText(false), cursorVisible(false), focusOnPress(false), + preserveSelection(true), textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), + cursor(0), cursorComponent(0), format(QFxTextEdit::AutoText), document(0) { } @@ -78,11 +79,13 @@ public: void updateDefaultTextOption(); void relayoutDocument(); + void updateSelection(); QString text; QmlFont font; QColor color; QColor highlightColor; + QColor highlightedTextColor; QString style; QColor styleColor; bool imgDirty; @@ -100,6 +103,10 @@ public: bool focusOnPress; bool preserveSelection; qreal textMargin; + int lastSelectionStart; + int lastSelectionEnd; + QmlComponent* cursorComponent; + QFxItem* cursor; QFxTextEdit::TextFormat format; QTextDocument *document; QTextControl *control; diff --git a/src/declarative/fx/qfxvisualitemmodel.h b/src/declarative/fx/qfxvisualitemmodel.h index 9cacde4..551c08d 100644 --- a/src/declarative/fx/qfxvisualitemmodel.h +++ b/src/declarative/fx/qfxvisualitemmodel.h @@ -70,7 +70,7 @@ class Q_DECLARATIVE_EXPORT QFxVisualItemModel : public QObject Q_PROPERTY(QVariant model READ model WRITE setModel) Q_PROPERTY(QmlComponent *delegate READ delegate WRITE setDelegate) Q_PROPERTY(QString part READ part WRITE setPart) - Q_PROPERTY(QObject *parts READ parts) + Q_PROPERTY(QObject *parts READ parts CONSTANT) Q_CLASSINFO("DefaultProperty", "delegate") public: QFxVisualItemModel(); diff --git a/src/declarative/qml/qml.h b/src/declarative/qml/qml.h index 1990b7f..cd01f6a 100644 --- a/src/declarative/qml/qml.h +++ b/src/declarative/qml/qml.h @@ -93,10 +93,10 @@ class QmlEngine; Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *); Q_DECLARATIVE_EXPORT QmlContext *qmlContext(const QObject *); Q_DECLARATIVE_EXPORT QmlEngine *qmlEngine(const QObject *); -Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *); +Q_DECLARATIVE_EXPORT QObject *qmlAttachedPropertiesObjectById(int, const QObject *, bool create = true); template<typename T> -QObject *qmlAttachedPropertiesObject(const QObject *obj) +QObject *qmlAttachedPropertiesObject(const QObject *obj, bool create = true) { // ### is this threadsafe? static int idx = -1; @@ -107,7 +107,7 @@ QObject *qmlAttachedPropertiesObject(const QObject *obj) if (idx == -1 || !obj) return 0; - return qmlAttachedPropertiesObjectById(idx, obj); + return qmlAttachedPropertiesObjectById(idx, obj, create); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index efe4d3f..fa09935 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -2,6 +2,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlinstruction.cpp \ qml/qmlvmemetaobject.cpp \ qml/qmlengine.cpp \ + qml/qmlexpression.cpp \ qml/qmlbindablevalue.cpp \ qml/qmlmetaproperty.cpp \ qml/qmlcomponent.cpp \ @@ -45,6 +46,7 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlvme_p.h \ qml/qmlcompiler_p.h \ qml/qmlengine_p.h \ + qml/qmlexpression_p.h \ qml/qmlprivate.h \ qml/qmldom.h \ qml/qmldom_p.h \ diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index 8b0cb42..478491f 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -45,7 +45,7 @@ #include <private/qmlengine_p.h> #include <private/qmlcontext_p.h> #include <QStack> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <private/qmlrefcount_p.h> #include <private/qmljsast_p.h> #include <private/qmljsengine_p.h> @@ -603,7 +603,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node, instr.type = ScriptInstruction::FetchD0Constant; instr.constant.idx = d0Idx; QMetaProperty prop = context->metaObject()->property(d0Idx); - instr.constant.notify = prop.notifySignalIndex(); + if (prop.isConstant()) + instr.constant.notify = 0; + else + instr.constant.notify = prop.notifySignalIndex(); instr.constant.type = prop.userType(); } else if (d1Idx != -1) { @@ -611,7 +614,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node, instr.type = ScriptInstruction::FetchD1Constant; instr.constant.idx = d1Idx; QMetaProperty prop = component->metaObject()->property(d1Idx); - instr.constant.notify = prop.notifySignalIndex(); + if (prop.isConstant()) + instr.constant.notify = 0; + else + instr.constant.notify = prop.notifySignalIndex(); instr.constant.type = prop.userType(); } else { @@ -635,7 +641,10 @@ bool QmlBasicScriptCompiler::parseName(AST::Node *node, instr.type = ScriptInstruction::FetchConstant; instr.constant.idx = idx; QMetaProperty prop = loadedType->metaObject()->property(idx); - instr.constant.notify = prop.notifySignalIndex(); + if (prop.isConstant()) + instr.constant.notify = 0; + else + instr.constant.notify = prop.notifySignalIndex(); instr.constant.type = prop.userType(); } else { int nref = data.count(); @@ -804,7 +813,7 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c { stack.push(contextPrivate->propertyValues.at(instr.fetch.idx)); enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(context, contextPrivate->notifyIndex + instr.fetch.idx); + QmlEnginePrivate::CapturedProperty(context, -1, contextPrivate->notifyIndex + instr.fetch.idx); state = Reset; } break; @@ -814,8 +823,9 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(0); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, instr.constant.notify); + if (instr.constant.notify != 0) + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; } break; @@ -825,8 +835,9 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = contextPrivate->defaultObjects.at(1); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, instr.constant.notify); + if (instr.constant.notify != 0) + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; } break; @@ -837,8 +848,9 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QObject *obj = qvariant_cast<QObject *>(o); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, instr.constant.notify); + if (instr.constant.notify != 0) + enginePrivate->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); state = Reset; } break; diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp index ef9eb55..6dda5e3 100644 --- a/src/declarative/qml/qmlbindablevalue.cpp +++ b/src/declarative/qml/qmlbindablevalue.cpp @@ -45,7 +45,7 @@ #include <qmlcontext.h> #include <qmlinfo.h> #include <QVariant> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <QtCore/qdebug.h> Q_DECLARE_METATYPE(QList<QObject *>); diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 47f69a0..b04c932 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "private/qmlcompiler_p.h" -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include "qmlparser_p.h" #include "private/qmlscriptparser_p.h" #include <qmlpropertyvaluesource.h> @@ -63,6 +63,7 @@ #include <private/qmlcontext_p.h> #include <private/qmlcomponent_p.h> #include "parser/qmljsast_p.h" +#include <private/qmlvmemetaobject_p.h> #include "qmlscriptparser_p.h" @@ -554,17 +555,18 @@ void QmlCompiler::compileTree(Object *tree) if (!compileObject(tree, 0)) // Compile failed return; - if (tree->metatype) - static_cast<QMetaObject &>(output->root) = *tree->metaObject(); - else - static_cast<QMetaObject &>(output->root) = *output->types.at(tree->type).metaObject(); - QmlInstruction def; init.line = 0; def.type = QmlInstruction::SetDefault; output->bytecode << def; finalizeComponent(0); + + if (tree->metatype) + static_cast<QMetaObject &>(output->root) = *tree->metaObject(); + else + static_cast<QMetaObject &>(output->root) = *output->types.at(tree->type).metaObject(); + } bool QmlCompiler::compileObject(Object *obj, const BindingContext &ctxt) @@ -798,13 +800,12 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, const BindingContext &ct if (obj) COMPILE_CHECK(compileObject(obj, ctxt)); - finalizeComponent(count); + COMPILE_CHECK(finalizeComponent(count)); create.createComponent.count = output->bytecode.count() - count; compileState = oldComponentCompileState; return true; } - bool QmlCompiler::compileFetchedObject(Object *obj, const BindingContext &ctxt) { Q_ASSERT(obj->metatype); @@ -1398,7 +1399,7 @@ bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, return true; } -bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) +bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj, int preAlias) { // ### FIXME - Check that there is only one default property etc. if (obj->dynamicProperties.isEmpty() && @@ -1406,49 +1407,81 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) obj->dynamicSlots.isEmpty()) return true; + QByteArray dynamicData(sizeof(QmlVMEMetaData), (char)0); + QMetaObjectBuilder builder; if (obj->metatype) builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + bool hasAlias = false; for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); - if (p.isDefaultProperty) + if (p.isDefaultProperty && + (p.type != Object::DynamicProperty::Alias || preAlias != -1)) builder.addClassInfo("DefaultProperty", p.name); QByteArray type; + int propertyType; switch(p.type) { + case Object::DynamicProperty::Alias: + hasAlias = true; + continue; + break; case Object::DynamicProperty::Variant: + propertyType = -1; type = "QVariant"; break; case Object::DynamicProperty::Int: + propertyType = QVariant::Int; type = "int"; break; case Object::DynamicProperty::Bool: + propertyType = QVariant::Bool; type = "bool"; break; case Object::DynamicProperty::Real: + propertyType = QVariant::Double; type = "double"; break; case Object::DynamicProperty::String: + propertyType = QVariant::String; type = "QString"; break; case Object::DynamicProperty::Url: + propertyType = QVariant::Url; type = "QUrl"; break; case Object::DynamicProperty::Color: + propertyType = QVariant::Color; type = "QColor"; break; case Object::DynamicProperty::Date: + propertyType = QVariant::Date; type = "QDate"; break; } + ((QmlVMEMetaData *)dynamicData.data())->propertyCount++; + QmlVMEMetaData::PropertyData propertyData = { propertyType }; + dynamicData.append((char *)&propertyData, sizeof(propertyData)); + builder.addSignal(p.name + "Changed()"); builder.addProperty(p.name, type, ii); } + if (preAlias != -1) { + for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if (p.type == Object::DynamicProperty::Alias) { + ((QmlVMEMetaData *)dynamicData.data())->aliasCount++; + compileAlias(builder, dynamicData, obj, p); + } + } + } + for (int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); QByteArray sig(s.name + "("); @@ -1459,14 +1492,28 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) sig.append(")"); QMetaMethodBuilder b = builder.addSignal(sig); b.setParameterNames(s.parameterNames); + ((QmlVMEMetaData *)dynamicData.data())->signalCount++; } int slotStart = obj->dynamicSlots.isEmpty()?-1:output->primitives.count(); for (int ii = 0; ii < obj->dynamicSlots.count(); ++ii) { const Object::DynamicSlot &s = obj->dynamicSlots.at(ii); - builder.addSlot(s.name + "()"); - output->primitives << s.body; + QByteArray sig(s.name + "("); + for (int jj = 0; jj < s.parameterNames.count(); ++jj) { + if (jj) sig.append(","); + sig.append("QVariant"); + } + sig.append(")"); + QMetaMethodBuilder b = builder.addSlot(sig); + b.setParameterNames(s.parameterNames); + + ((QmlVMEMetaData *)dynamicData.data())->methodCount++; + QmlVMEMetaData::MethodData methodData = { s.parameterNames.count() }; + dynamicData.append((char *)&methodData, sizeof(methodData)); + + if (preAlias == -1) + output->primitives << s.body; } if (obj->metatype) @@ -1475,17 +1522,37 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) obj->extObjectData = builder.toMetaObject(); static_cast<QMetaObject &>(obj->extObject) = *obj->extObjectData; - output->synthesizedMetaObjects << obj->extObjectData; - QmlInstruction store; - store.type = QmlInstruction::StoreMetaObject; - store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; - store.storeMeta.slotData = slotStart; - store.line = obj->location.start.line; - output->bytecode << store; + if (preAlias != -1) { + QmlInstruction &store = output->bytecode[preAlias]; + + store.storeMeta.aliasData = output->indexForByteArray(dynamicData); + qFree(output->synthesizedMetaObjects.at(store.storeMeta.data)); + output->synthesizedMetaObjects[store.storeMeta.data] = obj->extObjectData; + + } else { + output->synthesizedMetaObjects << obj->extObjectData; + QmlInstruction store; + store.type = QmlInstruction::StoreMetaObject; + store.storeMeta.data = output->synthesizedMetaObjects.count() - 1; + store.storeMeta.slotData = slotStart; + store.storeMeta.aliasData = output->indexForByteArray(dynamicData); + store.line = obj->location.start.line; + output->bytecode << store; + + if (hasAlias) { + AliasReference alias; + alias.object = obj; + alias.instructionIdx = output->bytecode.count() - 1; + compileState.aliases << alias; + } + } for (int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + if (p.type == Object::DynamicProperty::Alias) + continue; + if (p.defaultValue) { p.defaultValue->name = p.name; p.defaultValue->isDefault = false; @@ -1496,6 +1563,66 @@ bool QmlCompiler::compileDynamicMeta(QmlParser::Object *obj) return true; } +#include <private/qmljsparser_p.h> +static QStringList astNodeToStringList(QmlJS::AST::Node *node) +{ + if (node->kind == QmlJS::AST::Node::Kind_IdentifierExpression) { + QString name = + static_cast<QmlJS::AST::IdentifierExpression *>(node)->name->asString(); + return QStringList() << name; + } else if (node->kind == QmlJS::AST::Node::Kind_FieldMemberExpression) { + QmlJS::AST::FieldMemberExpression *expr = static_cast<QmlJS::AST::FieldMemberExpression *>(node); + + QStringList rv = astNodeToStringList(expr->base); + if (rv.isEmpty()) + return rv; + rv.append(expr->name->asString()); + return rv; + } + return QStringList(); +} + +bool QmlCompiler::compileAlias(QMetaObjectBuilder &builder, + QByteArray &data, + Object *obj, + const Object::DynamicProperty &prop) +{ + if (!prop.defaultValue) + COMPILE_EXCEPTION("No property alias location"); + + if (prop.defaultValue->values.count() != 1 || + prop.defaultValue->values.at(0)->object || + !prop.defaultValue->values.at(0)->value.isScript()) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + QmlJS::AST::Node *node = prop.defaultValue->values.at(0)->value.asAST(); + if (!node) + COMPILE_EXCEPTION("No property alias location"); // ### Can this happen? + + QStringList alias = astNodeToStringList(node); + + if (alias.count() != 2) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + if (!compileState.ids.contains(alias.at(0))) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + const IdReference &id = compileState.ids[alias.at(0)]; + int propIdx = id.object->metaObject()->indexOfProperty(alias.at(1).toUtf8().constData()); + + if (-1 == propIdx) + COMPILE_EXCEPTION2(prop.defaultValue, "Invalid alias location"); + + QMetaProperty aliasProperty = id.object->metaObject()->property(propIdx); + + data.append((const char *)&id.idx, sizeof(id.idx)); + data.append((const char *)&propIdx, sizeof(propIdx)); + + builder.addSignal(prop.name + "Changed()"); + builder.addProperty(prop.name, aliasProperty.typeName(), builder.methodCount() - 1); + return true; +} + bool QmlCompiler::compileBinding(QmlParser::Value *value, QmlParser::Property *prop, const BindingContext &ctxt) @@ -1564,17 +1691,29 @@ protected: // Update the init instruction with final data, and optimize some simple // bindings -void QmlCompiler::finalizeComponent(int patch) +bool QmlCompiler::finalizeComponent(int patch) { for (int ii = 0; ii < compileState.bindings.count(); ++ii) { const BindingReference &binding = compileState.bindings.at(ii); finalizeBinding(binding); } + for (int ii = 0; ii < compileState.aliases.count(); ++ii) { + const AliasReference &alias = compileState.aliases.at(ii); + COMPILE_CHECK(finalizeAlias(alias)); + } + output->bytecode[patch].init.dataSize = compileState.savedObjects;; output->bytecode[patch].init.bindingsSize = compileState.bindings.count(); output->bytecode[patch].init.parserStatusSize = compileState.parserStatusCount; + + return true; +} + +bool QmlCompiler::finalizeAlias(const AliasReference &alias) +{ + COMPILE_CHECK(compileDynamicMeta(alias.object, alias.instructionIdx)); } void QmlCompiler::finalizeBinding(const BindingReference &binding) diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 819c4ad..1c45f57 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -118,6 +118,7 @@ private: int indexForLocation(const QmlParser::LocationSpan &); }; +class QMetaObjectBuilder; class Q_DECLARATIVE_EXPORT QmlCompiler { public: @@ -181,13 +182,19 @@ private: const QMetaProperty &prop, QmlParser::Value *value); - bool compileDynamicMeta(QmlParser::Object *obj); + bool compileDynamicMeta(QmlParser::Object *obj, int preAlias = -1); + bool compileAlias(QMetaObjectBuilder &, + QByteArray &data, + QmlParser::Object *obj, + const QmlParser::Object::DynamicProperty &); bool compileBinding(QmlParser::Value *, QmlParser::Property *prop, const BindingContext &ctxt); - void finalizeComponent(int patch); + bool finalizeComponent(int patch); struct BindingReference; void finalizeBinding(const BindingReference &); + struct AliasReference; + bool finalizeAlias(const AliasReference &); bool canConvert(int, QmlParser::Object *); QStringList deferredProperties(QmlParser::Object *); @@ -199,6 +206,11 @@ private: int idx; }; + struct AliasReference { + QmlParser::Object *object; + int instructionIdx; + }; + struct BindingReference { QmlParser::Variant expression; QmlParser::Property *property; @@ -215,6 +227,7 @@ private: int savedObjects; int pushedProperties; QList<BindingReference> bindings; + QList<AliasReference> aliases; QmlParser::Object *root; }; ComponentCompileState compileState; diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 988d7c2..b55d77b 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -46,7 +46,7 @@ #include "qmlvme_p.h" #include "qml.h" #include <QStack> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <QStringList> #include <qmlengine.h> #include <QFileInfo> @@ -270,10 +270,25 @@ QmlComponent::QmlComponent(QmlEngine *engine, const QUrl &url, QObject *parent) } /*! + Create a QmlComponent from the given \a url and give it the specified + \a parent and \a engine. + + \sa loadUrl() +*/ +QmlComponent::QmlComponent(QmlEngine *engine, const QString &url, + QObject *parent) +: QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + loadUrl(QUrl(url)); +} + +/*! Create a QmlComponent from the given QML \a data and give it the - specified \a parent and \a engine. If \a url is provided, it is used to set - the component name, and to provide a base path for items resolved - by this component. + specified \a parent and \a engine. \a url is used to provide a base path + for items resolved by this component, and may be an empty url if the + component contains no items to resolve. \sa setData() */ @@ -339,10 +354,13 @@ void QmlComponent::loadUrl(const QUrl &url) d->clear(); - d->url = url; + if (url.isRelative()) + d->url = d->engine->baseUrl().resolved(url); + else + d->url = url; QmlCompositeTypeData *data = - d->engine->d_func()->typeManager.get(url); + d->engine->d_func()->typeManager.get(d->url); if (data->status == QmlCompositeTypeData::Waiting) { diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h index b29c123..5e6dce9 100644 --- a/src/declarative/qml/qmlcomponent.h +++ b/src/declarative/qml/qmlcomponent.h @@ -67,9 +67,10 @@ class Q_DECLARATIVE_EXPORT QmlComponent : public QObject public: QmlComponent(QObject *parent = 0); QmlComponent(QmlEngine *, QObject *parent=0); + QmlComponent(QmlEngine *, const QString &url, QObject *parent = 0); QmlComponent(QmlEngine *, const QUrl &url, QObject *parent = 0); QmlComponent(QmlEngine *, const QByteArray &data, - const QUrl &baseUrl=QUrl(), QObject *parent=0); + const QUrl &baseUrl, QObject *parent=0); virtual ~QmlComponent(); Q_ENUMS(Status) @@ -92,7 +93,7 @@ public: virtual void completeCreate(); void loadUrl(const QUrl &url); - void setData(const QByteArray &, const QUrl &baseUrl = QUrl()); + void setData(const QByteArray &, const QUrl &baseUrl); Q_SIGNALS: void statusChanged(QmlComponent::Status); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 60cb231..e97d2e9 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -41,12 +41,12 @@ #include <qmlcontext.h> #include <private/qmlcontext_p.h> +#include <private/qmlexpression_p.h> #include <private/qmlengine_p.h> #include <qmlengine.h> #include <qscriptengine.h> #include <QtCore/qvarlengtharray.h> - -#include <qdebug.h> +#include <QtCore/qdebug.h> // 6-bits #define MAXIMUM_DEFAULT_OBJECTS 63 diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h index 44d8caa..e0b6d7b 100644 --- a/src/declarative/qml/qmlcontext.h +++ b/src/declarative/qml/qmlcontext.h @@ -88,6 +88,7 @@ private: friend class QmlEngine; friend class QmlEnginePrivate; friend class QmlExpression; + friend class QmlExpressionPrivate; friend class QmlBasicScript; friend class QmlContextScriptClass; friend class QmlObjectScriptClass; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index fcbda95..4acdd0c 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -57,7 +57,7 @@ #include <QDebug> #include <QMetaObject> #include "qml.h" -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <QStack> #include "private/qmlbasicscript_p.h" #include "private/qmlcompiledcomponent_p.h" @@ -194,8 +194,8 @@ void QmlEnginePrivate::init() //###needed for the other funcs, but should it be exposed? scriptEngine.globalObject().setProperty(QLatin1String("qmlEngine"), scriptEngine.newQObject(q)); - scriptEngine.globalObject().setProperty(QLatin1String("evalQml"), - scriptEngine.newFunction(QmlEngine::createQMLObject, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), + scriptEngine.newFunction(QmlEngine::createQmlObject, 1)); scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), scriptEngine.newFunction(QmlEngine::createComponent, 1)); } @@ -208,7 +208,7 @@ QmlContext *QmlEnginePrivate::setCurrentBindContext(QmlContext *c) } QmlEnginePrivate::CapturedProperty::CapturedProperty(const QmlMetaProperty &p) -: object(p.object()), notifyIndex(p.property().notifySignalIndex()) +: object(p.object()), coreIndex(p.coreIndex()), notifyIndex(p.property().notifySignalIndex()) { } @@ -357,7 +357,7 @@ bool QmlEnginePrivate::loadCache(QmlBasicScriptNodeCache &cache, const QString & cache.type = QmlBasicScriptNodeCache::Variant; cache.context = context; cache.contextIndex = *iter; - capturedProperties << CapturedProperty(context->q_ptr, *iter + context->notifyIndex); + capturedProperties << CapturedProperty(context->q_ptr, -1, *iter + context->notifyIndex); return true; } @@ -512,6 +512,36 @@ QNetworkAccessManager *QmlEngine::networkAccessManager() const } /*! + Return the base URL for this engine. The base URL is only used to resolve + components when a relative URL is passed to the QmlComponent constructor. + + If a base URL has not been explicitly set, this method returns the + application's current working directory. + + \sa setBaseUrl() +*/ +QUrl QmlEngine::baseUrl() const +{ + Q_D(const QmlEngine); + if (d->baseUrl.isEmpty()) { + return QUrl::fromLocalFile(QDir::currentPath() + QDir::separator()); + } else { + return d->baseUrl; + } +} + +/*! + Set the base URL for this engine to \a url. + + \sa baseUrl() +*/ +void QmlEngine::setBaseUrl(const QUrl &url) +{ + Q_D(QmlEngine); + d->baseUrl = url; +} + +/*! Returns the QmlContext for the \a object, or 0 if no context has been set. When the QmlEngine instantiates a QObject, the context is set automatically. @@ -581,13 +611,13 @@ QmlEngine *qmlEngine(const QObject *obj) return context?context->engine():0; } -QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object) +QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) { QmlExtendedDeclarativeData *edata = QmlExtendedDeclarativeData::get(const_cast<QObject *>(object), true); QObject *rv = edata->attachedProperties.value(id); - if (rv) + if (rv || !create) return rv; QmlAttachedPropertiesFunc pf = QmlMetaType::attachedPropertiesFuncById(id); @@ -718,8 +748,8 @@ QScriptValue QmlEngine::qmlScriptObject(QObject* object, QmlEngine* engine) \endcode If you want to just create an arbitrary string of QML, instead of - loading a qml file, consider the evalQML() function. - \sa QmlComponent::createObject(), QmlEngine::createQMLObject() + loading a qml file, consider the createQmlObject() function. + \sa QmlComponent::createObject(), QmlEngine::createQmlObject() */ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *engine) { @@ -729,21 +759,31 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng if(ctxt->argumentCount() != 1 || !activeEngine){ c = new QmlComponent(activeEngine); }else{ - //### This url needs to be resolved in the context that the function - //### is called - it can't be done here. - QUrl url = QUrl(ctxt->argument(0).toString()); + QUrl url = QUrl(activeEngine->d_func()->currentExpression->context() + ->resolvedUrl(ctxt->argument(0).toString())); + if(!url.isValid()){ + qDebug() << "Error A:" << url << activeEngine->activeContext() << QmlEngine::activeEngine() << activeEngine; + url = QUrl(ctxt->argument(0).toString()); + } c = new QmlComponent(activeEngine, url, activeEngine); } return engine->newQObject(c); } /*! - Creates a new object from the specified string of qml. If a second argument - is provided, this is treated as the filepath that the qml came from. + Creates a new object from the specified string of QML. It requires a + second argument, which is the id of an existing QML object to use as + the new object's parent. If a third argument is provided, this is used + as the filepath that the qml came from. + + Example (where targetItem is the id of an existing QML item): + \code + newObject = createQmlObject('Rect {color: "red"; width: 20; height: 20}', + targetItem, "dynamicSnippet1"); + \endcode This function is intended for use inside QML only. It is intended to behave - similarly to eval, but for creating QML elements. Thus, it is called as - evalQml() in QtScript. + similarly to eval, but for creating QML elements. Returns the created object, or null if there is an error. In the case of an error, details of the error are output using qWarning(). @@ -752,504 +792,59 @@ QScriptValue QmlEngine::createComponent(QScriptContext *ctxt, QScriptEngine *eng the QML loads new components. If you are trying to load a new component, for example from a QML file, consider the createComponent() function instead. 'New components' refers to external QML files that have not yet - been loaded, and so it is safe to use evalQml to load built-in components. + been loaded, and so it is safe to use createQmlObject to load built-in + components. \sa QmlEngine::createComponent() */ -QScriptValue QmlEngine::createQMLObject(QScriptContext *ctxt, QScriptEngine *engine) +QScriptValue QmlEngine::createQmlObject(QScriptContext *ctxt, QScriptEngine *engine) { QmlEngine* activeEngine = qobject_cast<QmlEngine*>( engine->globalObject().property(QLatin1String("qmlEngine")).toQObject()); - if(ctxt->argumentCount() < 1 || !activeEngine){ - if(ctxt->argumentCount() < 1){ - qWarning() << "createQMLObject requires a string argument."; + if(ctxt->argumentCount() < 2 || !activeEngine){ + if(ctxt->argumentCount() < 2){ + qWarning() << "createQmlObject requires two arguments, A QML string followed by an existing QML item id."; }else{ - qWarning() << "createQMLObject cannot find engine."; + qWarning() << "createQmlObject cannot find engine."; } return engine->nullValue(); } QString qml = ctxt->argument(0).toString(); QUrl url; - if(ctxt->argumentCount() > 1) - url = QUrl(ctxt->argument(1).toString()); + if(ctxt->argumentCount() > 2) + url = QUrl(ctxt->argument(2).toString()); + QObject *parentArg = ctxt->argument(1).data().toQObject(); + QmlContext *qmlCtxt = qmlContext(parentArg); + url = qmlCtxt->resolvedUrl(url); QmlComponent component(activeEngine, qml.toUtf8(), url); if(component.isError()) { QList<QmlError> errors = component.errors(); foreach (const QmlError &error, errors) { - qWarning() << error; + qWarning() <<"Error in createQmlObject(): "<< error; } return engine->nullValue(); } - QObject *obj = component.create(); + QObject *obj = component.create(qmlCtxt); if(component.isError()) { QList<QmlError> errors = component.errors(); foreach (const QmlError &error, errors) { - qWarning() << error; + qWarning() <<"Error in createQmlObject(): "<< error; } return engine->nullValue(); } if(obj){ + obj->setParent(parentArg); + obj->setProperty("parent", QVariant::fromValue<QObject*>(parentArg)); return qmlScriptObject(obj, activeEngine); } return engine->nullValue(); } -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) -: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) -{ -} - -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) -: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) -{ -} - -QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) -: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) -{ -} - -QmlExpressionPrivate::~QmlExpressionPrivate() -{ - sse.deleteScriptState(sseData); - sseData = 0; - delete proxy; - delete log; -} - -/*! - Create an invalid QmlExpression. - - As the expression will not have an associated QmlContext, this will be a - null expression object and its value will always be an invalid QVariant. - */ -QmlExpression::QmlExpression() -: d(new QmlExpressionPrivate(this)) -{ -} - -/*! \internal */ -QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, - QmlRefCount *rc, QObject *me) -: d(new QmlExpressionPrivate(this, expr, rc)) -{ - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = me; -} - -/*! - Create a QmlExpression object. - - The \a expression ECMAScript will be executed in the \a ctxt QmlContext. - If specified, the \a scope object's properties will also be in scope during - the expression's execution. -*/ -QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, - QObject *scope) -: d(new QmlExpressionPrivate(this, expression)) -{ - d->ctxt = ctxt; - if(ctxt && ctxt->engine()) - d->id = ctxt->engine()->d_func()->getUniqueId(); - if(ctxt) - ctxt->d_func()->childExpressions.insert(this); - d->me = scope; -} - -/*! - Destroy the QmlExpression instance. -*/ -QmlExpression::~QmlExpression() -{ - if (d->ctxt) - d->ctxt->d_func()->childExpressions.remove(this); - delete d; d = 0; -} - -/*! - Returns the QmlEngine this expression is associated with, or 0 if there - is no association or the QmlEngine has been destroyed. -*/ -QmlEngine *QmlExpression::engine() const -{ - return d->ctxt?d->ctxt->engine():0; -} - -/*! - Returns the QmlContext this expression is associated with, or 0 if there - is no association or the QmlContext has been destroyed. -*/ -QmlContext *QmlExpression::context() const -{ - return d->ctxt; -} - -/*! - Returns the expression string. -*/ -QString QmlExpression::expression() const -{ - if (d->sse.isValid()) - return QLatin1String(d->sse.expression()); - else - return d->expression; -} - -/*! - Clear the expression. -*/ -void QmlExpression::clearExpression() -{ - setExpression(QString()); -} - -/*! - Set the expression to \a expression. -*/ -void QmlExpression::setExpression(const QString &expression) -{ - if (d->sseData) { - d->sse.deleteScriptState(d->sseData); - d->sseData = 0; - } - - delete d->proxy; d->proxy = 0; - - d->expression = expression; - - d->sse.clear(); -} - -/*! - Called by QmlExpression each time the expression value changes from the - last time it was evaluated. The expression must have been evaluated at - least once (by calling QmlExpression::value()) before this callback will - be made. - - The default implementation does nothing. -*/ -void QmlExpression::valueChanged() -{ -} - -void BindExpressionProxy::changed() -{ - e->valueChanged(); -} - -/*! - Returns the value of the expression, or an invalid QVariant if the - expression is invalid or has an error. -*/ -QVariant QmlExpression::value() -{ - QVariant rv; - if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty())) - return rv; - -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer<QFxPerf::BindValue> perf; -#endif - - QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset; - - QmlEnginePrivate *ep = engine()->d_func(); - QmlExpression *lastCurrentExpression = ep->currentExpression; - ep->currentExpression = this; - if (d->sse.isValid()) { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer<QFxPerf::BindValueSSE> perfsse; -#endif - - context()->d_func()->defaultObjects.insert(context()->d_func()->highPriorityCount, d->me); - - if (!d->sseData) - d->sseData = d->sse.newScriptState(); - rv = d->sse.run(context(), d->sseData, &cacheState); - - context()->d_func()->defaultObjects.removeAt(context()->d_func()->highPriorityCount); - } else { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer<QFxPerf::BindValueQt> perfqt; -#endif - context()->d_func()->defaultObjects.insert(context()->d_func()->highPriorityCount, d->me); - - QScriptEngine *scriptEngine = engine()->scriptEngine(); - QScriptValueList oldScopeChain = scriptEngine->currentContext()->scopeChain(); - for (int i = 0; i < oldScopeChain.size(); ++i) { - scriptEngine->currentContext()->popScope(); - } - for (int i = context()->d_func()->scopeChain.size() - 1; i > -1; --i) { - scriptEngine->currentContext()->pushScope(context()->d_func()->scopeChain.at(i)); - } - QScriptValue svalue = scriptEngine->evaluate(expression(), d->fileName.toString(), d->line); - if (scriptEngine->hasUncaughtException()) { - if (scriptEngine->uncaughtException().isError()){ - QScriptValue exception = scriptEngine->uncaughtException(); - if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){ - qWarning() << exception.property(QLatin1String("fileName")).toString() - << scriptEngine->uncaughtExceptionLineNumber() - << exception.toString(); - - } else { - qWarning() << exception.toString(); - } - } - } - - context()->d_func()->defaultObjects.removeAt(context()->d_func()->highPriorityCount); - if (svalue.isArray()) { - int length = svalue.property(QLatin1String("length")).toInt32(); - if (length && svalue.property(0).isObject()) { - QList<QObject *> list; - for (int ii = 0; ii < length; ++ii) { - QScriptValue arrayItem = svalue.property(ii); - QObject *d = qvariant_cast<QObject *>(arrayItem.data().toVariant()); - if (d) { - list << d; - } else { - list << 0; - } - } - rv = QVariant::fromValue(list); - } - } else if (svalue.isObject() && - !svalue.isNumber() && - !svalue.isString() && - !svalue.isDate() && - !svalue.isError() && - !svalue.isFunction() && - !svalue.isNull() && - !svalue.isQMetaObject() && - !svalue.isQObject() && - !svalue.isRegExp()) { - QScriptValue objValue = svalue.data(); - if (objValue.isValid()) { - QVariant var = objValue.toVariant(); - if (var.userType() >= (int)QVariant::UserType && - QmlMetaType::isObject(var.userType())) - rv = var; - } - } - if (rv.isNull()) - rv = svalue.toVariant(); - - for (int i = 0; i < context()->d_func()->scopeChain.size(); ++i) { - scriptEngine->currentContext()->popScope(); - } - for (int i = oldScopeChain.size() - 1; i > -1; --i) { - scriptEngine->currentContext()->pushScope(oldScopeChain.at(i)); - } - } - ep->currentExpression = lastCurrentExpression; - - if (cacheState != QmlBasicScript::NoChange) { - if (cacheState != QmlBasicScript::Incremental && d->proxy) { - delete d->proxy; - d->proxy = 0; - } - - if (trackChange() && ep->capturedProperties.count()) { - if (!d->proxy) - d->proxy = new BindExpressionProxy(this); - - static int changedIndex = -1; - if (changedIndex == -1) - changedIndex = BindExpressionProxy::staticMetaObject.indexOfSlot("changed()"); - - if(qmlDebugger()) { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - - for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { - const QmlEnginePrivate::CapturedProperty &prop = - ep->capturedProperties.at(ii); - - if (prop.notifyIndex != -1) { - QMetaObject::connect(prop.object, prop.notifyIndex, - d->proxy, changedIndex); - } else { - // ### FIXME - //QString warn = QLatin1String("Expression depends on property without a NOTIFY signal: [") + QLatin1String(prop.object->metaObject()->className()) + QLatin1String("].") + prop.name; - //log.addWarning(warn); - } - } - d->addLog(log); - - } else { - for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { - const QmlEnginePrivate::CapturedProperty &prop = - ep->capturedProperties.at(ii); - - if (prop.notifyIndex != -1) - QMetaObject::connect(prop.object, prop.notifyIndex, - d->proxy, changedIndex); - } - } - } else { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - d->addLog(log); - } - - } else { - if(qmlDebugger()) { - QmlExpressionLog log; - log.setTime(engine()->d_func()->getUniqueId()); - log.setExpression(expression()); - log.setResult(rv); - d->addLog(log); - } - } - - ep->capturedProperties.clear(); - - return rv; -} - -/*! - Returns true if the expression results in a constant value. - QmlExpression::value() must have been invoked at least once before the - return from this method is valid. - */ -bool QmlExpression::isConstant() const -{ - return d->proxy == 0; -} - -/*! - Returns true if the changes are tracked in the expression's value. -*/ -bool QmlExpression::trackChange() const -{ - return d->trackChange; -} - -/*! - Set whether changes are tracked in the expression's value to \a trackChange. - - If true, the QmlExpression will monitor properties involved in the - expression's evaluation, and call QmlExpression::valueChanged() if they have - changed. This allows an application to ensure that any value associated - with the result of the expression remains up to date. - - If false, the QmlExpression will not montitor properties involved in the - expression's evaluation, and QmlExpression::valueChanged() will never be - called. This is more efficient if an application wants a "one off" - evaluation of the expression. - - By default, trackChange is true. -*/ -void QmlExpression::setTrackChange(bool trackChange) -{ - d->trackChange = trackChange; -} - -/*! - Set the location of this expression to \a line of \a fileName. This information - is used by the script engine. -*/ -void QmlExpression::setSourceLocation(const QUrl &fileName, int line) -{ - d->fileName = fileName; - d->line = line; -} - -/*! - Returns the expression's scope object, if provided, otherwise 0. - - In addition to data provided by the expression's QmlContext, the scope - object's properties are also in scope during the expression's evaluation. -*/ -QObject *QmlExpression::scopeObject() const -{ - return d->me; -} - -/*! - \internal -*/ -quint32 QmlExpression::id() const -{ - return d->id; -} - -/*! - \class QmlExpression - \brief The QmlExpression class evaluates ECMAScript in a QML context. -*/ - -/*! - \class QmlExpressionObject - \brief The QmlExpressionObject class extends QmlExpression with signals and slots. - - To remain as lightweight as possible, QmlExpression does not inherit QObject - and consequently cannot use signals or slots. For the cases where this is - more convenient in an application, QmlExpressionObject can be used instead. - - QmlExpressionObject behaves identically to QmlExpression, except that the - QmlExpressionObject::value() method is a slot, and the - QmlExpressionObject::valueChanged() callback is a signal. -*/ -/*! - Create a QmlExpression with the specified \a parent. - - As the expression will not have an associated QmlContext, this will be a - null expression object and its value will always be an invalid QVariant. -*/ -QmlExpressionObject::QmlExpressionObject(QObject *parent) -: QObject(parent) -{ -} - -/*! - Create a QmlExpressionObject with the specified \a parent. - - The \a expression ECMAScript will be executed in the \a ctxt QmlContext. - If specified, the \a scope object's properties will also be in scope during - the expression's execution. -*/ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent) -: QObject(parent), QmlExpression(ctxt, expression, scope) -{ -} - -/*! \internal */ -QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me) -: QmlExpression(ctxt, d, rc, me) -{ -} - -/*! - Returns the value of the expression, or an invalid QVariant if the - expression is invalid or has an error. -*/ -QVariant QmlExpressionObject::value() -{ - return QmlExpression::value(); -} - -/*! - \fn void QmlExpressionObject::valueChanged() - - Emitted each time the expression value changes from the last time it was - evaluated. The expression must have been evaluated at least once (by - calling QmlExpressionObject::value()) before this signal will be emitted. -*/ - QmlScriptClass::QmlScriptClass(QmlEngine *bindengine) : QScriptClass(bindengine->scriptEngine()), engine(bindengine) { @@ -1333,7 +928,7 @@ QScriptValue QmlContextScriptClass::property(const QScriptValue &object, } else { rv = scriptEngine->newVariant(value); } - engine->d_func()->capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, index + bindContext->d_func()->notifyIndex); + engine->d_func()->capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, -1, index + bindContext->d_func()->notifyIndex); return rv; } default: @@ -1502,77 +1097,6 @@ void QmlObjectScriptClass::setProperty(QScriptValue &object, scriptEngine->currentContext()->setActivationObject(oldact); } -void QmlExpressionPrivate::addLog(const QmlExpressionLog &l) -{ - if (!log) - log = new QList<QmlExpressionLog>(); - log->append(l); -} - -QmlExpressionLog::QmlExpressionLog() -{ -} - -QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o) -: m_time(o.m_time), - m_expression(o.m_expression), - m_result(o.m_result), - m_warnings(o.m_warnings) -{ -} - -QmlExpressionLog::~QmlExpressionLog() -{ -} - -QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o) -{ - m_time = o.m_time; - m_expression = o.m_expression; - m_result = o.m_result; - m_warnings = o.m_warnings; - return *this; -} - -void QmlExpressionLog::setTime(quint32 time) -{ - m_time = time; -} - -quint32 QmlExpressionLog::time() const -{ - return m_time; -} - -QString QmlExpressionLog::expression() const -{ - return m_expression; -} - -void QmlExpressionLog::setExpression(const QString &e) -{ - m_expression = e; -} - -QStringList QmlExpressionLog::warnings() const -{ - return m_warnings; -} - -void QmlExpressionLog::addWarning(const QString &w) -{ - m_warnings << w; -} - -QVariant QmlExpressionLog::result() const -{ - return m_result; -} - -void QmlExpressionLog::setResult(const QVariant &r) -{ - m_result = r; -} class QmlImportsPrivate { public: @@ -1688,5 +1212,4 @@ QmlType* QmlEngine::resolveBuiltInType(const Imports& imports, const QByteArray& return imports.d->findBuiltin(imports.base,type); } - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h index a07ea96..0c9da39 100644 --- a/src/declarative/qml/qmlengine.h +++ b/src/declarative/qml/qmlengine.h @@ -94,13 +94,16 @@ public: void setNetworkAccessManager(QNetworkAccessManager *); QNetworkAccessManager *networkAccessManager() const; + QUrl baseUrl() const; + void setBaseUrl(const QUrl &); + static QmlContext *contextForObject(const QObject *); static void setContextForObject(QObject *, QmlContext *); static QScriptValue qmlScriptObject(QObject*, QmlEngine*); static QScriptValue createComponent(QScriptContext*, QScriptEngine*); - static QScriptValue createQMLObject(QScriptContext*, QScriptEngine*); + static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*); private: // LK: move to the private class @@ -113,6 +116,7 @@ private: friend class QmlContext; friend class QmlContextPrivate; friend class QmlExpression; + friend class QmlExpressionPrivate; friend class QmlBasicScript; friend class QmlVME; friend class QmlComponent; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index ca65e3e..9a8b9fb 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -103,11 +103,12 @@ public: QScriptValue propertyObject(const QScriptString &propName, QObject *, uint id = 0); struct CapturedProperty { - CapturedProperty(QObject *o, int n) - : object(o), notifyIndex(n) {} + CapturedProperty(QObject *o, int c, int n) + : object(o), coreIndex(c), notifyIndex(n) {} CapturedProperty(const QmlMetaProperty &); QObject *object; + int coreIndex; int notifyIndex; }; QPODVector<CapturedProperty> capturedProperties; @@ -128,6 +129,8 @@ public: QScriptEngine scriptEngine; + QUrl baseUrl; + template<class T> struct SimpleList { SimpleList() @@ -168,23 +171,6 @@ public: } }; - -class BindExpressionProxy : public QObject -{ -Q_OBJECT -public: - BindExpressionProxy(QmlExpression *be) - :e(be) - { - } - -private: - QmlExpression *e; - -private Q_SLOTS: - void changed(); -}; - class QmlScriptClass : public QScriptClass { public: @@ -246,60 +232,6 @@ public: const QScriptValue &value); }; -class QmlExpressionLog -{ -public: - QmlExpressionLog(); - QmlExpressionLog(const QmlExpressionLog &); - ~QmlExpressionLog(); - - QmlExpressionLog &operator=(const QmlExpressionLog &); - - void setTime(quint32); - quint32 time() const; - - QString expression() const; - void setExpression(const QString &); - - QStringList warnings() const; - void addWarning(const QString &); - - QVariant result() const; - void setResult(const QVariant &); - -private: - quint32 m_time; - QString m_expression; - QVariant m_result; - QStringList m_warnings; -}; - -class QmlExpressionPrivate -{ -public: - QmlExpressionPrivate(QmlExpression *); - QmlExpressionPrivate(QmlExpression *, const QString &expr); - QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc); - ~QmlExpressionPrivate(); - - QmlExpression *q; - QmlContext *ctxt; - QString expression; - QmlBasicScript sse; - void *sseData; - BindExpressionProxy *proxy; - QObject *me; - bool trackChange; - - QUrl fileName; - int line; - - quint32 id; - - void addLog(const QmlExpressionLog &); - QList<QmlExpressionLog> *log; -}; - QT_END_NAMESPACE #endif // QMLENGINE_P_H diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp new file mode 100644 index 0000000..84352b8 --- /dev/null +++ b/src/declarative/qml/qmlexpression.cpp @@ -0,0 +1,624 @@ +/**************************************************************************** +** +** 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 "qmlexpression.h" +#include "qmlexpression_p.h" +#include "qmlengine_p.h" +#include "qmlcontext_p.h" +#include "QtCore/qdebug.h" + +Q_DECLARE_METATYPE(QList<QObject *>); + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(qmlDebugger, QML_DEBUGGER) + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) +: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false), line(-1), id(0), log(0) +{ +} + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) +: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +{ +} + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr) +: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true), line(-1), id(0), log(0) +{ +} + +QmlExpressionPrivate::~QmlExpressionPrivate() +{ + sse.deleteScriptState(sseData); + sseData = 0; + delete proxy; + delete log; +} + +/*! + Create an invalid QmlExpression. + + As the expression will not have an associated QmlContext, this will be a + null expression object and its value will always be an invalid QVariant. + */ +QmlExpression::QmlExpression() +: d(new QmlExpressionPrivate(this)) +{ +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, + QmlRefCount *rc, QObject *me) +: d(new QmlExpressionPrivate(this, expr, rc)) +{ + d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); + if(ctxt) + ctxt->d_func()->childExpressions.insert(this); + d->me = me; +} + +/*! + Create a QmlExpression object. + + The \a expression ECMAScript will be executed in the \a ctxt QmlContext. + If specified, the \a scope object's properties will also be in scope during + the expression's execution. +*/ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, + QObject *scope) +: d(new QmlExpressionPrivate(this, expression)) +{ + d->ctxt = ctxt; + if(ctxt && ctxt->engine()) + d->id = ctxt->engine()->d_func()->getUniqueId(); + if(ctxt) + ctxt->d_func()->childExpressions.insert(this); + d->me = scope; +} + +/*! + Destroy the QmlExpression instance. +*/ +QmlExpression::~QmlExpression() +{ + if (d->ctxt) + d->ctxt->d_func()->childExpressions.remove(this); + delete d; d = 0; +} + +/*! + Returns the QmlEngine this expression is associated with, or 0 if there + is no association or the QmlEngine has been destroyed. +*/ +QmlEngine *QmlExpression::engine() const +{ + return d->ctxt?d->ctxt->engine():0; +} + +/*! + Returns the QmlContext this expression is associated with, or 0 if there + is no association or the QmlContext has been destroyed. +*/ +QmlContext *QmlExpression::context() const +{ + return d->ctxt; +} + +/*! + Returns the expression string. +*/ +QString QmlExpression::expression() const +{ + if (d->sse.isValid()) + return QLatin1String(d->sse.expression()); + else + return d->expression; +} + +/*! + Clear the expression. +*/ +void QmlExpression::clearExpression() +{ + setExpression(QString()); +} + +/*! + Set the expression to \a expression. +*/ +void QmlExpression::setExpression(const QString &expression) +{ + if (d->sseData) { + d->sse.deleteScriptState(d->sseData); + d->sseData = 0; + } + + delete d->proxy; d->proxy = 0; + + d->expression = expression; + + d->sse.clear(); +} + +/*! + Called by QmlExpression each time the expression value changes from the + last time it was evaluated. The expression must have been evaluated at + least once (by calling QmlExpression::value()) before this callback will + be made. + + The default implementation does nothing. +*/ +void QmlExpression::valueChanged() +{ +} + +QVariant QmlExpressionPrivate::evalSSE(QmlBasicScript::CacheState &cacheState) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValueSSE> perfsse; +#endif + + QmlContextPrivate *ctxtPriv = ctxt->d_func(); + if (me) + ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount , me); + + if (!sseData) + sseData = sse.newScriptState(); + QVariant rv = sse.run(ctxt, sseData, &cacheState); + + if (me) + ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); + + return rv; +} + +QVariant QmlExpressionPrivate::evalQtScript() +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValueQt> perfqt; +#endif + + QmlContextPrivate *ctxtPriv = ctxt->d_func(); + QmlEngine *engine = ctxt->engine(); + + if (me) + ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me); + + QScriptEngine *scriptEngine = engine->scriptEngine(); + QScriptValueList oldScopeChain = + scriptEngine->currentContext()->scopeChain(); + + for (int i = 0; i < oldScopeChain.size(); ++i) + scriptEngine->currentContext()->popScope(); + for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) + scriptEngine->currentContext()->pushScope(ctxtPriv->scopeChain.at(i)); + + QScriptValue svalue = + scriptEngine->evaluate(expression, fileName.toString(), line); + + if (scriptEngine->hasUncaughtException()) { + if (scriptEngine->uncaughtException().isError()){ + QScriptValue exception = scriptEngine->uncaughtException(); + QLatin1String fileNameProp("fileName"); + if (!exception.property(fileNameProp).toString().isEmpty()){ + qWarning() << exception.property(fileNameProp).toString() + << scriptEngine->uncaughtExceptionLineNumber() + << exception.toString(); + } else { + qWarning() << exception.toString(); + } + } + } + + if (me) + ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); + + QVariant rv; + + if (svalue.isArray()) { + int length = svalue.property(QLatin1String("length")).toInt32(); + if (length && svalue.property(0).isObject()) { + QList<QObject *> list; + for (int ii = 0; ii < length; ++ii) { + QScriptValue arrayItem = svalue.property(ii); + QObject *d = + qvariant_cast<QObject *>(arrayItem.data().toVariant()); + if (d) { + list << d; + } else { + list << 0; + } + } + rv = QVariant::fromValue(list); + } + } else if (svalue.isObject() && + !svalue.isNumber() && + !svalue.isString() && + !svalue.isDate() && + !svalue.isError() && + !svalue.isFunction() && + !svalue.isNull() && + !svalue.isQMetaObject() && + !svalue.isQObject() && + !svalue.isRegExp()) { + QScriptValue objValue = svalue.data(); + if (objValue.isValid()) { + QVariant var = objValue.toVariant(); + if (var.userType() >= (int)QVariant::UserType && + QmlMetaType::isObject(var.userType())) + rv = var; + } + } + if (rv.isNull()) + rv = svalue.toVariant(); + + for (int i = 0; i < ctxtPriv->scopeChain.size(); ++i) + scriptEngine->currentContext()->popScope(); + for (int i = oldScopeChain.size() - 1; i > -1; --i) + scriptEngine->currentContext()->pushScope(oldScopeChain.at(i)); + + return rv; +} + +/*! + Returns the value of the expression, or an invalid QVariant if the + expression is invalid or has an error. +*/ +QVariant QmlExpression::value() +{ + QVariant rv; + if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty())) + return rv; + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValue> perf; +#endif + + QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset; + + QmlEnginePrivate *ep = engine()->d_func(); + QmlExpression *lastCurrentExpression = ep->currentExpression; + ep->currentExpression = this; + + if (d->sse.isValid()) { + rv = d->evalSSE(cacheState); + } else { + rv = d->evalQtScript(); + } + + ep->currentExpression = lastCurrentExpression; + + if (cacheState != QmlBasicScript::NoChange) { + if (cacheState != QmlBasicScript::Incremental && d->proxy) { + delete d->proxy; + d->proxy = 0; + } + + if (trackChange() && ep->capturedProperties.count()) { + if (!d->proxy) + d->proxy = new QmlExpressionBindProxy(this); + + static int changedIndex = -1; + if (changedIndex == -1) + changedIndex = QmlExpressionBindProxy::staticMetaObject.indexOfSlot("changed()"); + + if(qmlDebugger()) { + QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); + log.setExpression(expression()); + log.setResult(rv); + + for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { + const QmlEnginePrivate::CapturedProperty &prop = + ep->capturedProperties.at(ii); + + if (prop.notifyIndex != -1) { + QMetaObject::connect(prop.object, prop.notifyIndex, + d->proxy, changedIndex); + } else { + const QMetaObject *metaObj = prop.object->metaObject(); + QMetaProperty metaProp = + metaObj->property(prop.coreIndex); + + QString warn = QLatin1String("Expression depends on non-NOTIFYable property: ") + + QLatin1String(metaObj->className()) + + QLatin1String("::") + + QLatin1String(metaProp.name()); + log.addWarning(warn); + } + } + d->addLog(log); + + } else { + bool outputWarningHeader = false; + for (int ii = 0; ii < ep->capturedProperties.count(); ++ii) { + const QmlEnginePrivate::CapturedProperty &prop = + ep->capturedProperties.at(ii); + + if (prop.notifyIndex != -1) { + QMetaObject::connect(prop.object, prop.notifyIndex, + d->proxy, changedIndex); + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QmlExpression: Expression" << expression() << "depends on non-NOTIFYable properties:"; + } + + const QMetaObject *metaObj = prop.object->metaObject(); + QMetaProperty metaProp = + metaObj->property(prop.coreIndex); + + qWarning().nospace() << " " << metaObj->className() + << "::" << metaProp.name(); + } + } + } + } else { + QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); + log.setExpression(expression()); + log.setResult(rv); + d->addLog(log); + } + + } else { + if(qmlDebugger()) { + QmlExpressionLog log; + log.setTime(engine()->d_func()->getUniqueId()); + log.setExpression(expression()); + log.setResult(rv); + d->addLog(log); + } + } + + ep->capturedProperties.clear(); + + return rv; +} + +/*! + Returns true if the expression results in a constant value. + QmlExpression::value() must have been invoked at least once before the + return from this method is valid. + */ +bool QmlExpression::isConstant() const +{ + return d->proxy == 0; +} + +/*! + Returns true if the changes are tracked in the expression's value. +*/ +bool QmlExpression::trackChange() const +{ + return d->trackChange; +} + +/*! + Set whether changes are tracked in the expression's value to \a trackChange. + + If true, the QmlExpression will monitor properties involved in the + expression's evaluation, and call QmlExpression::valueChanged() if they have + changed. This allows an application to ensure that any value associated + with the result of the expression remains up to date. + + If false, the QmlExpression will not montitor properties involved in the + expression's evaluation, and QmlExpression::valueChanged() will never be + called. This is more efficient if an application wants a "one off" + evaluation of the expression. + + By default, trackChange is true. +*/ +void QmlExpression::setTrackChange(bool trackChange) +{ + d->trackChange = trackChange; +} + +/*! + Set the location of this expression to \a line of \a fileName. This information + is used by the script engine. +*/ +void QmlExpression::setSourceLocation(const QUrl &fileName, int line) +{ + d->fileName = fileName; + d->line = line; +} + +/*! + Returns the expression's scope object, if provided, otherwise 0. + + In addition to data provided by the expression's QmlContext, the scope + object's properties are also in scope during the expression's evaluation. +*/ +QObject *QmlExpression::scopeObject() const +{ + return d->me; +} + +/*! + \internal +*/ +quint32 QmlExpression::id() const +{ + return d->id; +} + +/*! + \class QmlExpression + \brief The QmlExpression class evaluates ECMAScript in a QML context. +*/ + +/*! + \class QmlExpressionObject + \brief The QmlExpressionObject class extends QmlExpression with signals and slots. + + To remain as lightweight as possible, QmlExpression does not inherit QObject + and consequently cannot use signals or slots. For the cases where this is + more convenient in an application, QmlExpressionObject can be used instead. + + QmlExpressionObject behaves identically to QmlExpression, except that the + QmlExpressionObject::value() method is a slot, and the + QmlExpressionObject::valueChanged() callback is a signal. +*/ +/*! + Create a QmlExpression with the specified \a parent. + + As the expression will not have an associated QmlContext, this will be a + null expression object and its value will always be an invalid QVariant. +*/ +QmlExpressionObject::QmlExpressionObject(QObject *parent) +: QObject(parent) +{ +} + +/*! + Create a QmlExpressionObject with the specified \a parent. + + The \a expression ECMAScript will be executed in the \a ctxt QmlContext. + If specified, the \a scope object's properties will also be in scope during + the expression's execution. +*/ +QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent) +: QObject(parent), QmlExpression(ctxt, expression, scope) +{ +} + +/*! \internal */ +QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me) +: QmlExpression(ctxt, d, rc, me) +{ +} + +/*! + Returns the value of the expression, or an invalid QVariant if the + expression is invalid or has an error. +*/ +QVariant QmlExpressionObject::value() +{ + return QmlExpression::value(); +} + +/*! + \fn void QmlExpressionObject::valueChanged() + + Emitted each time the expression value changes from the last time it was + evaluated. The expression must have been evaluated at least once (by + calling QmlExpressionObject::value()) before this signal will be emitted. +*/ + +void QmlExpressionPrivate::addLog(const QmlExpressionLog &l) +{ + if (!log) + log = new QList<QmlExpressionLog>(); + log->append(l); +} + +QmlExpressionLog::QmlExpressionLog() +{ +} + +QmlExpressionLog::QmlExpressionLog(const QmlExpressionLog &o) +: m_time(o.m_time), + m_expression(o.m_expression), + m_result(o.m_result), + m_warnings(o.m_warnings) +{ +} + +QmlExpressionLog::~QmlExpressionLog() +{ +} + +QmlExpressionLog &QmlExpressionLog::operator=(const QmlExpressionLog &o) +{ + m_time = o.m_time; + m_expression = o.m_expression; + m_result = o.m_result; + m_warnings = o.m_warnings; + return *this; +} + +void QmlExpressionLog::setTime(quint32 time) +{ + m_time = time; +} + +quint32 QmlExpressionLog::time() const +{ + return m_time; +} + +QString QmlExpressionLog::expression() const +{ + return m_expression; +} + +void QmlExpressionLog::setExpression(const QString &e) +{ + m_expression = e; +} + +QStringList QmlExpressionLog::warnings() const +{ + return m_warnings; +} + +void QmlExpressionLog::addWarning(const QString &w) +{ + m_warnings << w; +} + +QVariant QmlExpressionLog::result() const +{ + return m_result; +} + +void QmlExpressionLog::setResult(const QVariant &r) +{ + m_result = r; +} + + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index e8cac7a..3d8f8df 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -86,7 +86,7 @@ protected: virtual void valueChanged(); private: - friend class BindExpressionProxy; + friend class QmlExpressionBindProxy; friend class QmlDebugger; friend class QmlContext; QmlExpressionPrivate *d; diff --git a/src/declarative/fx/qfxcontentwrapper_p.h b/src/declarative/qml/qmlexpression_p.h index a75fa1e..5883125 100644 --- a/src/declarative/fx/qfxcontentwrapper_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QFXCONTENTWRAPPER_P_H -#define QFXCONTENTWRAPPER_P_H +#ifndef QMLEXPRESSION_P_H +#define QMLEXPRESSION_P_H // // W A R N I N G @@ -53,19 +53,86 @@ // We mean it. // -#include "qfxitem_p.h" -#include "qfxcontentwrapper.h" - +#include "qmlbasicscript_p.h" +#include "qmlexpression.h" QT_BEGIN_NAMESPACE -class QFxContentWrapperPrivate : public QFxItemPrivate + +class QmlExpression; +class QString; +class QmlExpressionLog; +class QmlExpressionBindProxy; +class QmlExpressionPrivate +{ +public: + QmlExpressionPrivate(QmlExpression *); + QmlExpressionPrivate(QmlExpression *, const QString &expr); + QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc); + ~QmlExpressionPrivate(); + + QmlExpression *q; + QmlContext *ctxt; + QString expression; + QmlBasicScript sse; + void *sseData; + QmlExpressionBindProxy *proxy; + QObject *me; + bool trackChange; + + QUrl fileName; + int line; + + quint32 id; + + void addLog(const QmlExpressionLog &); + QList<QmlExpressionLog> *log; + + QVariant evalSSE(QmlBasicScript::CacheState &cacheState); + QVariant evalQtScript(); +}; + +class QmlExpressionBindProxy : public QObject { - Q_DECLARE_PUBLIC(QFxContentWrapper) +Q_OBJECT public: - QFxContentWrapperPrivate() { } + QmlExpressionBindProxy(QmlExpression *be) + :e(be) { } + +private: + QmlExpression *e; - QList<QFxItem *> _content; +private Q_SLOTS: + void changed() { e->valueChanged(); } +}; + +class QmlExpressionLog +{ +public: + QmlExpressionLog(); + QmlExpressionLog(const QmlExpressionLog &); + ~QmlExpressionLog(); + + QmlExpressionLog &operator=(const QmlExpressionLog &); + + void setTime(quint32); + quint32 time() const; + + QString expression() const; + void setExpression(const QString &); + + QStringList warnings() const; + void addWarning(const QString &); + + QVariant result() const; + void setResult(const QVariant &); + +private: + quint32 m_time; + QString m_expression; + QVariant m_result; + QStringList m_warnings; }; QT_END_NAMESPACE -#endif // QFXCONTENTWRAPPER_P_H + +#endif // QMLEXPRESSION_P_H diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index f2f3ac2..40f9a32 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -181,6 +181,7 @@ public: struct { int data; int slotData; + int aliasData; } storeMeta; struct { int value; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 307f76f..ee24074 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -42,7 +42,7 @@ #include "qmlmetaproperty.h" #include "qmlmetaproperty_p.h" #include <qml.h> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <QStringList> #include <qmlbindablevalue.h> #include <qmlcontext.h> @@ -882,7 +882,8 @@ bool QmlMetaProperty::hasChangedNotifier() const */ bool QmlMetaProperty::needsChangedNotifier() const { - return type() & Property && !(type() & Attached); + return type() & Property && !(type() & Attached) && + !property().isConstant(); } /*! @@ -1002,7 +1003,7 @@ QMetaMethod QmlMetaProperty::method() const */ QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, const QString &name) { - QStringList path = name.split('.'); + QStringList path = name.split(QLatin1Char('.')); QObject *object = obj; diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index df5e26e..8daab6a 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -48,7 +48,7 @@ #include <QRectF> #include <private/qmlvme_p.h> #include <qmlbindablevalue.h> -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <qml.h> #include "private/qmlcomponent_p.h" #include <qmlcomponent.h> @@ -133,7 +133,7 @@ QmlParser::Object::DynamicSlot::DynamicSlot() } QmlParser::Object::DynamicSlot::DynamicSlot(const DynamicSlot &o) -: name(o.name), body(o.body) +: name(o.name), body(o.body), parameterNames(o.parameterNames) { } diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index 9daa336..7550870 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -144,7 +144,7 @@ namespace QmlParser DynamicProperty(); DynamicProperty(const DynamicProperty &); - enum Type { Variant, Int, Bool, Real, String, Url, Color, Date }; + enum Type { Variant, Int, Bool, Real, String, Url, Color, Date, Alias }; bool isDefaultProperty; Type type; @@ -166,6 +166,7 @@ namespace QmlParser QByteArray name; QString body; + QList<QByteArray> parameterNames; }; // The list of dynamic properties diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index 4358a3e..cd0a255 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -55,7 +55,7 @@ #include <QCoreApplication> #include <QtDebug> -#include <qfxperf.h> +#include <private/qfxperf_p.h> QT_BEGIN_NAMESPACE @@ -537,6 +537,12 @@ bool ProcessAST::visit(AST::UiPublicMember *node) bool typeFound = false; Object::DynamicProperty::Type type; + + if (memberType == QLatin1String("alias")) { + type = Object::DynamicProperty::Alias; + typeFound = true; + } + for(int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) { if(QLatin1String(propTypeNameToTypes[ii].name) == memberType) { type = propTypeNameToTypes[ii].type; @@ -720,20 +726,19 @@ bool ProcessAST::visit(AST::UiSourceElement *node) if (AST::FunctionDeclaration *funDecl = AST::cast<AST::FunctionDeclaration *>(node->sourceElement)) { - if(funDecl->formals) { - QmlError error; - error.setDescription(QCoreApplication::translate("QmlParser","Slot declarations must be parameterless")); - error.setLine(funDecl->lparenToken.startLine); - error.setColumn(funDecl->lparenToken.startColumn); - _parser->_errors << error; - return false; + Object::DynamicSlot slot; + + AST::FormalParameterList *f = funDecl->formals; + while (f) { + slot.parameterNames << f->name->asString().toUtf8(); + f = f->finish(); } QString body = textAt(funDecl->lbraceToken, funDecl->rbraceToken); - Object::DynamicSlot slot; slot.name = funDecl->name->asString().toUtf8(); slot.body = body; obj->dynamicSlots << slot; + } else { QmlError error; error.setDescription(QCoreApplication::translate("QmlParser","QmlJS declaration outside Script element")); diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 962d917..a11caeb 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -40,14 +40,13 @@ ****************************************************************************/ #include "qmlvme_p.h" -#include <qfxperf.h> +#include <private/qfxperf_p.h> #include <private/qmlboundsignal_p.h> #include <private/qmlstringconverters_p.h> #include "private/qmetaobjectbuilder_p.h" #include "private/qmldeclarativedata_p.h" #include <qml.h> #include <private/qmlcustomparser_p.h> -#include <qperformancelog.h> #include <QStack> #include <QWidget> #include <private/qmlcompiledcomponent_p.h> @@ -240,7 +239,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledComp case QmlInstruction::StoreMetaObject: { QObject *target = stack.top(); - new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, comp); + new QmlVMEMetaObject(target, synthesizedMetaObjects.at(instr.storeMeta.data), &comp->primitives, instr.storeMeta.slotData, (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(), comp); } break; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index ec269b8..6d14689 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -47,6 +47,7 @@ #include <QtCore/qlist.h> #include <QtCore/qdebug.h> #include <qmlexpression.h> +#include <private/qmlcontext_p.h> QT_BEGIN_NAMESPACE @@ -54,8 +55,10 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, const QMetaObject *other, QList<QString> *strData, int slotData, + const QmlVMEMetaData *meta, QmlRefCount *rc) -: object(obj), ref(rc), slotData(strData), slotDataIdx(slotData), parent(0) +: object(obj), ref(rc), metaData(meta), slotData(strData), + slotDataIdx(slotData), parent(0) { if (ref) ref->addref(); @@ -68,37 +71,18 @@ QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); op->metaObject = this; - baseProp = propertyOffset(); - baseSig = methodOffset(); - data = new QVariant[propertyCount() - baseProp]; - vTypes.resize(propertyCount() - baseProp); + propOffset = QAbstractDynamicMetaObject::propertyOffset(); + methodOffset = QAbstractDynamicMetaObject::methodOffset(); - // ### Optimize - for (int ii = baseProp; ii < propertyCount(); ++ii) { - QMetaProperty prop = property(ii); - if ((int)prop.type() != -1) { - data[ii - baseProp] = QVariant((QVariant::Type)prop.userType()); - } else { - vTypes.setBit(ii - baseProp, true); - } - } + data = new QVariant[metaData->propertyCount]; + aConnected.resize(metaData->aliasCount); - baseSlot = -1; - slotCount = 0; - for (int ii = baseSig; ii < methodCount(); ++ii) { - QMetaMethod m = method(ii); - if (m.methodType() == QMetaMethod::Slot) { - if (baseSlot == -1) - baseSlot = ii; - } else { - if (baseSlot != -1) { - slotCount = ii - baseSlot; - break; - } - } + // ### Optimize + for (int ii = 0; ii < metaData->propertyCount; ++ii) { + int t = (metaData->propertyData() + ii)->propertyType; + if (t != -1) + data[ii] = QVariant((QVariant::Type)t); } - if(baseSlot != -1 && !slotCount) - slotCount = methodCount() - baseSlot; } QmlVMEMetaObject::~QmlVMEMetaObject() @@ -110,81 +94,146 @@ QmlVMEMetaObject::~QmlVMEMetaObject() delete [] data; } -int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) { + int id = _id; if(c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty) { - if (id >= baseProp) { - int propId = id - baseProp; - bool needActivate = false; - - if (vTypes.testBit(propId)) { - if (c == QMetaObject::ReadProperty) { - *reinterpret_cast<QVariant *>(a[0]) = data[propId]; - } else if (c == QMetaObject::WriteProperty) { - needActivate = - (data[propId] != *reinterpret_cast<QVariant *>(a[0])); - data[propId] = *reinterpret_cast<QVariant *>(a[0]); - } - } else { - if (c == QMetaObject::ReadProperty) { - switch(data[propId].type()) { - case QVariant::Int: - *reinterpret_cast<int *>(a[0]) = data[propId].toInt(); - break; - case QVariant::Bool: - *reinterpret_cast<bool *>(a[0]) = data[propId].toBool(); - break; - case QVariant::Double: - *reinterpret_cast<double *>(a[0]) = data[propId].toDouble(); - break; - case QVariant::String: - *reinterpret_cast<QString *>(a[0]) = data[propId].toString(); - break; - case QVariant::Url: - *reinterpret_cast<QUrl *>(a[0]) = data[propId].toUrl(); - break; - case QVariant::Color: - *reinterpret_cast<QColor *>(a[0]) = data[propId].value<QColor>(); - break; - case QVariant::Date: - *reinterpret_cast<QDate *>(a[0]) = data[propId].toDate(); - break; - default: - qFatal("Unknown type"); - break; + if (id >= propOffset) { + id -= propOffset; + + if (id < metaData->propertyCount) { + int t = (metaData->propertyData() + id)->propertyType; + bool needActivate = false; + + if (t == -1) { + + if (c == QMetaObject::ReadProperty) { + *reinterpret_cast<QVariant *>(a[0]) = data[id]; + } else if (c == QMetaObject::WriteProperty) { + needActivate = + (data[id] != *reinterpret_cast<QVariant *>(a[0])); + data[id] = *reinterpret_cast<QVariant *>(a[0]); + } + + } else { + + if (c == QMetaObject::ReadProperty) { + switch(t) { + case QVariant::Int: + *reinterpret_cast<int *>(a[0]) = data[id].toInt(); + break; + case QVariant::Bool: + *reinterpret_cast<bool *>(a[0]) = data[id].toBool(); + break; + case QVariant::Double: + *reinterpret_cast<double *>(a[0]) = data[id].toDouble(); + break; + case QVariant::String: + *reinterpret_cast<QString *>(a[0]) = data[id].toString(); + break; + case QVariant::Url: + *reinterpret_cast<QUrl *>(a[0]) = data[id].toUrl(); + break; + case QVariant::Color: + *reinterpret_cast<QColor *>(a[0]) = data[id].value<QColor>(); + break; + case QVariant::Date: + *reinterpret_cast<QDate *>(a[0]) = data[id].toDate(); + break; + default: + break; + } + + } else if (c == QMetaObject::WriteProperty) { + + QVariant value = QVariant((QVariant::Type)data[id].type(), a[0]); + needActivate = (data[id] != value); + data[id] = value; } - } else if (c == QMetaObject::WriteProperty) { - QVariant value = QVariant((QVariant::Type)data[propId].type(), a[0]); - needActivate = (data[propId] != value); - data[propId] = value; } + + if (c == QMetaObject::WriteProperty && needActivate) { + activate(object, methodOffset + id, 0); + } + + return -1; } - if (c == QMetaObject::WriteProperty && needActivate) { - activate(object, baseSig + propId, 0); + id -= metaData->propertyCount; + + if (id < metaData->aliasCount) { + + QmlContext *ctxt = qmlContext(object); + + if (!ctxt) return -1; + QmlVMEMetaData::AliasData *d = metaData->aliasData() + id; + QmlContextPrivate *ctxtPriv = + (QmlContextPrivate *)QObjectPrivate::get(ctxt); + + QObject *target = + *(QObject **)ctxtPriv->propertyValues[d->contextIdx].data(); + if (!target) return -1; + + if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) { + int sigIdx = methodOffset + id + metaData->propertyCount; + QMetaObject::connect(ctxt, d->contextIdx + ctxtPriv->notifyIndex, object, sigIdx); + + QMetaProperty prop = + target->metaObject()->property(d->propertyIdx); + if (prop.hasNotifySignal()) + QMetaObject::connect(target, prop.notifySignalIndex(), + object, sigIdx); + aConnected.setBit(id); + } + return QMetaObject::metacall(target, c, d->propertyIdx, a); + } + return -1; + + } - return id; - } } else if(c == QMetaObject::InvokeMetaMethod) { - if (id >= baseSig && (baseSlot == -1 || id < baseSlot)) { - QMetaObject::activate(object, id, a); - return id; - } else if (id >= baseSlot && id < (baseSlot + slotCount)) { - int idx = id - baseSlot + slotDataIdx; - QmlContext *ctxt = qmlContext(object); - QmlExpression expr(ctxt, slotData->at(idx), object); - expr.setTrackChange(false); - expr.value(); - return id; + + if (id >= methodOffset) { + + id -= methodOffset; + int plainSignals = metaData->signalCount + metaData->propertyCount + + metaData->aliasCount; + if (id < plainSignals) { + QMetaObject::activate(object, _id, a); + return -1; + } + + id -= plainSignals; + + if (id < metaData->methodCount) { + QString code = slotData->at(id + slotDataIdx); + QmlContext *ctxt = qmlContext(object); + + if (0 == (metaData->methodData() + id)->parameterCount) { + QmlExpression expr(ctxt, code, object); + expr.setTrackChange(false); + expr.value(); + } else { + QmlContext newCtxt(ctxt); + QMetaMethod m = method(_id); + QList<QByteArray> names = m.parameterNames(); + for (int ii = 0; ii < names.count(); ++ii) + newCtxt.setContextProperty(names.at(ii), *(QVariant *)a[ii + 1]); + QmlExpression expr(&newCtxt, code, object); + expr.setTrackChange(false); + expr.value(); + } + } + return -1; } } if (parent) - return parent->metaCall(c, id, a); + return parent->metaCall(c, _id, a); else - return object->qt_metacall(c, id, a); + return object->qt_metacall(c, _id, a); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h index 7b6fd2d..6421c3f 100644 --- a/src/declarative/qml/qmlvmemetaobject_p.h +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -59,11 +59,45 @@ #include <private/qobject_p.h> QT_BEGIN_NAMESPACE + +struct QmlVMEMetaData +{ + short propertyCount; + short aliasCount; + short signalCount; + short methodCount; + + struct AliasData { + int contextIdx; + int propertyIdx; + }; + + struct PropertyData { + int propertyType; + }; + + struct MethodData { + int parameterCount; + }; + + PropertyData *propertyData() const { + return (PropertyData *)(((const char *)this) + sizeof(QmlVMEMetaData)); + } + + AliasData *aliasData() const { + return (AliasData *)(propertyData() + propertyCount); + } + + MethodData *methodData() const { + return (MethodData *)(aliasData() + propertyCount); + } +}; + class QmlRefCount; class QmlVMEMetaObject : public QAbstractDynamicMetaObject { public: - QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, QmlRefCount * = 0); + QmlVMEMetaObject(QObject *, const QMetaObject *, QList<QString> *, int slotData, const QmlVMEMetaData *data, QmlRefCount * = 0); ~QmlVMEMetaObject(); protected: @@ -72,15 +106,19 @@ protected: private: QObject *object; QmlRefCount *ref; - int baseProp; - int baseSig; - int baseSlot; - int slotCount; + + const QmlVMEMetaData *metaData; + int propOffset; + int methodOffset; + QVariant *data; - QBitArray vTypes; + QBitArray aConnected; + QList<QString> *slotData; int slotDataIdx; + QAbstractDynamicMetaObject *parent; + }; QT_END_NAMESPACE diff --git a/src/declarative/qml/rewriter/rewriter.cpp b/src/declarative/qml/rewriter/rewriter.cpp index 2ce927c..ed45f16 100644 --- a/src/declarative/qml/rewriter/rewriter.cpp +++ b/src/declarative/qml/rewriter/rewriter.cpp @@ -83,14 +83,19 @@ void Rewriter::moveTextBefore(const AST::SourceLocation &firstLoc, const AST::SourceLocation &lastLoc, const AST::SourceLocation &loc) { - textWriter.move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset); + move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset); } void Rewriter::moveTextAfter(const AST::SourceLocation &firstLoc, const AST::SourceLocation &lastLoc, const AST::SourceLocation &loc) { - textWriter.move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset + loc.length); + move(firstLoc.offset, lastLoc.offset + lastLoc.length - firstLoc.offset, loc.offset + loc.length); +} + +void Rewriter::move(int pos, int length, int to) +{ + textWriter.move(pos, length, to); } QT_END_NAMESPACE diff --git a/src/declarative/qml/rewriter/rewriter_p.h b/src/declarative/qml/rewriter/rewriter_p.h index fcb9ca5..44f3cce 100644 --- a/src/declarative/qml/rewriter/rewriter_p.h +++ b/src/declarative/qml/rewriter/rewriter_p.h @@ -121,7 +121,8 @@ public: // // low-level offset based API // - void replace(int offset, int length, const QString &text); + virtual void replace(int offset, int length, const QString &text); + virtual void move(int pos, int length, int to); void insertText(int offset, const QString &text); void removeText(int offset, int length); diff --git a/src/declarative/test/qfxtestengine.cpp b/src/declarative/test/qfxtestengine.cpp index 0d7e5df..cf746db 100644 --- a/src/declarative/test/qfxtestengine.cpp +++ b/src/declarative/test/qfxtestengine.cpp @@ -41,7 +41,7 @@ #include <QFile> #include <QmlComponent> -#include <qmltimeline.h> +#include <private/qmltimeline_p.h> #include "qfxtestengine.h" #include "qfxtestobjects.h" #include <QCryptographicHash> diff --git a/src/declarative/timeline/qmltimelinevalueproxy.h b/src/declarative/timeline/qmltimelinevalueproxy.h deleted file mode 100644 index 9ecdba1..0000000 --- a/src/declarative/timeline/qmltimelinevalueproxy.h +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QMLTIMELINEVALUEPROXY_H -#define QMLTIMELINEVALUEPROXY_H - -#include <QtDeclarative/qmltimeline.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -template<class T> -class QmlTimeLineValueProxy : public QmlTimeLineValue -{ -public: - QmlTimeLineValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.) - : QmlTimeLineValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0) - { - Q_ASSERT(_class); - } - - QmlTimeLineValueProxy(T *cls, void (T::*func)(int), qreal v = 0.) - : QmlTimeLineValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func) - { - Q_ASSERT(_class); - } - - virtual void setValue(qreal v) - { - QmlTimeLineValue::setValue(v); - if (_setFunctionReal) (_class->*_setFunctionReal)(v); - else if (_setFunctionInt) (_class->*_setFunctionInt)((int)v); - } - -private: - T *_class; - void (T::*_setFunctionReal)(qreal); - void (T::*_setFunctionInt)(int); -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif//QMLTIMELINEVALUEPROXY_H diff --git a/src/declarative/timeline/timeline.pri b/src/declarative/timeline/timeline.pri deleted file mode 100644 index a7b3cb9..0000000 --- a/src/declarative/timeline/timeline.pri +++ /dev/null @@ -1,7 +0,0 @@ -SOURCES += \ - timeline/qmltimeline.cpp \ - -HEADERS += \ - timeline/qmltimeline.h \ - timeline/qmltimelinevalueproxy.h \ - diff --git a/src/declarative/util/qfxperf.cpp b/src/declarative/util/qfxperf.cpp index 9ac9e8d..db56b37 100644 --- a/src/declarative/util/qfxperf.cpp +++ b/src/declarative/util/qfxperf.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qfxperf.h" +#include "private/qfxperf_p.h" QT_BEGIN_NAMESPACE diff --git a/src/declarative/util/qfxperf.h b/src/declarative/util/qfxperf_p.h index 0bc0cc9..a1e38b7 100644 --- a/src/declarative/util/qfxperf.h +++ b/src/declarative/util/qfxperf_p.h @@ -41,7 +41,18 @@ #ifndef QFXPERF_H #define QFXPERF_H -#include "qperformancelog.h" +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "private/qperformancelog_p.h" QT_BEGIN_HEADER diff --git a/src/declarative/util/qfxview.cpp b/src/declarative/util/qfxview.cpp index 0855224..0a3afda 100644 --- a/src/declarative/util/qfxview.cpp +++ b/src/declarative/util/qfxview.cpp @@ -54,8 +54,8 @@ #include "qmlbindablevalue.h" #include "qml.h" #include "qfxitem.h" -#include "qperformancelog.h" -#include "qfxperf.h" +#include "private/qperformancelog_p.h" +#include "private/qfxperf_p.h" #include "qfxview.h" #include <QtDeclarative/qmlengine.h> diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 6ad47f5..ff070c1 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -58,12 +58,6 @@ #include <private/qmlstringconverters_p.h> #include <private/qvariantanimation_p.h> -/* TODO: - Check for any memory leaks - easing should be a QEasingCurve-type property - All other XXXs and ###s -*/ - QT_BEGIN_NAMESPACE QEasingCurve stringToCurve(const QString &curve) @@ -1108,7 +1102,7 @@ void QmlParentChangeActionPrivate::init() void QmlParentChangeActionPrivate::doAction() { - //XXX property.write(value); + //### property.write(value); } void QmlParentChangeAction::prepare(QmlMetaProperty &p) @@ -1120,7 +1114,7 @@ void QmlParentChangeAction::prepare(QmlMetaProperty &p) else d->property = d->userProperty; - //XXX + //### } QAbstractAnimation *QmlParentChangeAction::qtAnimation() @@ -1239,7 +1233,7 @@ QmlNumberAnimation::~QmlNumberAnimation() qreal QmlNumberAnimation::from() const { Q_D(const QmlPropertyAnimation); - return d->from.toDouble(); //### toFloat? + return d->from.toDouble(); } void QmlNumberAnimation::setFrom(qreal f) @@ -1259,7 +1253,7 @@ void QmlNumberAnimation::setFrom(qreal f) qreal QmlNumberAnimation::to() const { Q_D(const QmlPropertyAnimation); - return d->to.toDouble(); //### toFloat? + return d->to.toDouble(); } void QmlNumberAnimation::setTo(qreal t) @@ -1346,7 +1340,7 @@ void QmlSequentialAnimation::transition(QmlStateActions &actions, from = d->animations.count() - 1; } - //### needed for Behavior + //needed for Behavior if (d->userProperty.isValid() && d->propertyName.isEmpty() && !target()) { for (int i = 0; i < d->animations.count(); ++i) d->animations.at(i)->setTarget(d->userProperty); @@ -1428,7 +1422,7 @@ void QmlParallelAnimation::transition(QmlStateActions &actions, { Q_D(QmlAnimationGroup); - //### needed for Behavior + //needed for Behavior if (d->userProperty.isValid() && d->propertyName.isEmpty() && !target()) { for (int i = 0; i < d->animations.count(); ++i) d->animations.at(i)->setTarget(d->userProperty); @@ -1441,26 +1435,12 @@ void QmlParallelAnimation::transition(QmlStateActions &actions, QML_DEFINE_TYPE(QmlParallelAnimation,ParallelAnimation) -//### profile and optimize -QVariant QmlPropertyAnimationPrivate::interpolateVariant(const QVariant &from, const QVariant &to, qreal progress) -{ - if (from.userType() != to.userType()) - return QVariant(); - - QVariantAnimation::Interpolator interpolator = QVariantAnimationPrivate::getInterpolator(from.userType()); - if (interpolator) - return interpolator(from.constData(), to.constData(), progress); - else - return QVariant(); -} - //convert a variant from string type to another animatable type -//### should use any registered string convertor -//### profile and optimize -void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Type type) +void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) { if (variant.type() != QVariant::String) { - variant.convert(type); + if ((uint)type < QVariant::UserType) + variant.convert((QVariant::Type)type); return; } @@ -1494,7 +1474,12 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, QVariant::Ty break; } default: - variant.convert(type); + if ((uint)type >= QVariant::UserType) { + QmlMetaType::StringConverter converter = QmlMetaType::customStringConverter(type); + if (converter) + variant = converter(variant.toString()); + } else + variant.convert((QVariant::Type)type); break; } } @@ -1742,7 +1727,8 @@ void QmlPropertyAnimationPrivate::valueChanged(qreal r) if (!fromSourced) { if (!fromIsDefined) { from = property.read(); - convertVariant(from, (QVariant::Type)(interpolatorType ? interpolatorType : property.propertyType())); + convertVariant(from, interpolatorType ? interpolatorType : property.propertyType()); + //### check for invalid variant if using property type } fromSourced = true; } @@ -1752,8 +1738,6 @@ void QmlPropertyAnimationPrivate::valueChanged(qreal r) } else { if (interpolator) property.write(interpolator(from.constData(), to.constData(), r)); - else - property.write(interpolateVariant(from, to, r)); //### optimize } } @@ -1771,9 +1755,15 @@ void QmlPropertyAnimation::prepare(QmlMetaProperty &p) else d->property = d->userProperty; - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : d->property.propertyType())); + int propType = d->property.propertyType(); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : propType); if (d->fromIsDefined) - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : d->property.propertyType())); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : propType); + + if (!d->interpolatorType) { + //### check for invalid variants + d->interpolator = QVariantAnimationPrivate::getInterpolator(propType); + } d->fromSourced = false; d->value.QmlTimeLineValue::setValue(0.); @@ -1810,7 +1800,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (action.fromValue.isNull()) { action.fromValue = action.property.read(); if (interpolatorType) - QmlPropertyAnimationPrivate::convertVariant(action.fromValue, (QVariant::Type)interpolatorType); + QmlPropertyAnimationPrivate::convertVariant(action.fromValue, interpolatorType); } if (!interpolatorType) { int propType = action.property.propertyType(); @@ -1871,8 +1861,8 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, if (d->toIsDefined) myAction.toValue = d->to; - d->convertVariant(myAction.fromValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); - d->convertVariant(myAction.toValue, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(myAction.fromValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); + d->convertVariant(myAction.toValue, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); modified << action.property; @@ -1890,10 +1880,10 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, continue; if (d->fromIsDefined) { - d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->from, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.fromValue = d->from; } - d->convertVariant(d->to, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); + d->convertVariant(d->to, d->interpolatorType ? d->interpolatorType : myAction.property.propertyType()); myAction.toValue = d->to; data->actions << myAction; } diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index fce5eca..87d480f 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -63,7 +63,7 @@ #include <QtDeclarative/qmlanimation.h> #include <QtDeclarative/qml.h> #include <QtDeclarative/qmlcontext.h> -#include <QtDeclarative/qmltimelinevalueproxy.h> +#include <private/qmltimeline_p.h> QT_BEGIN_NAMESPACE @@ -346,7 +346,7 @@ public: QmlTimeLineValueProxy<QmlPropertyAnimationPrivate> value; static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress); - static void convertVariant(QVariant &variant, QVariant::Type type); + static void convertVariant(QVariant &variant, int type); }; QT_END_NAMESPACE diff --git a/src/declarative/util/qmlfollow.cpp b/src/declarative/util/qmlfollow.cpp index c6d806a..b8e6685 100644 --- a/src/declarative/util/qmlfollow.cpp +++ b/src/declarative/util/qmlfollow.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include <limits.h> +#include <math.h> #include <QtCore/qdebug.h> #include "private/qobject_p.h" #include "qmlfollow.h" @@ -55,7 +56,7 @@ class QmlFollowPrivate : public QObjectPrivate public: QmlFollowPrivate() : sourceValue(0), maxVelocity(0), lastTime(0) - , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), enabled(true), mode(Track), clock(this) {} + , mass(1.0), spring(0.), damping(0.), velocity(0), epsilon(0.005), modulus(0.0), enabled(true), mode(Track), clock(this) {} QmlMetaProperty property; qreal currentValue; @@ -68,6 +69,7 @@ public: qreal damping; qreal velocity; qreal epsilon; + qreal modulus; bool enabled; enum Mode { @@ -92,6 +94,11 @@ void QmlFollowPrivate::tick(int time) int elapsed = time - lastTime; if (!elapsed) return; + qreal srcVal = sourceValue; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + srcVal = fmod(srcVal, modulus); + } if (mode == Spring) { if (elapsed < 16) // capped at 62fps. return; @@ -99,7 +106,13 @@ void QmlFollowPrivate::tick(int time) // We'll do something much simpler which gives a result that looks fine. int count = (elapsed+8) / 16; for (int i = 0; i < count; ++i) { - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } velocity = velocity + spring * diff - damping * velocity; // The following line supports mass. Not sure its worth the extra divisions. // velocity = velocity + spring / mass * diff - damping / mass * velocity; @@ -111,24 +124,39 @@ void QmlFollowPrivate::tick(int time) velocity = -maxVelocity; } currentValue += velocity * 16.0 / 1000.0; + if (modulus != 0.0) { + currentValue = fmod(currentValue, modulus); + if (currentValue < 0.0) + currentValue += modulus; + } } - if (qAbs(velocity) < epsilon && qAbs(sourceValue - currentValue) < epsilon) { + if (qAbs(velocity) < epsilon && qAbs(srcVal - currentValue) < epsilon) { velocity = 0.0; - currentValue = sourceValue; + currentValue = srcVal; clock.stop(); } lastTime = time - (elapsed - count * 16); } else { qreal moveBy = elapsed * velocityms; - qreal diff = sourceValue - currentValue; + qreal diff = srcVal - currentValue; + if (modulus != 0.0 && qAbs(diff) > modulus / 2) { + if (diff < 0) + diff += modulus; + else + diff -= modulus; + } if (diff > 0) { currentValue += moveBy; + if (modulus != 0.0) + currentValue = fmod(currentValue, modulus); if (currentValue > sourceValue) { currentValue = sourceValue; clock.stop(); } } else { currentValue -= moveBy; + if (modulus != 0.0 && currentValue < 0.0) + currentValue = fmod(currentValue, modulus) + modulus; if (currentValue < sourceValue) { currentValue = sourceValue; clock.stop(); @@ -326,6 +354,25 @@ void QmlFollow::setEpsilon(qreal epsilon) } /*! + \qmlproperty qreal Follow::modulus + This property holds the modulus value. + + Setting a \a modulus forces the target value to "wrap around" at the modulus. + For example, setting the modulus to 360 will cause a value of 370 to wrap around to 10. +*/ +qreal QmlFollow::modulus() const +{ + Q_D(const QmlFollow); + return d->modulus; +} + +void QmlFollow::setModulus(qreal modulus) +{ + Q_D(QmlFollow); + d->modulus = modulus; +} + +/*! \qmlproperty qreal Follow::followValue The current value. */ diff --git a/src/declarative/util/qmlfollow.h b/src/declarative/util/qmlfollow.h index 0953f2c..07e15e9 100644 --- a/src/declarative/util/qmlfollow.h +++ b/src/declarative/util/qmlfollow.h @@ -64,8 +64,10 @@ class Q_DECLARATIVE_EXPORT QmlFollow : public QmlPropertyValueSource, Q_PROPERTY(qreal spring READ spring WRITE setSpring) Q_PROPERTY(qreal damping READ damping WRITE setDamping) Q_PROPERTY(qreal epsilon READ epsilon WRITE setEpsilon) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus) Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) Q_PROPERTY(qreal followValue READ value NOTIFY valueChanged) + Q_PROPERTY(qreal modulus READ modulus WRITE setModulus NOTIFY modulusChanged) public: QmlFollow(QObject *parent=0); @@ -83,6 +85,8 @@ public: void setDamping(qreal damping); qreal epsilon() const; void setEpsilon(qreal epsilon); + qreal modulus() const; + void setModulus(qreal modulus); bool enabled() const; void setEnabled(bool enabled); diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp index f8cbf96..8d03804 100644 --- a/src/declarative/util/qmlscript.cpp +++ b/src/declarative/util/qmlscript.cpp @@ -55,7 +55,7 @@ #include <QNetworkReply> #include <QNetworkRequest> #include <QtDeclarative/qmlinfo.h> -#include <qfxperf.h> +#include <private/qfxperf_p.h> QT_BEGIN_NAMESPACE diff --git a/src/declarative/timeline/qmltimeline.cpp b/src/declarative/util/qmltimeline.cpp index dcc8745..5ba310d 100644 --- a/src/declarative/timeline/qmltimeline.cpp +++ b/src/declarative/util/qmltimeline.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qmltimeline.h" +#include "qmltimeline_p.h" #include <QDebug> #include <QMutex> #include <QThread> diff --git a/src/declarative/timeline/qmltimeline.h b/src/declarative/util/qmltimeline_p.h index 627ec79..abed80a 100644 --- a/src/declarative/timeline/qmltimeline.h +++ b/src/declarative/util/qmltimeline_p.h @@ -42,16 +42,23 @@ #ifndef QMLTIMELINE_H #define QMLTIMELINE_H +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + #include <QtCore/QObject> #include <QtCore/QAbstractAnimation> #include <QtDeclarative/qfxglobal.h> -QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE -QT_MODULE(Declarative) - class QEasingCurve; class QmlTimeLineValue; class QmlTimeLineEvent; @@ -183,8 +190,35 @@ private: QmlTimeLineObject *d2; }; -QT_END_NAMESPACE +template<class T> +class QmlTimeLineValueProxy : public QmlTimeLineValue +{ +public: + QmlTimeLineValueProxy(T *cls, void (T::*func)(qreal), qreal v = 0.) + : QmlTimeLineValue(v), _class(cls), _setFunctionReal(func), _setFunctionInt(0) + { + Q_ASSERT(_class); + } + + QmlTimeLineValueProxy(T *cls, void (T::*func)(int), qreal v = 0.) + : QmlTimeLineValue(v), _class(cls), _setFunctionReal(0), _setFunctionInt(func) + { + Q_ASSERT(_class); + } + + virtual void setValue(qreal v) + { + QmlTimeLineValue::setValue(v); + if (_setFunctionReal) (_class->*_setFunctionReal)(v); + else if (_setFunctionInt) (_class->*_setFunctionInt)((int)v); + } -QT_END_HEADER +private: + T *_class; + void (T::*_setFunctionReal)(qreal); + void (T::*_setFunctionInt)(int); +}; + +QT_END_NAMESPACE #endif diff --git a/src/declarative/util/qperformancelog.cpp b/src/declarative/util/qperformancelog.cpp index 932e4b3..8e11997 100644 --- a/src/declarative/util/qperformancelog.cpp +++ b/src/declarative/util/qperformancelog.cpp @@ -39,7 +39,7 @@ ** ****************************************************************************/ -#include "qperformancelog.h" +#include "qperformancelog_p.h" #include <QHash> #include <QDebug> diff --git a/src/declarative/util/qperformancelog.h b/src/declarative/util/qperformancelog_p.h index 6655a8d..6655a8d 100644 --- a/src/declarative/util/qperformancelog.h +++ b/src/declarative/util/qperformancelog_p.h diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index 0619a47..aae10af 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -17,13 +17,14 @@ SOURCES += \ util/qmllistmodel.cpp\ util/qmllistaccessor.cpp \ util/qmlopenmetaobject.cpp \ + util/qmltimeline.cpp \ util/qmlbind.cpp HEADERS += \ util/qfxview.h \ - util/qfxperf.h \ + util/qfxperf_p.h \ util/qfxglobal.h \ - util/qperformancelog.h \ + util/qperformancelog_p.h \ util/qmlconnection.h \ util/qmlpackage.h \ util/qmlscript.h \ @@ -42,4 +43,5 @@ HEADERS += \ util/qmllistaccessor.h \ util/qmlopenmetaobject.h \ util/qmlnullablevalue_p.h \ + util/qmltimeline_p.h \ util/qmlbind.h |