diff options
Diffstat (limited to 'src/declarative')
30 files changed, 352 insertions, 115 deletions
diff --git a/src/declarative/debugger/qmldebug.cpp b/src/declarative/debugger/qmldebug.cpp index 2537ec0..5a8cda0 100644 --- a/src/declarative/debugger/qmldebug.cpp +++ b/src/declarative/debugger/qmldebug.cpp @@ -67,26 +67,30 @@ int QmlEngineDebugPrivate::getId() void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugEnginesQuery *q) { QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c); - p->enginesQuery.remove(q->m_queryId); + if (p && q) + p->enginesQuery.remove(q->m_queryId); } void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugRootContextQuery *q) { QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c); - p->rootContextQuery.remove(q->m_queryId); + if (p && q) + p->rootContextQuery.remove(q->m_queryId); } void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugObjectQuery *q) { QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c); - p->objectQuery.remove(q->m_queryId); + if (p && q) + p->objectQuery.remove(q->m_queryId); } void QmlEngineDebugPrivate::remove(QmlEngineDebug *c, QmlDebugExpressionQuery *q) { QmlEngineDebugPrivate *p = (QmlEngineDebugPrivate *)QObjectPrivate::get(c); - p->expressionQuery.remove(q->m_queryId); + if (p && q) + p->expressionQuery.remove(q->m_queryId); } Q_DECLARE_METATYPE(QmlDebugObjectReference); @@ -118,9 +122,10 @@ void QmlEngineDebugPrivate::decode(QDataStream &ds, QmlDebugObjectReference &o, prop.m_binding = data.binding; prop.m_hasNotifySignal = data.hasNotifySignal; prop.m_valueTypeName = data.valueTypeName; - if (data.type == QmlEngineDebugServer::QmlObjectProperty::Basic) + if (data.type == QmlEngineDebugServer::QmlObjectProperty::Basic + || data.type == QmlEngineDebugServer::QmlObjectProperty::List) { prop.m_value = data.value; - else if (data.type == QmlEngineDebugServer::QmlObjectProperty::Object) { + } else if (data.type == QmlEngineDebugServer::QmlObjectProperty::Object) { QmlDebugObjectReference obj; obj.m_debugId = prop.m_value.toInt(); prop.m_value = qVariantFromValue(obj); diff --git a/src/declarative/extra/qmlxmllistmodel.cpp b/src/declarative/extra/qmlxmllistmodel.cpp index df89f56..a3c96fd 100644 --- a/src/declarative/extra/qmlxmllistmodel.cpp +++ b/src/declarative/extra/qmlxmllistmodel.cpp @@ -406,6 +406,11 @@ void QmlXmlRoleList::insert(int i, QmlXmlListModelRole *role) } /*! + \class QmlXmlListModel + \internal +*/ + +/*! \qmlclass XmlListModel \brief The XmlListModel element allows you to specify a model using XPath expressions. diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 860af66..45a481c 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -82,7 +82,7 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Image,QFxImage) \o fillMode: Tile \qml Image { - fillMode: "Tile" + fillMode: Image.Tile width: 160; height: 160 source: "pics/qtlogo.png" } @@ -92,7 +92,7 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Image,QFxImage) \o fillMode: TileVertically \qml Image { - fillMode: "TileVertically" + fillMode: Image.TileVertically width: 160; height: 160 source: "pics/qtlogo.png" } @@ -102,7 +102,7 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Image,QFxImage) \o fillMode: TileHorizontally \qml Image { - fillMode: "TileHorizontally" + fillMode: Image.TileHorizontally width: 160; height: 160 source: "pics/qtlogo.png" } @@ -161,7 +161,7 @@ void QFxImage::setPixmap(const QPixmap &pix) } /*! - \qmlproperty FillMode Image::fillMode + \qmlproperty enumeration Image::fillMode Set this property to define what happens when the image set for the item is smaller than the size of the item. diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index e714494..ed07696 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -79,6 +79,19 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Rotation,QGraphicsRotation) #include "qfxeffects.cpp" /*! + \qmlclass Transform + \brief The Transform elements provide a way of building advanced transformations on Items. + + The Transform elements let you create and control advanced transformations that can be configured + independently using specialized properties. + + You can assign any number of Transform elements to an Item. Each Transform is applied in order, + one at a time, to the Item it's assigned to. + + \sa Rotation, Scale +*/ + +/*! \qmlclass Scale \brief The Scale object provides a way to scale an Item. @@ -1199,7 +1212,7 @@ QFxKeysAttached *QFxKeysAttached::qmlAttachedProperties(QObject *obj) /*! \class QFxItem - \brief QFxItem is the most basic of all visual items in QML. + \brief The QFxItem class provides the most basic of all visual items in QML. All visual items in Qt Declarative inherit from QFxItem. Although QFxItem has no visual appearance, it defines all the properties that are @@ -1295,7 +1308,7 @@ QFxKeysAttached *QFxKeysAttached::qmlAttachedProperties(QObject *obj) This signal is emitted when the \a state of the item changes. - \sa states-transitions + \sa {qmlstates}{States} */ /*! @@ -2315,14 +2328,14 @@ QmlList<QObject *> *QFxItem::resources() } \endqml - \sa {states-transitions}{States and Transitions} + \sa {qmlstate}{States} */ /*! \property QFxItem::states This property holds a list of states defined by the item. - \sa {states-transitions}{States and Transitions} + \sa {qmlstate}{States} */ QmlList<QmlState *>* QFxItem::states() { @@ -2344,14 +2357,14 @@ QmlList<QmlState *>* QFxItem::states() } \endqml - \sa {states-transitions}{States and Transitions} + \sa {state-transitions}{Transitions} */ /*! \property QFxItem::transitions This property holds a list of transitions defined by the item. - \sa {states-transitions}{States and Transitions} + \sa {state-transitions}{Transitions} */ QmlList<QmlTransition *>* QFxItem::transitions() { @@ -2423,7 +2436,7 @@ QmlList<QmlTransition *>* QFxItem::transitions() set), \c state will be a blank string. Likewise, you can return an item to its base state by setting its current state to \c ''. - \sa {states-transitions}{States and Transitions} + \sa {qmlstates}{States} */ /*! @@ -2449,7 +2462,7 @@ QmlList<QmlTransition *>* QFxItem::transitions() set), \c state will be a blank string. Likewise, you can return an item to its base state by setting its current state to \c ''. - \sa {states-transitions}{States and Transitions} + \sa {qmlstates}{States} */ QString QFxItem::state() const { diff --git a/src/declarative/fx/qfxmouseregion.cpp b/src/declarative/fx/qfxmouseregion.cpp index 4b31fd4..315a273 100644 --- a/src/declarative/fx/qfxmouseregion.cpp +++ b/src/declarative/fx/qfxmouseregion.cpp @@ -319,8 +319,8 @@ void QFxMouseRegion::setEnabled(bool a) \code Text { text: mr.pressedButtons & Qt.RightButton ? "right" : "" - horizontalAlignment: "AlignHCenter" - verticalAlignment: "AlignVCenter" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter MouseRegion { id: mr acceptedButtons: Qt.LeftButton | Qt.RightButton diff --git a/src/declarative/fx/qfxpositioners.cpp b/src/declarative/fx/qfxpositioners.cpp index f8e7213..86a069d 100644 --- a/src/declarative/fx/qfxpositioners.cpp +++ b/src/declarative/fx/qfxpositioners.cpp @@ -375,6 +375,10 @@ Column { \endqml \endtable + Note that the positioner assumes that the x and y positions of its children + will not change. If you manually change the x or y properties in script, bind + the x or y properties, or use anchors on a child of a positioner, then the + positioner may exhibit strange behaviour. */ /*! @@ -539,6 +543,11 @@ Row { \endqml \image horizontalpositioner_example.png + Note that the positioner assumes that the x and y positions of its children + will not change. If you manually change the x or y properties in script, bind + the x or y properties, or use anchors on a child of a positioner, then the + positioner may exhibit strange behaviour. + */ /*! \qmlproperty Transition Row::remove @@ -659,8 +668,10 @@ void QFxRow::doPositioning() child->setX(hoffset); setMovingItem(0); } - hoffset += child->width(); - hoffset += spacing(); + if(child->width() && child->height()){//don't advance for invisible children + hoffset += child->width(); + hoffset += spacing(); + } } } @@ -705,6 +716,11 @@ Grid { } \endqml \endtable + + Note that the positioner assumes that the x and y positions of its children + will not change. If you manually change the x or y properties in script, bind + the x or y properties, or use anchors on a child of a positioner, then the + positioner may exhibit strange behaviour. */ /*! \qmlproperty Transition Grid::remove diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp index 4d02f0d..4a01cbd 100644 --- a/src/declarative/fx/qfxtext.cpp +++ b/src/declarative/fx/qfxtext.cpp @@ -231,9 +231,9 @@ QColor QFxText::color() const \qml Row { Text { font.pointSize: 24; text: "Normal" } - Text { font.pointSize: 24; text: "Raised"; style: "Raised"; styleColor: "#AAAAAA" } - Text { font.pointSize: 24; text: "Outline"; style: "Outline"; styleColor: "red" } - Text { font.pointSize: 24; text: "Sunken"; style: "Sunken"; styleColor: "#AAAAAA" } + Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" } + Text { font.pointSize: 24; text: "Outline"; style: Text.Outline; styleColor: "red" } + Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" } } \endqml @@ -420,28 +420,28 @@ void QFxText::setTextFormat(TextFormat format) } /*! - \qmlproperty Qt::TextElideMode Text::elide + \qmlproperty enumeration Text::elide Set this property to elide parts of the text fit to the Text item's width. The text will only elide if an explicit width has been set. This property cannot be used with wrap enabled or with rich text. - Eliding can be ElideNone (the default), ElideLeft, ElideMiddle, or ElideRight. + Eliding can be \c ElideNone (the default), \c ElideLeft, \c ElideMiddle, or \c ElideRight. - If the text is a multi-length string, and the mode is not ElideNone, + If the text is a multi-length string, and the mode is not \c ElideNone, the first string that fits will be used, otherwise the last will be elided. Multi-length strings are ordered from longest to shortest, separated by the - Unicode "String Terminator" character U009C (write this in QML with "\\x9C"). + Unicode "String Terminator" character \c U009C (write this in QML with \c{"\\x9C"}). */ -Qt::TextElideMode QFxText::elideMode() const +QFxText::TextElideMode QFxText::elideMode() const { Q_D(const QFxText); return d->elideMode; } -void QFxText::setElideMode(Qt::TextElideMode mode) +void QFxText::setElideMode(QFxText::TextElideMode mode) { Q_D(QFxText); if (mode == d->elideMode) @@ -458,7 +458,7 @@ void QFxText::geometryChanged(const QRectF &newGeometry, { Q_D(QFxText); if (newGeometry.width() != oldGeometry.width()) { - if (d->wrap || d->elideMode != Qt::ElideNone) { + if (d->wrap || d->elideMode != QFxText::ElideNone) { d->imgDirty = true; d->updateSize(); } @@ -486,8 +486,8 @@ void QFxTextPrivate::updateSize() tmp = text; tmp.replace(QLatin1Char('\n'), QChar::LineSeparator); singleline = !tmp.contains(QChar::LineSeparator); - if (singleline && elideMode != Qt::ElideNone && q->widthValid()) - tmp = fm.elidedText(tmp,elideMode,q->width()); // XXX still worth layout...? + if (singleline && elideMode != QFxText::ElideNone && q->widthValid()) + tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); // XXX still worth layout...? layout.clearLayout(); layout.setFont(font); layout.setText(tmp); @@ -586,7 +586,7 @@ QSize QFxTextPrivate::setupTextLayout(QTextLayout *layout) qreal lineWidth = 0; //set manual width - if ((wrap || elideMode != Qt::ElideNone) && q->widthValid()) + if ((wrap || elideMode != QFxText::ElideNone) && q->widthValid()) lineWidth = q->width(); layout->beginLayout(); @@ -596,7 +596,7 @@ QSize QFxTextPrivate::setupTextLayout(QTextLayout *layout) if (!line.isValid()) break; - if ((wrap || elideMode != Qt::ElideNone) && q->widthValid()) + if ((wrap || elideMode != QFxText::ElideNone) && q->widthValid()) line.setLineWidth(lineWidth); } layout->endLayout(); diff --git a/src/declarative/fx/qfxtext.h b/src/declarative/fx/qfxtext.h index 763e2aa..cdb8025 100644 --- a/src/declarative/fx/qfxtext.h +++ b/src/declarative/fx/qfxtext.h @@ -57,6 +57,7 @@ class Q_DECLARATIVE_EXPORT QFxText : public QFxItem Q_ENUMS(VAlignment) Q_ENUMS(TextStyle) Q_ENUMS(TextFormat) + Q_ENUMS(TextElideMode) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QFont font READ font WRITE setFont) @@ -67,7 +68,7 @@ class Q_DECLARATIVE_EXPORT QFxText : public QFxItem Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign) Q_PROPERTY(bool wrap READ wrap WRITE setWrap) //### there are several wrap modes in Qt Q_PROPERTY(TextFormat textFormat READ textFormat WRITE setTextFormat) - Q_PROPERTY(Qt::TextElideMode elide READ elideMode WRITE setElideMode) //### elideMode? + Q_PROPERTY(TextElideMode elide READ elideMode WRITE setElideMode) //### elideMode? public: QFxText(QFxItem *parent=0); @@ -84,8 +85,12 @@ public: Raised, Sunken }; enum TextFormat { PlainText = Qt::PlainText, - RichText = Qt::RichText, - AutoText = Qt::AutoText }; + RichText = Qt::RichText, + AutoText = Qt::AutoText }; + enum TextElideMode { ElideLeft = Qt::ElideLeft, + ElideRight = Qt::ElideRight, + ElideMiddle = Qt::ElideMiddle, + ElideNone = Qt::ElideNone }; QString text() const; void setText(const QString &); @@ -114,8 +119,8 @@ public: TextFormat textFormat() const; void setTextFormat(TextFormat format); - Qt::TextElideMode elideMode() const; - void setElideMode(Qt::TextElideMode); + TextElideMode elideMode() const; + void setElideMode(TextElideMode); void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); diff --git a/src/declarative/fx/qfxtext_p.h b/src/declarative/fx/qfxtext_p.h index 8b24c66..a10cdfa 100644 --- a/src/declarative/fx/qfxtext_p.h +++ b/src/declarative/fx/qfxtext_p.h @@ -70,7 +70,7 @@ class QFxTextPrivate : public QFxItemPrivate public: QFxTextPrivate() : color((QRgb)0), style(QFxText::Normal), imgDirty(true), - hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(Qt::ElideNone), + hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), elideMode(QFxText::ElideNone), dirty(true), wrap(false), richText(false), singleline(false), control(0), doc(0), format(QFxText::AutoText) { @@ -97,7 +97,7 @@ public: QPixmap imgStyleCache; QFxText::HAlignment hAlign; QFxText::VAlignment vAlign; - Qt::TextElideMode elideMode; + QFxText::TextElideMode elideMode; bool dirty; bool wrap; bool richText; diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 65ff789..317a4b3 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -58,10 +58,46 @@ QT_BEGIN_NAMESPACE QML_DEFINE_NOCREATE_TYPE(QmlBinding); QmlBindingData::QmlBindingData() -: updating(false), enabled(false) +: updating(false), enabled(false), nextError(0), prevError(0) { } +QmlBindingData::~QmlBindingData() +{ + removeError(); +} + +void QmlBindingData::removeError() +{ + if (!prevError) return; + + if (nextError) nextError->prevError = prevError; + *prevError = nextError; + nextError = 0; + prevError = 0; +} + +bool QmlBindingData::addError() +{ + if (prevError) return false; + + QmlContext *c = context(); + if (!c) return false; + QmlEngine *e = c->engine(); + if (!e) return false; + + QmlEnginePrivate *p = QmlEnginePrivate::get(e); + + if (p->inProgressCreations == 0) return false; // Not in construction + + prevError = &p->erroredBindings; + nextError = p->erroredBindings; + p->erroredBindings = this; + if (nextError) nextError->prevError = &nextError; + + return true; +} + QmlBindingPrivate::QmlBindingPrivate() : QmlExpressionPrivate(new QmlBindingData) { @@ -128,10 +164,12 @@ void QmlBinding::update(QmlMetaProperty::WriteFlags flags) idx, a); } else { - bool undefined = false; - QVariant value = this->value(&undefined); + bool isUndefined = false; + QVariant value = this->value(&isUndefined); + + if (!isUndefined && data->property.object() && + !data->property.write(value, flags)) { - if (!undefined && data->property.object() && !data->property.write(value, flags)) { QString fileName = data->fileName; int line = data->line; if (fileName.isEmpty()) fileName = QLatin1String("<Unknown File>"); @@ -139,9 +177,21 @@ void QmlBinding::update(QmlMetaProperty::WriteFlags flags) const char *valueType = 0; if (value.userType() == QVariant::Invalid) valueType = "null"; else valueType = QMetaType::typeName(value.userType()); - qWarning().nospace() << qPrintable(fileName) << ":" << line - << " Unable to assign " << valueType << " to " - << QMetaType::typeName(data->property.propertyType()); + + data->error.setUrl(fileName); + data->error.setLine(line); + data->error.setColumn(-1); + data->error.setDescription(QLatin1String("Unable to assign ") + + QLatin1String(valueType) + + QLatin1String(" to ") + + QLatin1String(QMetaType::typeName(data->property.propertyType()))); + } + + if (data->error.isValid()) { + if (!data->addError()) + qWarning().nospace() << qPrintable(this->error().toString()); + } else { + data->removeError(); } } diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h index 2c0c6b9..c9378cb 100644 --- a/src/declarative/qml/qmlbinding_p.h +++ b/src/declarative/qml/qmlbinding_p.h @@ -63,11 +63,17 @@ class QmlBindingData : public QmlExpressionData { public: QmlBindingData(); + virtual ~QmlBindingData(); bool updating:1; bool enabled:1; QmlMetaProperty property; + + void removeError(); + bool addError(); + QmlBindingData *nextError; + QmlBindingData **prevError; }; class QmlBindingPrivate : public QmlExpressionPrivate diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp index ce591e8..d715309 100644 --- a/src/declarative/qml/qmlboundsignal.cpp +++ b/src/declarative/qml/qmlboundsignal.cpp @@ -175,8 +175,11 @@ int QmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) { if (c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { if (m_params) m_params->setValues(a); - if (m_expression) + if (m_expression) { QmlExpressionPrivate::get(m_expression)->value(m_params); + if (m_expression->hasError()) + qWarning().nospace() << qPrintable(m_expression->error().toString()); + } if (m_params) m_params->clearValues(); return -1; } else { diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index ad74446..7a417bb 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -150,6 +150,8 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) } /*! + \macro COMPILE_EXCEPTION + \internal Inserts an error into the QmlCompiler error list, and returns false (failure). @@ -175,6 +177,8 @@ bool QmlCompiler::isSignalPropertyName(const QByteArray &name) } /*! + \macro COMPILE_CHECK + \internal Returns false if \a is false, otherwise does nothing. */ #define COMPILE_CHECK(a) \ diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 0894758..6181f41 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -55,6 +55,7 @@ #include "qmlbinding.h" #include <QtCore/qdebug.h> #include <QApplication> +#include <private/qmlbinding_p.h> #include "qmlscriptparser_p.h" @@ -74,7 +75,7 @@ int statusId = qRegisterMetaType<QmlComponent::Status>("QmlComponent::Status"); \brief The Component element encapsulates a QML component description. Components are reusable, encapsulated Qml element with a well-defined interface. - They are often defined in \l {components}{Component Files}. + They are often defined in \l {qmldocuments.html}{Component Files}. The \e Component element allows defining components within a QML file. This can be useful for reusing a small component within a single QML @@ -197,6 +198,12 @@ QmlComponent::QmlComponent(QObject *parent) QmlComponent::~QmlComponent() { Q_D(QmlComponent); + + if (d->completePending) { + qWarning("QmlComponent: Component destroyed while completion pending"); + d->completeCreate(); + } + if (d->typeData) { d->typeData->remWaiter(d); d->typeData->release(); @@ -267,6 +274,10 @@ bool QmlComponent::isLoading() const return status() == Loading; } +/*! + Returns he progress of loading the component, from 0.0 (nothing loaded) + to 1.0 (finished). +*/ qreal QmlComponent::progress() const { Q_D(const QmlComponent); @@ -274,6 +285,13 @@ qreal QmlComponent::progress() const } /*! + \fn void QmlComponent::progressChanged(qreal progress) + + Emitted whenever the component's loading progress changes. \a progress will be the + current progress between 0.0 (nothing loaded) and 1.0 (finished). +*/ + +/*! \fn void QmlComponent::statusChanged(QmlComponent::Status status) Emitted whenever the component's status changes. \a status will be the @@ -368,8 +386,9 @@ void QmlComponent::setData(const QByteArray &data, const QUrl &url) QmlCompositeTypeData *typeData = QmlEnginePrivate::get(d->engine)->typeManager.getImmediate(data, url); - if (typeData->status == QmlCompositeTypeData::Waiting) { - + if (typeData->status == QmlCompositeTypeData::Waiting + || typeData->status == QmlCompositeTypeData::WaitingResources) + { d->typeData = typeData; d->typeData->addWaiter(d); @@ -414,7 +433,9 @@ void QmlComponent::loadUrl(const QUrl &url) QmlCompositeTypeData *data = QmlEnginePrivate::get(d->engine)->typeManager.get(d->url); - if (data->status == QmlCompositeTypeData::Waiting) { + if (data->status == QmlCompositeTypeData::Waiting + || data->status == QmlCompositeTypeData::WaitingResources) + { d->typeData = data; d->typeData->addWaiter(d); d->progress = data->progress; @@ -574,8 +595,10 @@ QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) ep->bindValues.clear(); ep->parserStatus.clear(); completePending = true; + QmlEnginePrivate::get(engine)->inProgressCreations++; } + if (rv) { QFx_setParent_noEvent(ctxt, rv); } else { @@ -643,6 +666,14 @@ void QmlComponentPrivate::completeCreate() bindValues.clear(); parserStatus.clear(); completePending = false; + QmlEnginePrivate *p = QmlEnginePrivate::get(engine); + p->inProgressCreations--; + if (0 == p->inProgressCreations) { + while (p->erroredBindings) { + qWarning().nospace() << qPrintable(p->erroredBindings->error.toString()); + p->erroredBindings->removeError(); + } + } } } @@ -659,6 +690,9 @@ QmlComponentAttached::~QmlComponentAttached() next = 0; } +/*! + \internal +*/ QmlComponentAttached *QmlComponent::qmlAttachedProperties(QObject *obj) { QmlComponentAttached *a = new QmlComponentAttached(obj); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 2ebdf10..5032ff4 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -77,8 +77,11 @@ void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject, QScriptValue val = scriptEngine->evaluate(script, fileName, lineNumber); - if (scriptEngine->hasUncaughtException()) - QmlExpressionPrivate::printException(scriptEngine); + if (scriptEngine->hasUncaughtException()) { + QmlError error; + QmlExpressionPrivate::exceptionToError(scriptEngine, error); + qWarning().nospace() << qPrintable(error.toString()); + } scriptEngine->popContext(); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 8581751..426ebc6 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -118,8 +118,9 @@ static QString userLocalDataPath(const QString& app) QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentExpression(0), isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), globalClass(0), - nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), cleanup(0), scriptEngine(this), - componentAttacheds(0), rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) + nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), cleanup(0), erroredBindings(0), + inProgressCreations(0), scriptEngine(this), componentAttacheds(0), rootComponent(0), + networkAccessManager(0), typeManager(e), uniqueId(1) { // Note that all documentation for stuff put on the global object goes in // doc/src/declarative/globalobject.qdoc diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index f5bc015..53d867d 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -98,6 +98,7 @@ class QmlTypeNameCache; class QmlComponentAttached; class QmlListScriptClass; class QmlCleanup; +class QmlBindingData; class QmlEnginePrivate : public QObjectPrivate { @@ -143,6 +144,10 @@ public: // Registered cleanup handlers QmlCleanup *cleanup; + // Bindings that have had errors during startup + QmlBindingData *erroredBindings; + int inProgressCreations; + struct QmlScriptEngine : public QScriptEngine { QmlScriptEngine(QmlEnginePrivate *priv) diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index 664ca3f..63be6b0 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -57,8 +57,8 @@ QmlEngineDebugServer::QmlEngineDebugServer(QObject *parent) : QmlDebugService(QLatin1String("QmlEngine"), parent), m_watch(new QmlWatcher(this)) { - QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QByteArray,QVariant)), - this, SLOT(propertyChanged(int,int,QByteArray,QVariant))); + QObject::connect(m_watch, SIGNAL(propertyChanged(int,int,QMetaProperty,QVariant)), + this, SLOT(propertyChanged(int,int,QMetaProperty,QVariant))); } QDataStream &operator<<(QDataStream &ds, @@ -110,9 +110,11 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) if (binding) rv.binding = binding->expression(); + QVariant value = prop.read(obj); + rv.value = valueContents(value); + if (prop.type() < QVariant::UserType) { rv.type = QmlObjectProperty::Basic; - rv.value = prop.read(obj); } else if (QmlMetaType::isObject(prop.userType())) { rv.type = QmlObjectProperty::Object; } else if (QmlMetaType::isList(prop.userType()) || @@ -123,6 +125,32 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) return rv; } +QVariant QmlEngineDebugServer::valueContents(const QVariant &value) const +{ + if (value.type() < QVariant::UserType) + return value; + + int userType = value.userType(); + + if (QmlMetaType::isList(userType) || QmlMetaType::isQmlList(userType)) { + int count = QmlMetaType::listCount(value); + QVariantList contents; + for (int i=0; i<count; i++) + contents << valueContents(QmlMetaType::listAt(value, i)); + return contents; + } else if (QmlMetaType::isObject(userType)) { + QObject *o = QmlMetaType::toQObject(value); + if (o) { + QString name = o->objectName(); + if (name.isEmpty()) + name = QLatin1String("<unnamed>"); + return name; + } + } + + return QLatin1String("<unknown value>"); +} + void QmlEngineDebugServer::buildObjectDump(QDataStream &message, QObject *object, bool recur) { @@ -188,32 +216,6 @@ void QmlEngineDebugServer::buildObjectList(QDataStream &message, } } -QVariant QmlEngineDebugServer::serializableVariant(const QVariant &value) -{ - if (value.type() < QVariant::UserType) - return value; - - if (!value.toString().isEmpty()) - return value.toString(); - - QVariant v; - if (value.type() == QVariant::UserType || QmlMetaType::isObject(value.userType())) { - QObject *o = QmlMetaType::toQObject(value); - if (o) { - QString objectName = o->objectName(); - if (objectName.isEmpty()) - objectName = QLatin1String("<unnamed>"); - v = QString::fromUtf8(o->metaObject()->className()) + - QLatin1String(": ") + objectName; - } - } - - if (v.isNull()) - v = QString::fromUtf8(value.typeName()); - - return v; -} - QmlEngineDebugServer::QmlObjectData QmlEngineDebugServer::objectData(QObject *object) { @@ -357,7 +359,7 @@ void QmlEngineDebugServer::messageReceived(const QByteArray &message) if (undefined) result = QLatin1String("<undefined>"); else - result = serializableVariant(value); + result = valueContents(value); delete exprObj; } else { result = QLatin1String("<unknown context>"); @@ -371,13 +373,12 @@ void QmlEngineDebugServer::messageReceived(const QByteArray &message) } } -void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QByteArray &property, const QVariant &value) +void QmlEngineDebugServer::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) { QByteArray reply; - QVariant v = serializableVariant(value); QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("UPDATE_WATCH") << id << objectId << property << v; + rs << QByteArray("UPDATE_WATCH") << id << objectId << QString::fromUtf8(property.name()) << valueContents(value); sendMessage(reply); } diff --git a/src/declarative/qml/qmlenginedebug_p.h b/src/declarative/qml/qmlenginedebug_p.h index 075a711..a8572eb 100644 --- a/src/declarative/qml/qmlenginedebug_p.h +++ b/src/declarative/qml/qmlenginedebug_p.h @@ -97,14 +97,14 @@ protected: virtual void messageReceived(const QByteArray &); private Q_SLOTS: - void propertyChanged(int id, int objectId, const QByteArray &property, const QVariant &value); + void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); private: void buildObjectList(QDataStream &, QmlContext *); void buildObjectDump(QDataStream &, QObject *, bool); QmlObjectData objectData(QObject *); QmlObjectProperty propertyData(QObject *, int); - QVariant serializableVariant(const QVariant &value); + QVariant valueContents(const QVariant &defaultValue) const; static QList<QmlEngine *> m_engines; QmlWatcher *m_watch; diff --git a/src/declarative/qml/qmlerror.cpp b/src/declarative/qml/qmlerror.cpp index 514fe44..f4c9580 100644 --- a/src/declarative/qml/qmlerror.cpp +++ b/src/declarative/qml/qmlerror.cpp @@ -70,7 +70,7 @@ QmlErrorPrivate::QmlErrorPrivate() Create an empty error object. */ QmlError::QmlError() -: d(new QmlErrorPrivate) +: d(0) { } @@ -78,7 +78,7 @@ QmlError::QmlError() Create a copy of \a other. */ QmlError::QmlError(const QmlError &other) -: d(new QmlErrorPrivate) +: d(0) { *this = other; } @@ -88,10 +88,16 @@ QmlError::QmlError(const QmlError &other) */ QmlError &QmlError::operator=(const QmlError &other) { - d->url = other.d->url; - d->description = other.d->description; - d->line = other.d->line; - d->column = other.d->column; + if (!other.d) { + delete d; + d = 0; + } else { + if (!d) d = new QmlErrorPrivate; + d->url = other.d->url; + d->description = other.d->description; + d->line = other.d->line; + d->column = other.d->column; + } return *this; } @@ -104,11 +110,20 @@ QmlError::~QmlError() } /*! + Return true if this error is valid, otherwise false. +*/ +bool QmlError::isValid() const +{ + return d != 0; +} + +/*! Return the url for the file that caused this error. */ QUrl QmlError::url() const { - return d->url; + if (d) return d->url; + else return QUrl(); } /*! @@ -116,6 +131,7 @@ QUrl QmlError::url() const */ void QmlError::setUrl(const QUrl &url) { + if (!d) d = new QmlErrorPrivate; d->url = url; } @@ -124,7 +140,8 @@ void QmlError::setUrl(const QUrl &url) */ QString QmlError::description() const { - return d->description; + if (d) return d->description; + else return QString(); } /*! @@ -132,6 +149,7 @@ QString QmlError::description() const */ void QmlError::setDescription(const QString &description) { + if (!d) d = new QmlErrorPrivate; d->description = description; } @@ -140,7 +158,8 @@ void QmlError::setDescription(const QString &description) */ int QmlError::line() const { - return d->line; + if (d) return d->line; + else return -1; } /*! @@ -148,6 +167,7 @@ int QmlError::line() const */ void QmlError::setLine(int line) { + if (!d) d = new QmlErrorPrivate; d->line = line; } @@ -156,7 +176,8 @@ void QmlError::setLine(int line) */ int QmlError::column() const { - return d->column; + if (d) return d->column; + else return -1; } /*! @@ -164,6 +185,7 @@ int QmlError::column() const */ void QmlError::setColumn(int column) { + if (!d) d = new QmlErrorPrivate; d->column = column; } diff --git a/src/declarative/qml/qmlerror.h b/src/declarative/qml/qmlerror.h index c1a8720..ee3d7b4 100644 --- a/src/declarative/qml/qmlerror.h +++ b/src/declarative/qml/qmlerror.h @@ -61,6 +61,8 @@ public: QmlError &operator=(const QmlError &); ~QmlError(); + bool isValid() const; + QUrl url() const; void setUrl(const QUrl &); QString description() const; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index c62756b..e5e5cf9 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -260,7 +260,8 @@ QVariant QmlExpressionPrivate::evalSSE() return rv; } -void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) +void QmlExpressionPrivate::exceptionToError(QScriptEngine *scriptEngine, + QmlError &error) { if (scriptEngine->hasUncaughtException() && scriptEngine->uncaughtException().isError()) { @@ -277,8 +278,12 @@ void QmlExpressionPrivate::printException(QScriptEngine *scriptEngine) fileName = QLatin1String("<Unknown File>"); } - qWarning().nospace() << qPrintable(fileName) << ":" << lineNumber << ": " - << qPrintable(exception.toString()); + error.setUrl(QUrl(fileName)); + error.setLine(lineNumber); + error.setColumn(-1); + error.setDescription(exception.toString()); + } else { + error = QmlError(); } } @@ -288,6 +293,7 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUnd QFxPerfTimer<QFxPerf::BindValueQt> perfqt; #endif + QmlExpressionData *data = this->data; QmlContextPrivate *ctxtPriv = data->context()->d_func(); QmlEngine *engine = data->context()->engine(); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); @@ -321,10 +327,13 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope, bool *isUnd if (isUndefined) *isUndefined = svalue.isUndefined() || scriptEngine->hasUncaughtException(); + // Handle exception if (scriptEngine->hasUncaughtException()) { - printException(scriptEngine); + exceptionToError(scriptEngine, data->error); scriptEngine->clearExceptions(); return QVariant(); + } else { + data->error = QmlError(); } if (secondaryScope) { @@ -418,6 +427,8 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope, bool *isUndefined) \a isUndefined is set to true if the expression resulted in an undefined value. + + \sa hasError(), error() */ QVariant QmlExpression::value(bool *isUndefined) { @@ -509,6 +520,43 @@ QObject *QmlExpression::scopeObject() const return d->data->me; } +/*! + Returns true if the last call to value() resulted in an error, + otherwise false. + + \sa error(), clearError() +*/ +bool QmlExpression::hasError() const +{ + Q_D(const QmlExpression); + return d->data->error.isValid(); +} + +/*! + Clear any expression errors. Calls to hasError() following this will + return false. + + \sa hasError(), error() +*/ +void QmlExpression::clearError() +{ + Q_D(QmlExpression); + d->data->error = QmlError(); +} + +/*! + Return any error from the last call to value(). If there was no error, + this returns an invalid QmlError instance. + + \sa hasError(), clearError() +*/ + +QmlError QmlExpression::error() const +{ + Q_D(const QmlExpression); + return d->data->error; +} + /*! \internal */ void QmlExpression::__q_notify() { diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h index 96694d6..127d3f3 100644 --- a/src/declarative/qml/qmlexpression.h +++ b/src/declarative/qml/qmlexpression.h @@ -44,6 +44,7 @@ #include <QtCore/qobject.h> #include <QtCore/qvariant.h> +#include <QtDeclarative/qmlerror.h> QT_BEGIN_HEADER @@ -82,6 +83,10 @@ public: QObject *scopeObject() const; + bool hasError() const; + void clearError(); + QmlError error() const; + public Q_SLOTS: QVariant value(bool *isUndefined = 0); diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 3ec8d1c..4e13de3 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -83,7 +83,7 @@ class QmlExpressionData : public QmlAbstractExpression, public QmlRefCount { public: QmlExpressionData(); - ~QmlExpressionData(); + virtual ~QmlExpressionData(); QmlExpressionPrivate *q; @@ -92,6 +92,8 @@ public: bool expressionRewritten:1; QScriptValue expressionFunction; + QmlError error; + QmlBasicScript sse; QObject *me; bool trackChange; @@ -151,7 +153,7 @@ public: return static_cast<QmlExpressionPrivate *>(QObjectPrivate::get(expr)); } - static void printException(QScriptEngine *); + static void exceptionToError(QScriptEngine *, QmlError &); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlwatcher.cpp b/src/declarative/qml/qmlwatcher.cpp index ca99472..8cd51e0 100644 --- a/src/declarative/qml/qmlwatcher.cpp +++ b/src/declarative/qml/qmlwatcher.cpp @@ -112,7 +112,7 @@ void QmlWatchProxy::notifyValueChanged() else v = m_property.read(m_object); - emit m_watch->propertyChanged(m_id, m_debugId, QByteArray(m_property.name()), v); + emit m_watch->propertyChanged(m_id, m_debugId, m_property, v); } diff --git a/src/declarative/qml/qmlwatcher_p.h b/src/declarative/qml/qmlwatcher_p.h index 99cae88..0bfcd71 100644 --- a/src/declarative/qml/qmlwatcher_p.h +++ b/src/declarative/qml/qmlwatcher_p.h @@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE class QmlWatchProxy; class QmlExpression; class QmlContext; +class QMetaProperty; class QmlWatcher : public QObject { @@ -79,7 +80,7 @@ public: void removeWatch(int id); Q_SIGNALS: - void propertyChanged(int id, int objectId, const QByteArray &property, const QVariant &value); + void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); private: friend class QmlWatchProxy; diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp index 7ccccec..9c9fa6a 100644 --- a/src/declarative/util/qmllistmodel.cpp +++ b/src/declarative/util/qmllistmodel.cpp @@ -809,6 +809,12 @@ void QmlListModelParser::setCustomData(QObject *obj, const QByteArray &d) QML_DEFINE_CUSTOM_TYPE(Qt, 4,6, (QT_VERSION&0x00ff00)>>8, ListModel, QmlListModel, QmlListModelParser) +/*! + \qmlclass ListElement + \brief The ListElement element defines a data item in a ListModel. + + \sa ListModel +*/ // ### FIXME class QmlListElement : public QObject { diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index 7e4e992..425480c 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -134,7 +134,7 @@ QmlStateOperation::QmlStateOperation(QObjectPrivate &dd, QObject *parent) inadvisible. Not only would this have the same effect as going directly to the second state it may cause the program to crash. - \sa {states-transitions}{States and Transitions} + \sa {qmlstates}{States}, {state-transitions}{Transitions} */ /*! diff --git a/src/declarative/util/qmltransition.cpp b/src/declarative/util/qmltransition.cpp index 66275d9..97a3b74 100644 --- a/src/declarative/util/qmltransition.cpp +++ b/src/declarative/util/qmltransition.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE \qmlclass Transition QmlTransition \brief The Transition element defines animated transitions that occur on state changes. - \sa {states-transitions}{States and Transitions} + \sa {qmlstates}{States}, {state-transitions}{Transitions} */ /*! diff --git a/src/declarative/util/qmlview.cpp b/src/declarative/util/qmlview.cpp index f91d0db..329a9b2 100644 --- a/src/declarative/util/qmlview.cpp +++ b/src/declarative/util/qmlview.cpp @@ -386,7 +386,7 @@ void QmlView::continueExecute() */ /*! \fn void QmlView::initialSize(QSize size) - This signal is emitted when the initial size of the root item is known. + This signal is emitted when the initial \a size of the root item is known. */ /*! \fn void QmlView::errors(const QList<QmlError> &errors) |