diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2009-11-03 06:48:56 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2009-11-03 06:48:56 (GMT) |
commit | ee259b6c04cf4296f45eed31c4d3c5c195fc0924 (patch) | |
tree | 67645a557da11167e225704740e7a8aa928b5ee7 | |
parent | 79d35acae62bf28c37022b763b04e94f5e67bf6f (diff) | |
parent | 7bc853890bbd8653c3d058d50811ae6dfaad1fd1 (diff) | |
download | Qt-ee259b6c04cf4296f45eed31c4d3c5c195fc0924.zip Qt-ee259b6c04cf4296f45eed31c4d3c5c195fc0924.tar.gz Qt-ee259b6c04cf4296f45eed31c4d3c5c195fc0924.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
35 files changed, 1547 insertions, 110 deletions
diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index 0eda95e..69535ce 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -60,9 +60,10 @@ The following table lists the QML elements provided by the Qt Declarative module \list \o \l State \o \l PropertyChanges -\o \l ParentChange -\o \l StateChangeScript -\o \l AnchorChanges +\o \l StateGroup +\o \l ParentChange (Item-specific) +\o \l StateChangeScript (Item-specific) +\o \l AnchorChanges (Item-specific) \endlist \o diff --git a/examples/declarative/fonts/banner.qml b/examples/declarative/fonts/banner.qml new file mode 100644 index 0000000..ece481b --- /dev/null +++ b/examples/declarative/fonts/banner.qml @@ -0,0 +1,18 @@ +import Qt 4.6 + +Rectangle { + id: screen + width: 640; height: 320; color: "steelblue" + + property int pixelSize: screen.height * 1.25 + property color textColor: "lightsteelblue" + property string text: "Hello world! " + + Row { + y: -screen.height / 4.5 + x: NumberAnimation { from: 0; to: -text.width; duration: 6000; running: true; repeat: true } + Text { id: text; font.pixelSize: screen.pixelSize; color: screen.textColor; text: screen.text } + Text { font.pixelSize: screen.pixelSize; color: screen.textColor; text: screen.text } + Text { font.pixelSize: screen.pixelSize; color: screen.textColor; text: screen.text } + } +} diff --git a/examples/declarative/fonts/fonts.qml b/examples/declarative/fonts/fonts.qml index e68bdb6..80d82ad 100644 --- a/examples/declarative/fonts/fonts.qml +++ b/examples/declarative/fonts/fonts.qml @@ -1,12 +1,10 @@ import Qt 4.6 Rectangle { - property string myText: "Lorem ipsum dolor sit amet, consectetur adipisicing elit" + property string myText: "The quick brown fox jumps over the lazy dog." - width: 800; height: 600 - color: palette.base - - SystemPalette { id: palette; colorGroup: Qt.Active } + width: 800; height: 480 + color: "steelblue" FontLoader { id: fixedFont; name: "Courier" } @@ -17,28 +15,36 @@ Rectangle { FontLoader { id: webFont2; source: "http://wrong.address.org" } Column { - anchors.fill: parent + anchors.fill: parent; spacing: 10 anchors.leftMargin: 10; anchors.rightMargin: 10 Text { - text: myText - color: palette.windowText + text: myText; color: "lightsteelblue" width: parent.width; elide: Text.ElideRight - font.family: "Times" - font.pointSize: 32 + font.family: "Times"; font.pointSize: 36 } Text { - text: myText - color: palette.windowText - width: parent.width; elide: Text.ElideRight - font.family: fixedFont.name - font.pointSize: 32 + text: myText; color: "lightsteelblue" + width: parent.width; elide: Text.ElideLeft + font.family: "Times"; font.pointSize: 36 + font.capitalization: "AllUppercase" + } + Text { + text: myText; color: "lightsteelblue" + width: parent.width; elide: Text.ElideMiddle + font.family: fixedFont.name; font.pointSize: 36; font.weight: "Bold" + font.capitalization: "AllLowercase" } Text { - text: myText - color: palette.windowText + text: myText; color: "lightsteelblue" width: parent.width; elide: Text.ElideRight - font.family: localFont.name - font.pointSize: 32 + font.family: fixedFont.name; font.pointSize: 36; font.italic: true + font.capitalization: "SmallCaps" + } + Text { + text: myText; color: "lightsteelblue" + width: parent.width; elide: Text.ElideLeft + font.family: localFont.name; font.pointSize: 36 + font.capitalization: "Capitalize" } Text { text: { @@ -46,10 +52,9 @@ Rectangle { else if (webFont.status == 2) "Loading..." else if (webFont.status == 3) "Error loading font" } - color: palette.windowText - width: parent.width; elide: Text.ElideRight - font.family: webFont.name - font.pointSize: 32 + color: "lightsteelblue" + width: parent.width; elide: Text.ElideMiddle + font.family: webFont.name; font.pointSize: 36 } Text { text: { @@ -57,10 +62,9 @@ Rectangle { else if (webFont2.status == 2) "Loading..." else if (webFont2.status == 3) "Error loading font" } - color: palette.windowText + color: "lightsteelblue" width: parent.width; elide: Text.ElideRight - font.family: webFont2.name - font.pointSize: 32 + font.family: webFont2.name; font.pointSize: 36 } } } diff --git a/examples/declarative/fonts/hello.qml b/examples/declarative/fonts/hello.qml new file mode 100644 index 0000000..6aef3e6 --- /dev/null +++ b/examples/declarative/fonts/hello.qml @@ -0,0 +1,27 @@ +import Qt 4.6 + +Rectangle { + id: screen; width: 800; height: 480; color: "black" + + Item { + id: container; x: screen.width / 2; y: screen.height / 2 + Text { + id: text; color: "white"; anchors.centerIn: parent + text: "Hello world!"; font.pixelSize: 60 + + font.letterSpacing: SequentialAnimation { + repeat: true; running: true + NumberAnimation { from: 100; to: 300; easing: "easeInQuad"; duration: 3000 } + ScriptAction { script: { + container.y = (screen.height / 4) + (Math.random() * screen.height / 2) + container.x = (screen.width / 4) + (Math.random() * screen.width / 2) + } } + } + opacity: SequentialAnimation { + repeat: true; running: true + NumberAnimation { from: 1; to: 0; duration: 2600 } + PauseAnimation { duration: 400 } + } + } + } +} diff --git a/src/declarative/extra/qmlgraphicsanimatedimageitem.cpp b/src/declarative/extra/qmlgraphicsanimatedimageitem.cpp index 5dbffc0..f3c2058 100644 --- a/src/declarative/extra/qmlgraphicsanimatedimageitem.cpp +++ b/src/declarative/extra/qmlgraphicsanimatedimageitem.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ #include <QMovie> -#include <QtDeclarative/qmlcontext.h> #include <QtDeclarative/qmlengine.h> #include "qmlgraphicsanimatedimageitem_p.h" #include "qmlgraphicsanimatedimageitem_p_p.h" @@ -179,6 +178,14 @@ int QmlGraphicsAnimatedImageItem::frameCount() const return d->_movie->frameCount(); } +static QString toLocalFileOrQrc(const QUrl& url) +{ + QString r = url.toLocalFile(); + if (r.isEmpty() && url.scheme() == QLatin1String("qrc")) + r = QLatin1Char(':') + url.path(); + return r; +} + void QmlGraphicsAnimatedImageItem::setSource(const QUrl &url) { Q_D(QmlGraphicsAnimatedImageItem); @@ -193,15 +200,46 @@ void QmlGraphicsAnimatedImageItem::setSource(const QUrl &url) d->reply = 0; } - d->url = qmlContext(this)->resolvedUrl(url); + d->url = url; if (url.isEmpty()) { delete d->_movie; d->status = Null; } else { +#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML + QString lf = toLocalFileOrQrc(url); + if (!lf.isEmpty()) { + //### should be unified with movieRequestFinished + d->_movie = new QMovie(lf); + if (!d->_movie->isValid()){ + qWarning() << "Error Reading Animated Image File " << d->url; + delete d->_movie; + d->_movie = 0; + return; + } + connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)), + this, SLOT(playingStatusChanged())); + connect(d->_movie, SIGNAL(frameChanged(int)), + this, SLOT(movieUpdate())); + d->_movie->setCacheMode(QMovie::CacheAll); + if(d->playing) + d->_movie->start(); + else + d->_movie->jumpToFrame(0); + if(d->paused) + d->_movie->setPaused(true); + d->setPixmap(d->_movie->currentPixmap()); + d->status = Ready; + d->progress = 1.0; + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(d->progress); + return; + } +#endif d->status = Loading; QNetworkRequest req(d->url); - d->reply = qmlContext(this)->engine()->networkAccessManager()->get(req); + d->reply = qmlEngine(this)->networkAccessManager()->get(req); QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(movieRequestFinished())); } @@ -230,13 +268,13 @@ void QmlGraphicsAnimatedImageItem::movieRequestFinished() d->_movie->jumpToFrame(0); if(d->paused) d->_movie->setPaused(true); - setPixmap(d->_movie->currentPixmap()); + d->setPixmap(d->_movie->currentPixmap()); } void QmlGraphicsAnimatedImageItem::movieUpdate() { Q_D(QmlGraphicsAnimatedImageItem); - setPixmap(d->_movie->currentPixmap()); + d->setPixmap(d->_movie->currentPixmap()); emit frameChanged(); } diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp index 8895977..19c5abc 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp @@ -344,7 +344,7 @@ void QmlGraphicsFlickablePrivate::updateBeginningEnd() QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Flickable,QmlGraphicsFlickable) /*! - \qmlclass Flickable QFxFlickable + \qmlclass Flickable QmlGraphicsFlickable \brief The Flickable item provides a surface that can be "flicked". \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp b/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp index d3ee184..a19e355 100644 --- a/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsfocuspanel.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,FocusPanel,QmlGraphicsFocusPanel) /*! - \qmlclass FocusPanel QFxFocusPanel + \qmlclass FocusPanel QmlGraphicsFocusPanel \brief The FocusPanel item explicitly creates a focus panel. \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp b/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp index cd30b2b..f03e3f1 100644 --- a/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsfocusscope.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,FocusScope,QmlGraphicsFocusScope) /*! - \qmlclass FocusScope QFxFocusScope + \qmlclass FocusScope QmlGraphicsFocusScope \brief The FocusScope object explicitly creates a focus scope. \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp index cadd650..1ee4511 100644 --- a/src/declarative/graphicsitems/qmlgraphicsgridview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsgridview.cpp @@ -658,7 +658,7 @@ void QmlGraphicsGridViewPrivate::updateCurrent(int modelIndex) //---------------------------------------------------------------------------- /*! - \qmlclass GridView QFxGridView + \qmlclass GridView QmlGraphicsGridView \inherits Flickable \brief The GridView item provides a grid view of items provided by a model. diff --git a/src/declarative/graphicsitems/qmlgraphicsimage.cpp b/src/declarative/graphicsitems/qmlgraphicsimage.cpp index fd220a3..938fe2a 100644 --- a/src/declarative/graphicsitems/qmlgraphicsimage.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsimage.cpp @@ -152,12 +152,18 @@ void QmlGraphicsImage::setPixmap(const QPixmap &pix) Q_D(QmlGraphicsImage); if (!d->url.isEmpty()) return; - d->pix = pix; + d->setPixmap(pix); +} + +void QmlGraphicsImagePrivate::setPixmap(const QPixmap &pixmap) +{ + Q_Q(QmlGraphicsImage); + pix = pixmap; - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + q->setImplicitWidth(pix.width()); + q->setImplicitHeight(pix.height()); - update(); + q->update(); } /*! diff --git a/src/declarative/graphicsitems/qmlgraphicsimage_p_p.h b/src/declarative/graphicsitems/qmlgraphicsimage_p_p.h index 62a4d1e..f6b4e51 100644 --- a/src/declarative/graphicsitems/qmlgraphicsimage_p_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsimage_p_p.h @@ -69,7 +69,7 @@ public: } QmlGraphicsImage::FillMode fillMode; - + void setPixmap(const QPixmap &pix); }; QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.cpp b/src/declarative/graphicsitems/qmlgraphicsitem.cpp index 0e741c4..5083f43 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitem.cpp @@ -2918,5 +2918,5 @@ QML_DECLARE_TYPE(QmlGraphicsKeysAttached) QML_DECLARE_TYPEINFO(QmlGraphicsKeysAttached, QML_HAS_ATTACHED_PROPERTIES) QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Keys,QmlGraphicsKeysAttached) QML_DECLARE_TYPE(QmlGraphicsKeyNavigationAttached) +QML_DECLARE_TYPEINFO(QmlGraphicsKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES) QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,KeyNavigation,QmlGraphicsKeyNavigationAttached) - diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index cf399f9..a393cb1 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -954,7 +954,7 @@ void QmlGraphicsListViewPrivate::flickY(qreal velocity) //---------------------------------------------------------------------------- /*! - \qmlclass ListView QFxListView + \qmlclass ListView QmlGraphicsListView \inherits Flickable \brief The ListView item provides a list view of items provided by a model. diff --git a/src/declarative/graphicsitems/qmlgraphicsloader.cpp b/src/declarative/graphicsitems/qmlgraphicsloader.cpp index 65753d8..4d463ab 100644 --- a/src/declarative/graphicsitems/qmlgraphicsloader.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsloader.cpp @@ -56,7 +56,7 @@ QmlGraphicsLoaderPrivate::~QmlGraphicsLoaderPrivate() QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Loader,QmlGraphicsLoader) /*! - \qmlclass Loader QFxLoader + \qmlclass Loader QmlGraphicsLoader \inherits Item \brief The Loader item allows dynamically loading an Item-based diff --git a/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp b/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp index 75e31b8..1a57062 100644 --- a/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsmouseregion.cpp @@ -120,7 +120,7 @@ void QmlGraphicsDrag::setYmax(qreal m) } /*! - \qmlclass MouseRegion QFxMouseRegion + \qmlclass MouseRegion QmlGraphicsMouseRegion \brief The MouseRegion item enables simple mouse handling. \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicspath.cpp b/src/declarative/graphicsitems/qmlgraphicspath.cpp index c0e6caf..ed0dfaa 100644 --- a/src/declarative/graphicsitems/qmlgraphicspath.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspath.cpp @@ -57,7 +57,7 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,PathQuad,QmlGraphicsPathQuad) QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,PathCubic,QmlGraphicsPathCubic) /*! - \qmlclass PathElement QFxPathElement + \qmlclass PathElement QmlGraphicsPathElement \brief PathElement is the base path type. This type is the base for all path types. It cannot @@ -464,7 +464,7 @@ void QmlGraphicsCurve::setY(qreal y) /****************************************************************************/ /*! - \qmlclass PathAttribute QFxPathAttribute + \qmlclass PathAttribute QmlGraphicsPathAttribute \brief The PathAttribute allows setting an attribute at a given position in a Path. The PathAttribute object allows attibutes consisting of a name and @@ -543,7 +543,7 @@ void QmlGraphicsPathAttribute::setValue(qreal value) /****************************************************************************/ /*! - \qmlclass PathLine QFxPathLine + \qmlclass PathLine QmlGraphicsPathLine \brief The PathLine defines a straight line. The example below creates a path consisting of a straight line from @@ -583,7 +583,7 @@ void QmlGraphicsPathLine::addToPath(QPainterPath &path) /****************************************************************************/ /*! - \qmlclass PathQuad QFxPathQuad + \qmlclass PathQuad QmlGraphicsPathQuad \brief The PathQuad defines a quadratic Bezier curve with a control point. The following QML produces the path shown below: @@ -667,7 +667,7 @@ void QmlGraphicsPathQuad::addToPath(QPainterPath &path) /****************************************************************************/ /*! - \qmlclass PathCubic QFxPathCubic + \qmlclass PathCubic QmlGraphicsPathCubic \brief The PathCubic defines a cubic Bezier curve with two control points. The following QML produces the path shown below: @@ -777,7 +777,7 @@ void QmlGraphicsPathCubic::addToPath(QPainterPath &path) /****************************************************************************/ /*! - \qmlclass PathPercent QFxPathPercent + \qmlclass PathPercent QmlGraphicsPathPercent \brief The PathPercent manipulates the way a path is interpreted. The examples below show the normal distrubution of items along a path diff --git a/src/declarative/graphicsitems/qmlgraphicspathview.cpp b/src/declarative/graphicsitems/qmlgraphicspathview.cpp index 52d2fa9..d2a9be1 100644 --- a/src/declarative/graphicsitems/qmlgraphicspathview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspathview.cpp @@ -97,7 +97,7 @@ private: */ /*! - \qmlclass PathView QFxPathView + \qmlclass PathView QmlGraphicsPathView \brief The PathView element lays out model-provided items on a path. \inherits Item diff --git a/src/declarative/graphicsitems/qmlgraphicspositioners.cpp b/src/declarative/graphicsitems/qmlgraphicspositioners.cpp index ba696e7..f599025 100644 --- a/src/declarative/graphicsitems/qmlgraphicspositioners.cpp +++ b/src/declarative/graphicsitems/qmlgraphicspositioners.cpp @@ -333,7 +333,7 @@ void QmlGraphicsBasePositioner::applyRemove(const QList<QPair<QString, QVariant> QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Column,QmlGraphicsColumn) /*! - \qmlclass Column QFxColumn + \qmlclass Column QmlGraphicsColumn \brief The Column item lines up its children vertically. \inherits Item @@ -481,6 +481,11 @@ QmlGraphicsColumn::QmlGraphicsColumn(QmlGraphicsItem *parent) { } +inline bool isInvisible(QmlGraphicsItem *child) +{ + return child->opacity() == 0.0 || !child->isVisible() || !child->width() || !child->height(); +} + void QmlGraphicsColumn::doPositioning() { int voffset = 0; @@ -495,7 +500,7 @@ void QmlGraphicsColumn::doPositioning() QList<QGraphicsItem *> children = childItems(); for (int ii = 0; ii < children.count(); ++ii) { QmlGraphicsItem *child = qobject_cast<QmlGraphicsItem *>(children.at(ii)); - if (!child || child->opacity() == 0.0) + if (!child || isInvisible(child)) continue; bool needMove = (child->y() != voffset || child->x()); @@ -519,7 +524,7 @@ void QmlGraphicsColumn::doPositioning() QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Row,QmlGraphicsRow) /*! - \qmlclass Row QFxRow + \qmlclass Row QmlGraphicsRow \brief The Row item lines up its children horizontally. \inherits Item @@ -651,7 +656,7 @@ void QmlGraphicsRow::doPositioning() QList<QGraphicsItem *> children = childItems(); for (int ii = 0; ii < children.count(); ++ii) { QmlGraphicsItem *child = qobject_cast<QmlGraphicsItem *>(children.at(ii)); - if (!child || child->opacity() == 0.0) + if (!child || isInvisible(child)) continue; bool needMove = (child->x() != hoffset || child->y()); @@ -668,10 +673,8 @@ void QmlGraphicsRow::doPositioning() child->setX(hoffset); setMovingItem(0); } - if(child->width() && child->height()){//don't advance for invisible children - hoffset += child->width(); - hoffset += spacing(); - } + hoffset += child->width(); + hoffset += spacing(); } } @@ -867,7 +870,7 @@ void QmlGraphicsGrid::doPositioning() if (childIndex == children.count()) continue; QmlGraphicsItem *child = qobject_cast<QmlGraphicsItem *>(children.at(childIndex++)); - if (!child || child->opacity() == 0.0) + if (!child || isInvisible(child)) continue; if (child->width() > maxColWidth[j]) maxColWidth[j] = child->width(); @@ -888,7 +891,7 @@ void QmlGraphicsGrid::doPositioning() } foreach(QGraphicsItem* schild, children){ QmlGraphicsItem *child = qobject_cast<QmlGraphicsItem *>(schild); - if (!child || child->opacity() == 0.0) + if (!child || isInvisible(child)) continue; bool needMove = (child->x()!=xoffset)||(child->y()!=yoffset); QList<QPair<QString, QVariant> > changes; diff --git a/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp b/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp index ba860e9..646374f 100644 --- a/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsrepeater.cpp @@ -59,7 +59,7 @@ QmlGraphicsRepeaterPrivate::~QmlGraphicsRepeaterPrivate() QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Repeater,QmlGraphicsRepeater) /*! - \qmlclass Repeater QFxRepeater + \qmlclass Repeater QmlGraphicsRepeater \inherits Item \brief The Repeater item allows you to repeat a component based on a model. diff --git a/src/declarative/graphicsitems/qmlgraphicstextedit.cpp b/src/declarative/graphicsitems/qmlgraphicstextedit.cpp index 0c81dca..13df329 100644 --- a/src/declarative/graphicsitems/qmlgraphicstextedit.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstextedit.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,TextEdit,QmlGraphicsTextEdit) /*! - \qmlclass TextEdit QFxTextEdit + \qmlclass TextEdit QmlGraphicsTextEdit \brief The TextEdit item allows you to add editable formatted text to a scene. It can display both plain and rich text. For example: diff --git a/src/declarative/graphicsitems/qmlgraphicstextinput.cpp b/src/declarative/graphicsitems/qmlgraphicstextinput.cpp index 44ccda1..9a4f627 100644 --- a/src/declarative/graphicsitems/qmlgraphicstextinput.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstextinput.cpp @@ -54,7 +54,7 @@ QML_DEFINE_NOCREATE_TYPE(QValidator); QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,QIntValidator,QIntValidator); /*! - \qmlclass TextInput QFxTextInput + \qmlclass TextInput QmlGraphicsTextInput The TextInput item allows you to add an editable line of text to a scene. TextInput can only display a single line of text, and can only display diff --git a/src/declarative/graphicsitems/qmlgraphicswebview.cpp b/src/declarative/graphicsitems/qmlgraphicswebview.cpp index c6ab4c7..d1da0f2 100644 --- a/src/declarative/graphicsitems/qmlgraphicswebview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicswebview.cpp @@ -208,7 +208,7 @@ public: }; /*! - \qmlclass WebView QFxWebView + \qmlclass WebView QmlGraphicsWebView \brief The WebView item allows you to add web content to a canvas. \inherits Item diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index d37d959..f8e685a 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -88,18 +88,6 @@ void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject, scripts.append(scope); } -void QmlContextPrivate::dump() -{ - dump(0); -} - -void QmlContextPrivate::dump(int depth) -{ - QByteArray ba(depth * 4, ' '); - if (parent) - parent->d_func()->dump(depth + 1); -} - void QmlContextPrivate::destroyed(ContextGuard *guard) { Q_Q(QmlContext); @@ -382,8 +370,8 @@ void QmlContext::setContextProperty(const QString &name, const QVariant &value) if (d->notifyIndex == -1) d->notifyIndex = this->metaObject()->methodCount(); - if (QmlMetaType::isObject(value.userType())) { - QObject *o = QmlMetaType::toQObject(value); + if (d->engine && QmlEnginePrivate::get(d->engine)->isObject(value.userType())) { + QObject *o = *(QObject **)value.constData(); setContextProperty(name, o); } else { diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index cc8fcc6..7f9be0f 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -101,9 +101,6 @@ public: void init(); - void dump(); - void dump(int depth); - void invalidateEngines(); void refreshExpressions(); QSet<QmlContext *> childContexts; diff --git a/src/declarative/qml/qmlvaluetype.cpp b/src/declarative/qml/qmlvaluetype.cpp index 1713205..859a93a 100644 --- a/src/declarative/qml/qmlvaluetype.cpp +++ b/src/declarative/qml/qmlvaluetype.cpp @@ -521,6 +521,16 @@ void QmlFontValueType::setBold(bool b) font.setBold(b); } +QmlFontValueType::FontWeight QmlFontValueType::weight() const +{ + return (QmlFontValueType::FontWeight)font.weight(); +} + +void QmlFontValueType::setWeight(QmlFontValueType::FontWeight w) +{ + font.setWeight((QFont::Weight)w); +} + bool QmlFontValueType::italic() const { return font.italic(); @@ -541,6 +551,26 @@ void QmlFontValueType::setUnderline(bool b) font.setUnderline(b); } +bool QmlFontValueType::overline() const +{ + return font.overline(); +} + +void QmlFontValueType::setOverline(bool b) +{ + font.setOverline(b); +} + +bool QmlFontValueType::strikeout() const +{ + return font.strikeOut(); +} + +void QmlFontValueType::setStrikeout(bool b) +{ + font.setStrikeOut(b); +} + qreal QmlFontValueType::pointSize() const { return font.pointSizeF(); @@ -566,4 +596,34 @@ void QmlFontValueType::setPixelSize(int size) hasPixelSize = true; } +QmlFontValueType::Capitalization QmlFontValueType::capitalization() const +{ + return (QmlFontValueType::Capitalization)font.capitalization(); +} + +void QmlFontValueType::setCapitalization(QmlFontValueType::Capitalization c) +{ + font.setCapitalization((QFont::Capitalization)c); +} + +qreal QmlFontValueType::letterSpacing() const +{ + return font.letterSpacing(); +} + +void QmlFontValueType::setLetterSpacing(qreal size) +{ + font.setLetterSpacing(QFont::PercentageSpacing, size); +} + +qreal QmlFontValueType::wordSpacing() const +{ + return font.wordSpacing(); +} + +void QmlFontValueType::setWordSpacing(qreal size) +{ + font.setWordSpacing(size); +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvaluetype_p.h b/src/declarative/qml/qmlvaluetype_p.h index 9842c02..0af3813 100644 --- a/src/declarative/qml/qmlvaluetype_p.h +++ b/src/declarative/qml/qmlvaluetype_p.h @@ -258,13 +258,34 @@ private: class QmlFontValueType : public QmlValueType { Q_OBJECT + Q_ENUMS(FontWeight) + Q_ENUMS(Capitalization) + Q_PROPERTY(QString family READ family WRITE setFamily) Q_PROPERTY(bool bold READ bold WRITE setBold) + Q_PROPERTY(FontWeight weight READ weight WRITE setWeight) Q_PROPERTY(bool italic READ italic WRITE setItalic) Q_PROPERTY(bool underline READ underline WRITE setUnderline) + Q_PROPERTY(bool overline READ overline WRITE setOverline) + Q_PROPERTY(bool strikeout READ strikeout WRITE setStrikeout) Q_PROPERTY(qreal pointSize READ pointSize WRITE setPointSize) Q_PROPERTY(int pixelSize READ pixelSize WRITE setPixelSize) + Q_PROPERTY(Capitalization capitalization READ capitalization WRITE setCapitalization) + Q_PROPERTY(qreal letterSpacing READ letterSpacing WRITE setLetterSpacing) + Q_PROPERTY(qreal wordSpacing READ wordSpacing WRITE setWordSpacing) + public: + enum FontWeight { Light = QFont::Light, + Normal = QFont::Normal, + DemiBold = QFont::DemiBold, + Bold = QFont::Bold, + Black = QFont::Black }; + enum Capitalization { MixedCase = QFont::MixedCase, + AllUppercase = QFont::AllUppercase, + AllLowercase = QFont::AllLowercase, + SmallCaps = QFont::SmallCaps, + Capitalize = QFont::Capitalize }; + QmlFontValueType(QObject *parent = 0); virtual void read(QObject *, int); @@ -278,18 +299,36 @@ public: bool bold() const; void setBold(bool b); + FontWeight weight() const; + void setWeight(FontWeight); + bool italic() const; void setItalic(bool b); bool underline() const; void setUnderline(bool b); + bool overline() const; + void setOverline(bool b); + + bool strikeout() const; + void setStrikeout(bool b); + qreal pointSize() const; void setPointSize(qreal size); int pixelSize() const; void setPixelSize(int size); + Capitalization capitalization() const; + void setCapitalization(Capitalization); + + qreal letterSpacing() const; + void setLetterSpacing(qreal spacing); + + qreal wordSpacing() const; + void setWordSpacing(qreal spacing); + private: QFont font; bool hasPixelSize; diff --git a/src/declarative/util/qmlstategroup.cpp b/src/declarative/util/qmlstategroup.cpp index f518ea5..2eb9dca 100644 --- a/src/declarative/util/qmlstategroup.cpp +++ b/src/declarative/util/qmlstategroup.cpp @@ -84,6 +84,34 @@ public: void updateAutoState(); }; +/*! + \qmlclass StateGroup QmlStateGroup + \brief The StateGroup element provides state support for non-Item elements. + + Item (and all dervied elements) provides built in support for states and transitions + via its state, states and transitions properties. StateGroup provides an easy way to + use this support in other (non-Item-derived) elements. + + \qml + MyCustomObject { + StateGroup { + id: myStateGroup + states: State { + name: "state1" + ... + } + transitions: Transition { + ... + } + } + + onSomethingHappened: myStateGroup.state = "state1"; + } + \endqml + + \sa {qmlstate}{States} and {state-transitions}{Transitions} +*/ + QmlStateGroup::QmlStateGroup(QObject *parent) : QObject(*(new QmlStateGroupPrivate(this)), parent) { @@ -99,18 +127,75 @@ QList<QmlState *> QmlStateGroup::states() const return d->states; } +/*! + \qmlproperty list<State> StateGroup::states + This property holds a list of states defined by the state group. + + \qml + StateGroup { + states: [ + State { ... }, + State { ... } + ... + ] + } + \endqml + + \sa {qmlstate}{States} +*/ QmlList<QmlState *>* QmlStateGroup::statesProperty() { Q_D(QmlStateGroup); return &(d->states); } +/*! + \qmlproperty list<Transition> StateGroup::transitions + This property holds a list of transitions defined by the state group. + + \qml + StateGroup { + transitions: [ + Transition { ... }, + Transition { ... } + ... + ] + } + \endqml + + \sa {state-transitions}{Transitions} +*/ QmlList<QmlTransition *>* QmlStateGroup::transitionsProperty() { Q_D(QmlStateGroup); return &(d->transitions); } +/*! + \qmlproperty string StateGroup::state + + This property holds the name of the current state of the state group. + + This property is often used in scripts to change between states. For + example: + + \qml + Script { + function toggle() { + if (button.state == 'On') + button.state = 'Off'; + else + button.state = 'On'; + } + } + \endqml + + If the state group is in its base state (i.e. no explicit state has been + set), \c state will be a blank string. Likewise, you can return a + state group to its base state by setting its current state to \c ''. + + \sa {qmlstates}{States} +*/ QString QmlStateGroup::state() const { Q_D(const QmlStateGroup); diff --git a/src/declarative/util/qmltimer.cpp b/src/declarative/util/qmltimer.cpp index 268d5ec..2e844be 100644 --- a/src/declarative/util/qmltimer.cpp +++ b/src/declarative/util/qmltimer.cpp @@ -57,12 +57,12 @@ public: : interval(1000), running(false), repeating(false), triggeredOnStart(false) , classBegun(false), componentComplete(false) {} int interval; - bool running; - bool repeating; - bool triggeredOnStart; QPauseAnimation pause; - bool classBegun; - bool componentComplete; + bool running : 1; + bool repeating : 1; + bool triggeredOnStart : 1; + bool classBegun : 1; + bool componentComplete : 1; }; /*! @@ -82,6 +82,9 @@ public: } \endqml + QmlTimer is synchronized with the animation timer. Since the animation + timer is usually set to 60fps, the resolution of QmlTimer will be + at best 16ms. */ QmlTimer::QmlTimer(QObject *parent) @@ -89,7 +92,6 @@ QmlTimer::QmlTimer(QObject *parent) { Q_D(QmlTimer); connect(&d->pause, SIGNAL(currentLoopChanged(int)), this, SLOT(ticked())); - connect(&d->pause, SIGNAL(finished()), this, SLOT(ticked())); connect(&d->pause, SIGNAL(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State)) , this, SLOT(stateChanged(QAbstractAnimation::State,QAbstractAnimation::State))); d->pause.setLoopCount(1); @@ -259,7 +261,9 @@ void QmlTimer::componentComplete() */ void QmlTimer::ticked() { - emit triggered(); + Q_D(QmlTimer); + if (d->running) + emit triggered(); } void QmlTimer::stateChanged(QAbstractAnimation::State, QAbstractAnimation::State state) @@ -267,6 +271,7 @@ void QmlTimer::stateChanged(QAbstractAnimation::State, QAbstractAnimation::State Q_D(QmlTimer); if (d->running && state != QAbstractAnimation::Running) { d->running = false; + emit triggered(); emit runningChanged(); } } diff --git a/tests/auto/declarative/animatedimage/tst_animatedimage.cpp b/tests/auto/declarative/animatedimage/tst_animatedimage.cpp index f6141cb..6ae2112 100644 --- a/tests/auto/declarative/animatedimage/tst_animatedimage.cpp +++ b/tests/auto/declarative/animatedimage/tst_animatedimage.cpp @@ -61,34 +61,40 @@ private slots: void tst_animatedimage::play() { - QmlGraphicsAnimatedImageItem anim; - anim.setSource(QUrl("file://" SRCDIR "/data/stickman.gif")); - QVERIFY(anim.isPlaying()); + QmlEngine engine; + QmlComponent component(&engine, QUrl("file://" SRCDIR "/data/stickman.qml")); + QmlGraphicsAnimatedImageItem *anim = qobject_cast<QmlGraphicsAnimatedImageItem *>(component.create()); + QVERIFY(anim); + QVERIFY(anim->isPlaying()); } void tst_animatedimage::pause() { - QmlGraphicsAnimatedImageItem anim; - anim.setSource(QUrl("file://" SRCDIR "/data/stickman.gif")); - anim.setPaused(true); - QVERIFY(!anim.isPlaying()); + QmlEngine engine; + QmlComponent component(&engine, QUrl("file://" SRCDIR "/data/stickmanpause.qml")); + QmlGraphicsAnimatedImageItem *anim = qobject_cast<QmlGraphicsAnimatedImageItem *>(component.create()); + QVERIFY(anim); + QVERIFY(anim->isPlaying()); + QVERIFY(anim->isPaused()); } void tst_animatedimage::setFrame() { - QmlGraphicsAnimatedImageItem anim; - anim.setSource(QUrl("file://" SRCDIR "/data/stickman.gif")); - anim.setPaused(true); - QVERIFY(!anim.isPlaying()); - anim.setCurrentFrame(2); - QCOMPARE(anim.currentFrame(), 2); + QmlEngine engine; + QmlComponent component(&engine, QUrl("file://" SRCDIR "/data/stickmanpause.qml")); + QmlGraphicsAnimatedImageItem *anim = qobject_cast<QmlGraphicsAnimatedImageItem *>(component.create()); + QVERIFY(anim); + QVERIFY(anim->isPlaying()); + QCOMPARE(anim->currentFrame(), 2); } void tst_animatedimage::frameCount() { - QmlGraphicsAnimatedImageItem anim; - anim.setSource(QUrl("file://" SRCDIR "/data/stickman.gif")); - QCOMPARE(anim.frameCount(), 299); + QmlEngine engine; + QmlComponent component(&engine, QUrl("file://" SRCDIR "/data/stickman.qml")); + QmlGraphicsAnimatedImageItem *anim = qobject_cast<QmlGraphicsAnimatedImageItem *>(component.create()); + QVERIFY(anim); + QCOMPARE(anim->frameCount(), 299); } QTEST_MAIN(tst_animatedimage) diff --git a/tests/auto/declarative/behaviors/data/simple.qml b/tests/auto/declarative/behaviors/data/simple.qml index a715f7b..37c3915 100644 --- a/tests/auto/declarative/behaviors/data/simple.qml +++ b/tests/auto/declarative/behaviors/data/simple.qml @@ -6,7 +6,10 @@ Rectangle { id: rect objectName: "MyRect" width: 100; height: 100; color: "green" - x: Behavior { NumberAnimation { duration: 200; } } + x: Behavior { + objectName: "MyBehavior"; + NumberAnimation { duration: 200; } + } } MouseRegion { id: clicker diff --git a/tests/auto/declarative/behaviors/tst_behaviors.cpp b/tests/auto/declarative/behaviors/tst_behaviors.cpp index 9803a9d..29c631d 100644 --- a/tests/auto/declarative/behaviors/tst_behaviors.cpp +++ b/tests/auto/declarative/behaviors/tst_behaviors.cpp @@ -43,6 +43,7 @@ #include <QtDeclarative/qmlcomponent.h> #include <QtDeclarative/qmlview.h> #include <private/qmlgraphicsrectangle_p.h> +#include <private/qmlbehavior_p.h> #include <private/qmlanimation_p.h> class tst_behaviors : public QObject @@ -60,6 +61,9 @@ private slots: void replaceBinding(); //void transitionOverrides(); void group(); + void emptyBehavior(); + void nonSelectingBehavior(); + void reassignedAnimation(); }; void tst_behaviors::simpleBehavior() @@ -68,6 +72,7 @@ void tst_behaviors::simpleBehavior() QmlComponent c(&engine, QUrl("file://" SRCDIR "/data/simple.qml")); QmlGraphicsRectangle *rect = qobject_cast<QmlGraphicsRectangle*>(c.create()); QVERIFY(rect); + QVERIFY(qobject_cast<QmlBehavior*>(rect->findChild<QmlBehavior*>("MyBehavior"))->animation()); rect->setState("moved"); QTest::qWait(100); @@ -189,6 +194,44 @@ void tst_behaviors::group() } } +void tst_behaviors::emptyBehavior() +{ + QmlEngine engine; + QmlComponent c(&engine, QUrl("file://" SRCDIR "/data/empty.qml")); + QmlGraphicsRectangle *rect = qobject_cast<QmlGraphicsRectangle*>(c.create()); + QVERIFY(rect); + + rect->setState("moved"); + qreal x = qobject_cast<QmlGraphicsRectangle*>(rect->findChild<QmlGraphicsRectangle*>("MyRect"))->x(); + QCOMPARE(x, qreal(200)); //should change immediately +} + +void tst_behaviors::nonSelectingBehavior() +{ + QmlEngine engine; + QmlComponent c(&engine, QUrl("file://" SRCDIR "/data/nonSelecting.qml")); + QmlGraphicsRectangle *rect = qobject_cast<QmlGraphicsRectangle*>(c.create()); + QVERIFY(rect); + + rect->setState("moved"); + qreal x = qobject_cast<QmlGraphicsRectangle*>(rect->findChild<QmlGraphicsRectangle*>("MyRect"))->x(); + QCOMPARE(x, qreal(200)); //should change immediately +} + +void tst_behaviors::reassignedAnimation() +{ + QmlEngine engine; + QmlComponent c(&engine, QUrl("file://" SRCDIR "/data/reassignedAnimation.qml")); + QTest::ignoreMessage(QtWarningMsg, "QML QmlBehavior (file://" SRCDIR "/data/reassignedAnimation.qml:9:12) Can't change the animation assigned to a Behavior."); + QmlGraphicsRectangle *rect = qobject_cast<QmlGraphicsRectangle*>(c.create()); + QVERIFY(rect); + + rect->setState("moved"); + QTest::qWait(200 + 100); + qreal x = qobject_cast<QmlGraphicsRectangle*>(rect->findChild<QmlGraphicsRectangle*>("MyRect"))->x(); + QCOMPARE(x, qreal(200)); //i.e. the right behavior has been triggered +} + QTEST_MAIN(tst_behaviors) #include "tst_behaviors.moc" diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 40cdb58..0d55391 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -15,6 +15,7 @@ SUBDIRS += anchors \ qfxtextedit \ qfxtextinput \ qfxwebview \ + qmetaobjectbuilder \ qmlcontext \ qmldom \ qmlecmascript \ diff --git a/tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro b/tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro new file mode 100644 index 0000000..94ffe4b --- /dev/null +++ b/tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative +macx:CONFIG -= app_bundle + +SOURCES += \ + tst_qmetaobjectbuilder.cpp + diff --git a/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp new file mode 100644 index 0000000..9beec17 --- /dev/null +++ b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp @@ -0,0 +1,1059 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> +#include <QtCore/qlocale.h> +#include <private/qmetaobjectbuilder_p.h> + +class tst_QMetaObjectBuilder : public QObject +{ + Q_OBJECT +public: + tst_QMetaObjectBuilder() {} + ~tst_QMetaObjectBuilder() {} + +private slots: + void mocVersionCheck(); + void create(); + void className(); + void superClass(); + void method(); + void slot(); + void signal(); + void constructor(); + void property(); + void notifySignal(); + void enumerator(); + void classInfo(); + void relatedMetaObject(); + void staticMetacall(); + void copyMetaObject(); + void serialize(); + +private: + static bool checkForSideEffects + (const QMetaObjectBuilder& builder, + QMetaObjectBuilder::AddMembers members); + static bool sameMetaObject + (const QMetaObject *meta1, const QMetaObject *meta2); +}; + +void tst_QMetaObjectBuilder::mocVersionCheck() +{ + // This test will fail when the moc version number is changed. + // It is intended as a reminder to also update QMetaObjectBuilder + // whenenver moc changes. Once QMetaObjectBuilder has been + // updated, this test can be changed to check for the next version. + QCOMPARE(int(QObject::staticMetaObject.d.data[0]), 4); + QCOMPARE(int(staticMetaObject.d.data[0]), 4); +} + +void tst_QMetaObjectBuilder::create() +{ + QMetaObjectBuilder builder; + QVERIFY(builder.className().isEmpty()); + QVERIFY(builder.superClass() == &QObject::staticMetaObject); + QCOMPARE(builder.methodCount(), 0); + QCOMPARE(builder.constructorCount(), 0); + QCOMPARE(builder.propertyCount(), 0); + QCOMPARE(builder.enumeratorCount(), 0); + QCOMPARE(builder.classInfoCount(), 0); + QCOMPARE(builder.relatedMetaObjectCount(), 0); + QVERIFY(builder.staticMetacallFunction() == 0); +} + +void tst_QMetaObjectBuilder::className() +{ + QMetaObjectBuilder builder; + + // Change the class name. + builder.setClassName("Foo"); + QCOMPARE(builder.className(), QByteArray("Foo")); + + // Change it again. + builder.setClassName("Bar"); + QCOMPARE(builder.className(), QByteArray("Bar")); + + // Clone the class name off a static QMetaObject. + builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::ClassName); + QCOMPARE(builder.className(), QByteArray("QObject")); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassName)); +} + +void tst_QMetaObjectBuilder::superClass() +{ + QMetaObjectBuilder builder; + + // Change the super class. + builder.setSuperClass(&QObject::staticMetaObject); + QVERIFY(builder.superClass() == &QObject::staticMetaObject); + + // Change it again. + builder.setSuperClass(&staticMetaObject); + QVERIFY(builder.superClass() == &staticMetaObject); + + // Clone the super class off a static QMetaObject. + builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::SuperClass); + QVERIFY(builder.superClass() == 0); + builder.addMetaObject(&staticMetaObject, QMetaObjectBuilder::SuperClass); + QVERIFY(builder.superClass() == staticMetaObject.superClass()); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::SuperClass)); +} + +void tst_QMetaObjectBuilder::method() +{ + QMetaObjectBuilder builder; + + // Add a method and check its attributes. + QMetaMethodBuilder method1 = builder.addMethod("foo(const QString&, int)"); + QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(method1.methodType() == QMetaMethod::Method); + QVERIFY(method1.returnType().isEmpty()); + QVERIFY(method1.parameterNames().isEmpty()); + QVERIFY(method1.tag().isEmpty()); + QVERIFY(method1.access() == QMetaMethod::Public); + QCOMPARE(method1.attributes(), 0); + QCOMPARE(method1.index(), 0); + QCOMPARE(builder.methodCount(), 1); + + // Add another method and check again. + QMetaMethodBuilder method2 = builder.addMethod("bar(QString)"); + QCOMPARE(method2.signature(), QByteArray("bar(QString)")); + QVERIFY(method2.methodType() == QMetaMethod::Method); + QVERIFY(method2.returnType().isEmpty()); + QVERIFY(method2.parameterNames().isEmpty()); + QVERIFY(method2.tag().isEmpty()); + QVERIFY(method2.access() == QMetaMethod::Public); + QCOMPARE(method2.attributes(), 0); + QCOMPARE(method2.index(), 1); + QCOMPARE(builder.methodCount(), 2); + + // Perform index-based lookup. + QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), 0); + QCOMPARE(builder.indexOfMethod("bar(QString)"), 1); + QCOMPARE(builder.indexOfMethod("baz()"), -1); + + // Modify the attributes on method1. + method1.setReturnType("int"); + method1.setParameterNames(QList<QByteArray>() << "a" << "b"); + method1.setTag("tag"); + method1.setAccess(QMetaMethod::Private); + method1.setAttributes(42); + + // Check that method1 is changed, but method2 is not. + QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(method1.methodType() == QMetaMethod::Method); + QCOMPARE(method1.returnType(), QByteArray("int")); + QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b"); + QCOMPARE(method1.tag(), QByteArray("tag")); + QVERIFY(method1.access() == QMetaMethod::Private); + QCOMPARE(method1.attributes(), 42); + QCOMPARE(method1.index(), 0); + QCOMPARE(method2.signature(), QByteArray("bar(QString)")); + QVERIFY(method2.methodType() == QMetaMethod::Method); + QVERIFY(method2.returnType().isEmpty()); + QVERIFY(method2.parameterNames().isEmpty()); + QVERIFY(method2.tag().isEmpty()); + QVERIFY(method2.access() == QMetaMethod::Public); + QCOMPARE(method2.attributes(), 0); + QCOMPARE(method2.index(), 1); + QCOMPARE(builder.methodCount(), 2); + + // Modify the attributes on method2. + method2.setReturnType("QString"); + method2.setParameterNames(QList<QByteArray>() << "c"); + method2.setTag("Q_FOO"); + method2.setAccess(QMetaMethod::Protected); + method2.setAttributes(24); + + // This time check that only method2 changed. + QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(method1.methodType() == QMetaMethod::Method); + QCOMPARE(method1.returnType(), QByteArray("int")); + QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b"); + QCOMPARE(method1.tag(), QByteArray("tag")); + QVERIFY(method1.access() == QMetaMethod::Private); + QCOMPARE(method1.attributes(), 42); + QCOMPARE(method1.index(), 0); + QCOMPARE(method2.signature(), QByteArray("bar(QString)")); + QVERIFY(method2.methodType() == QMetaMethod::Method); + QCOMPARE(method2.returnType(), QByteArray("QString")); + QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c"); + QCOMPARE(method2.tag(), QByteArray("Q_FOO")); + QVERIFY(method2.access() == QMetaMethod::Protected); + QCOMPARE(method2.attributes(), 24); + QCOMPARE(method2.index(), 1); + QCOMPARE(builder.methodCount(), 2); + + // Remove method1 and check that method2 becomes index 0. + builder.removeMethod(0); + QCOMPARE(builder.methodCount(), 1); + method2 = builder.method(0); + QCOMPARE(method2.signature(), QByteArray("bar(QString)")); + QVERIFY(method2.methodType() == QMetaMethod::Method); + QCOMPARE(method2.returnType(), QByteArray("QString")); + QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c"); + QCOMPARE(method2.tag(), QByteArray("Q_FOO")); + QVERIFY(method2.access() == QMetaMethod::Protected); + QCOMPARE(method2.attributes(), 24); + QCOMPARE(method2.index(), 0); + + // Perform index-based lookup again. + QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), -1); + QCOMPARE(builder.indexOfMethod("bar(QString)"), 0); + QCOMPARE(builder.indexOfMethod("baz()"), -1); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods)); +} + +void tst_QMetaObjectBuilder::slot() +{ + QMetaObjectBuilder builder; + + // Add a slot and check its attributes. + QMetaMethodBuilder method1 = builder.addSlot("foo(const QString&, int)"); + QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(method1.methodType() == QMetaMethod::Slot); + QVERIFY(method1.returnType().isEmpty()); + QVERIFY(method1.parameterNames().isEmpty()); + QVERIFY(method1.tag().isEmpty()); + QVERIFY(method1.access() == QMetaMethod::Public); + QCOMPARE(method1.attributes(), 0); + QCOMPARE(method1.index(), 0); + QCOMPARE(builder.methodCount(), 1); + + // Add another slot and check again. + QMetaMethodBuilder method2 = builder.addSlot("bar(QString)"); + QCOMPARE(method2.signature(), QByteArray("bar(QString)")); + QVERIFY(method2.methodType() == QMetaMethod::Slot); + QVERIFY(method2.returnType().isEmpty()); + QVERIFY(method2.parameterNames().isEmpty()); + QVERIFY(method2.tag().isEmpty()); + QVERIFY(method2.access() == QMetaMethod::Public); + QCOMPARE(method2.attributes(), 0); + QCOMPARE(method2.index(), 1); + QCOMPARE(builder.methodCount(), 2); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods)); +} + +void tst_QMetaObjectBuilder::signal() +{ + QMetaObjectBuilder builder; + + // Add a signal and check its attributes. + QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)"); + QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(method1.methodType() == QMetaMethod::Signal); + QVERIFY(method1.returnType().isEmpty()); + QVERIFY(method1.parameterNames().isEmpty()); + QVERIFY(method1.tag().isEmpty()); + QVERIFY(method1.access() == QMetaMethod::Protected); + QCOMPARE(method1.attributes(), 0); + QCOMPARE(method1.index(), 0); + QCOMPARE(builder.methodCount(), 1); + + // Add another signal and check again. + QMetaMethodBuilder method2 = builder.addSignal("bar(QString)"); + QCOMPARE(method2.signature(), QByteArray("bar(QString)")); + QVERIFY(method2.methodType() == QMetaMethod::Signal); + QVERIFY(method2.returnType().isEmpty()); + QVERIFY(method2.parameterNames().isEmpty()); + QVERIFY(method2.tag().isEmpty()); + QVERIFY(method2.access() == QMetaMethod::Protected); + QCOMPARE(method2.attributes(), 0); + QCOMPARE(method2.index(), 1); + QCOMPARE(builder.methodCount(), 2); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods)); +} + +void tst_QMetaObjectBuilder::constructor() +{ + QMetaObjectBuilder builder; + + // Add a constructor and check its attributes. + QMetaMethodBuilder ctor1 = builder.addConstructor("foo(const QString&, int)"); + QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(ctor1.methodType() == QMetaMethod::Constructor); + QVERIFY(ctor1.returnType().isEmpty()); + QVERIFY(ctor1.parameterNames().isEmpty()); + QVERIFY(ctor1.tag().isEmpty()); + QVERIFY(ctor1.access() == QMetaMethod::Public); + QCOMPARE(ctor1.attributes(), 0); + QCOMPARE(ctor1.index(), 0); + QCOMPARE(builder.constructorCount(), 1); + + // Add another constructor and check again. + QMetaMethodBuilder ctor2 = builder.addConstructor("bar(QString)"); + QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); + QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); + QVERIFY(ctor2.returnType().isEmpty()); + QVERIFY(ctor2.parameterNames().isEmpty()); + QVERIFY(ctor2.tag().isEmpty()); + QVERIFY(ctor2.access() == QMetaMethod::Public); + QCOMPARE(ctor2.attributes(), 0); + QCOMPARE(ctor2.index(), 1); + QCOMPARE(builder.constructorCount(), 2); + + // Perform index-based lookup. + QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), 0); + QCOMPARE(builder.indexOfConstructor("bar(QString)"), 1); + QCOMPARE(builder.indexOfConstructor("baz()"), -1); + + // Modify the attributes on ctor1. + ctor1.setReturnType("int"); + ctor1.setParameterNames(QList<QByteArray>() << "a" << "b"); + ctor1.setTag("tag"); + ctor1.setAccess(QMetaMethod::Private); + ctor1.setAttributes(42); + + // Check that ctor1 is changed, but ctor2 is not. + QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(ctor1.methodType() == QMetaMethod::Constructor); + QCOMPARE(ctor1.returnType(), QByteArray("int")); + QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b"); + QCOMPARE(ctor1.tag(), QByteArray("tag")); + QVERIFY(ctor1.access() == QMetaMethod::Private); + QCOMPARE(ctor1.attributes(), 42); + QCOMPARE(ctor1.index(), 0); + QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); + QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); + QVERIFY(ctor2.returnType().isEmpty()); + QVERIFY(ctor2.parameterNames().isEmpty()); + QVERIFY(ctor2.tag().isEmpty()); + QVERIFY(ctor2.access() == QMetaMethod::Public); + QCOMPARE(ctor2.attributes(), 0); + QCOMPARE(ctor2.index(), 1); + QCOMPARE(builder.constructorCount(), 2); + + // Modify the attributes on ctor2. + ctor2.setReturnType("QString"); + ctor2.setParameterNames(QList<QByteArray>() << "c"); + ctor2.setTag("Q_FOO"); + ctor2.setAccess(QMetaMethod::Protected); + ctor2.setAttributes(24); + + // This time check that only ctor2 changed. + QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); + QVERIFY(ctor1.methodType() == QMetaMethod::Constructor); + QCOMPARE(ctor1.returnType(), QByteArray("int")); + QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b"); + QCOMPARE(ctor1.tag(), QByteArray("tag")); + QVERIFY(ctor1.access() == QMetaMethod::Private); + QCOMPARE(ctor1.attributes(), 42); + QCOMPARE(ctor1.index(), 0); + QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); + QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); + QCOMPARE(ctor2.returnType(), QByteArray("QString")); + QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c"); + QCOMPARE(ctor2.tag(), QByteArray("Q_FOO")); + QVERIFY(ctor2.access() == QMetaMethod::Protected); + QCOMPARE(ctor2.attributes(), 24); + QCOMPARE(ctor2.index(), 1); + QCOMPARE(builder.constructorCount(), 2); + + // Remove ctor1 and check that ctor2 becomes index 0. + builder.removeConstructor(0); + QCOMPARE(builder.constructorCount(), 1); + ctor2 = builder.constructor(0); + QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); + QVERIFY(ctor2.methodType() == QMetaMethod::Constructor); + QCOMPARE(ctor2.returnType(), QByteArray("QString")); + QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c"); + QCOMPARE(ctor2.tag(), QByteArray("Q_FOO")); + QVERIFY(ctor2.access() == QMetaMethod::Protected); + QCOMPARE(ctor2.attributes(), 24); + QCOMPARE(ctor2.index(), 0); + + // Perform index-based lookup again. + QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), -1); + QCOMPARE(builder.indexOfConstructor("bar(QString)"), 0); + QCOMPARE(builder.indexOfConstructor("baz()"), -1); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Constructors)); +} + +void tst_QMetaObjectBuilder::property() +{ + QMetaObjectBuilder builder; + + // Add a property and check its attributes. + QMetaPropertyBuilder prop1 = builder.addProperty("foo", "const QString &"); + QCOMPARE(prop1.name(), QByteArray("foo")); + QCOMPARE(prop1.type(), QByteArray("QString")); + QVERIFY(!prop1.hasNotifySignal()); + QVERIFY(prop1.isReadable()); + QVERIFY(prop1.isWritable()); + QVERIFY(!prop1.isResettable()); + QVERIFY(!prop1.isDesignable()); + QVERIFY(!prop1.isScriptable()); + QVERIFY(!prop1.isStored()); + QVERIFY(!prop1.isEditable()); + QVERIFY(!prop1.isUser()); + QVERIFY(!prop1.hasStdCppSet()); + QVERIFY(!prop1.isEnumOrFlag()); + QCOMPARE(prop1.index(), 0); + QCOMPARE(builder.propertyCount(), 1); + + // Add another property and check again. + QMetaPropertyBuilder prop2 = builder.addProperty("bar", "int"); + QCOMPARE(prop2.name(), QByteArray("bar")); + QCOMPARE(prop2.type(), QByteArray("int")); + QVERIFY(!prop2.hasNotifySignal()); + QVERIFY(prop2.isReadable()); + QVERIFY(prop2.isWritable()); + QVERIFY(!prop2.isResettable()); + QVERIFY(!prop2.isDesignable()); + QVERIFY(!prop2.isScriptable()); + QVERIFY(!prop2.isStored()); + QVERIFY(!prop2.isEditable()); + QVERIFY(!prop2.isUser()); + QVERIFY(!prop2.hasStdCppSet()); + QVERIFY(!prop2.isEnumOrFlag()); + QCOMPARE(prop2.index(), 1); + QCOMPARE(builder.propertyCount(), 2); + + // Perform index-based lookup. + QCOMPARE(builder.indexOfProperty("foo"), 0); + QCOMPARE(builder.indexOfProperty("bar"), 1); + QCOMPARE(builder.indexOfProperty("baz"), -1); + + // Modify the attributes on prop1. + prop1.setReadable(false); + prop1.setWritable(false); + prop1.setResettable(true); + prop1.setDesignable(true); + prop1.setScriptable(true); + prop1.setStored(true); + prop1.setEditable(true); + prop1.setUser(true); + prop1.setStdCppSet(true); + prop1.setEnumOrFlag(true); + + // Check that prop1 is changed, but prop2 is not. + QCOMPARE(prop1.name(), QByteArray("foo")); + QCOMPARE(prop1.type(), QByteArray("QString")); + QVERIFY(!prop1.isReadable()); + QVERIFY(!prop1.isWritable()); + QVERIFY(prop1.isResettable()); + QVERIFY(prop1.isDesignable()); + QVERIFY(prop1.isScriptable()); + QVERIFY(prop1.isStored()); + QVERIFY(prop1.isEditable()); + QVERIFY(prop1.isUser()); + QVERIFY(prop1.hasStdCppSet()); + QVERIFY(prop1.isEnumOrFlag()); + QVERIFY(prop2.isReadable()); + QVERIFY(prop2.isWritable()); + QCOMPARE(prop2.name(), QByteArray("bar")); + QCOMPARE(prop2.type(), QByteArray("int")); + QVERIFY(!prop2.isResettable()); + QVERIFY(!prop2.isDesignable()); + QVERIFY(!prop2.isScriptable()); + QVERIFY(!prop2.isStored()); + QVERIFY(!prop2.isEditable()); + QVERIFY(!prop2.isUser()); + QVERIFY(!prop2.hasStdCppSet()); + QVERIFY(!prop2.isEnumOrFlag()); + + // Remove prop1 and check that prop2 becomes index 0. + builder.removeProperty(0); + QCOMPARE(builder.propertyCount(), 1); + prop2 = builder.property(0); + QCOMPARE(prop2.name(), QByteArray("bar")); + QCOMPARE(prop2.type(), QByteArray("int")); + QVERIFY(!prop2.isResettable()); + QVERIFY(!prop2.isDesignable()); + QVERIFY(!prop2.isScriptable()); + QVERIFY(!prop2.isStored()); + QVERIFY(!prop2.isEditable()); + QVERIFY(!prop2.isUser()); + QVERIFY(!prop2.hasStdCppSet()); + QVERIFY(!prop2.isEnumOrFlag()); + QCOMPARE(prop2.index(), 0); + + // Perform index-based lookup again. + QCOMPARE(builder.indexOfProperty("foo"), -1); + QCOMPARE(builder.indexOfProperty("bar"), 0); + QCOMPARE(builder.indexOfProperty("baz"), -1); + + // Check for side-effects between the flags on prop2. + // Setting a flag to true shouldn't set any of the others to true. + // This checks for cut-and-paste bugs in the implementation where + // the flag code was pasted but the flag name was not changed. +#define CLEAR_FLAGS() \ + do { \ + prop2.setReadable(false); \ + prop2.setWritable(false); \ + prop2.setResettable(false); \ + prop2.setDesignable(false); \ + prop2.setScriptable(false); \ + prop2.setStored(false); \ + prop2.setEditable(false); \ + prop2.setUser(false); \ + prop2.setStdCppSet(false); \ + prop2.setEnumOrFlag(false); \ + } while (0) +#define COUNT_FLAGS() \ + ((prop2.isReadable() ? 1 : 0) + \ + (prop2.isWritable() ? 1 : 0) + \ + (prop2.isResettable() ? 1 : 0) + \ + (prop2.isDesignable() ? 1 : 0) + \ + (prop2.isScriptable() ? 1 : 0) + \ + (prop2.isStored() ? 1 : 0) + \ + (prop2.isEditable() ? 1 : 0) + \ + (prop2.isUser() ? 1 : 0) + \ + (prop2.hasStdCppSet() ? 1 : 0) + \ + (prop2.isEnumOrFlag() ? 1 : 0)) +#define CHECK_FLAG(setFunc,isFunc) \ + do { \ + CLEAR_FLAGS(); \ + QCOMPARE(COUNT_FLAGS(), 0); \ + prop2.setFunc(true); \ + QVERIFY(prop2.isFunc()); \ + QCOMPARE(COUNT_FLAGS(), 1); \ + } while (0) + CHECK_FLAG(setReadable, isReadable); + CHECK_FLAG(setWritable, isWritable); + CHECK_FLAG(setResettable, isResettable); + CHECK_FLAG(setDesignable, isDesignable); + CHECK_FLAG(setScriptable, isScriptable); + CHECK_FLAG(setStored, isStored); + CHECK_FLAG(setEditable, isEditable); + CHECK_FLAG(setUser, isUser); + CHECK_FLAG(setStdCppSet, hasStdCppSet); + CHECK_FLAG(setEnumOrFlag, isEnumOrFlag); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties)); +} + +void tst_QMetaObjectBuilder::notifySignal() +{ + QMetaObjectBuilder builder; + + QMetaPropertyBuilder prop = builder.addProperty("foo", "const QString &"); + builder.addSlot("setFoo(QString)"); + QMetaMethodBuilder notify = builder.addSignal("fooChanged(QString)"); + + QVERIFY(!prop.hasNotifySignal()); + QCOMPARE(prop.notifySignal().index(), 0); + + prop.setNotifySignal(notify); + QVERIFY(prop.hasNotifySignal()); + QCOMPARE(prop.notifySignal().index(), 1); + + prop.setNotifySignal(QMetaMethodBuilder()); + QVERIFY(!prop.hasNotifySignal()); + QCOMPARE(prop.notifySignal().index(), 0); + + prop.setNotifySignal(notify); + prop.removeNotifySignal(); + QVERIFY(!prop.hasNotifySignal()); + QCOMPARE(prop.notifySignal().index(), 0); + + QCOMPARE(builder.methodCount(), 2); + QCOMPARE(builder.propertyCount(), 1); + + // Check that nothing else changed except methods and properties. + QVERIFY(checkForSideEffects + (builder, QMetaObjectBuilder::Methods | QMetaObjectBuilder::Properties)); +} + +void tst_QMetaObjectBuilder::enumerator() +{ + QMetaObjectBuilder builder; + + // Add an enumerator and check its attributes. + QMetaEnumBuilder enum1 = builder.addEnumerator("foo"); + QCOMPARE(enum1.name(), QByteArray("foo")); + QVERIFY(!enum1.isFlag()); + QCOMPARE(enum1.keyCount(), 0); + QCOMPARE(enum1.index(), 0); + QCOMPARE(builder.enumeratorCount(), 1); + + // Add another enumerator and check again. + QMetaEnumBuilder enum2 = builder.addEnumerator("bar"); + QCOMPARE(enum2.name(), QByteArray("bar")); + QVERIFY(!enum2.isFlag()); + QCOMPARE(enum2.keyCount(), 0); + QCOMPARE(enum2.index(), 1); + QCOMPARE(builder.enumeratorCount(), 2); + + // Perform index-based lookup. + QCOMPARE(builder.indexOfEnumerator("foo"), 0); + QCOMPARE(builder.indexOfEnumerator("bar"), 1); + QCOMPARE(builder.indexOfEnumerator("baz"), -1); + + // Modify the attributes on enum1. + enum1.setIsFlag(true); + QCOMPARE(enum1.addKey("ABC", 0), 0); + QCOMPARE(enum1.addKey("DEF", 1), 1); + QCOMPARE(enum1.addKey("GHI", -1), 2); + + // Check that enum1 is changed, but enum2 is not. + QCOMPARE(enum1.name(), QByteArray("foo")); + QVERIFY(enum1.isFlag()); + QCOMPARE(enum1.keyCount(), 3); + QCOMPARE(enum1.index(), 0); + QCOMPARE(enum1.key(0), QByteArray("ABC")); + QCOMPARE(enum1.key(1), QByteArray("DEF")); + QCOMPARE(enum1.key(2), QByteArray("GHI")); + QCOMPARE(enum1.value(0), 0); + QCOMPARE(enum1.value(1), 1); + QCOMPARE(enum1.value(2), -1); + QCOMPARE(enum2.name(), QByteArray("bar")); + QVERIFY(!enum2.isFlag()); + QCOMPARE(enum2.keyCount(), 0); + QCOMPARE(enum2.index(), 1); + + // Modify the attributes on enum2. + enum2.setIsFlag(true); + QCOMPARE(enum2.addKey("XYZ", 10), 0); + QCOMPARE(enum2.addKey("UVW", 19), 1); + + // This time check that only method2 changed. + QCOMPARE(enum1.name(), QByteArray("foo")); + QVERIFY(enum1.isFlag()); + QCOMPARE(enum1.keyCount(), 3); + QCOMPARE(enum1.index(), 0); + QCOMPARE(enum1.key(0), QByteArray("ABC")); + QCOMPARE(enum1.key(1), QByteArray("DEF")); + QCOMPARE(enum1.key(2), QByteArray("GHI")); + QCOMPARE(enum1.value(0), 0); + QCOMPARE(enum1.value(1), 1); + QCOMPARE(enum1.value(2), -1); + QCOMPARE(enum2.name(), QByteArray("bar")); + QVERIFY(enum2.isFlag()); + QCOMPARE(enum2.keyCount(), 2); + QCOMPARE(enum2.index(), 1); + QCOMPARE(enum2.key(0), QByteArray("XYZ")); + QCOMPARE(enum2.key(1), QByteArray("UVW")); + QCOMPARE(enum2.value(0), 10); + QCOMPARE(enum2.value(1), 19); + + // Remove enum1 and check that enum2 becomes index 0. + builder.removeEnumerator(0); + QCOMPARE(builder.enumeratorCount(), 1); + enum2 = builder.enumerator(0); + QCOMPARE(enum2.name(), QByteArray("bar")); + QVERIFY(enum2.isFlag()); + QCOMPARE(enum2.keyCount(), 2); + QCOMPARE(enum2.index(), 0); + QCOMPARE(enum2.key(0), QByteArray("XYZ")); + QCOMPARE(enum2.key(1), QByteArray("UVW")); + QCOMPARE(enum2.value(0), 10); + QCOMPARE(enum2.value(1), 19); + + // Perform index-based lookup again. + QCOMPARE(builder.indexOfEnumerator("foo"), -1); + QCOMPARE(builder.indexOfEnumerator("bar"), 0); + QCOMPARE(builder.indexOfEnumerator("baz"), -1); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators)); +} + +void tst_QMetaObjectBuilder::classInfo() +{ + QMetaObjectBuilder builder; + + // Add two items of class information and check their attributes. + QCOMPARE(builder.addClassInfo("foo", "value1"), 0); + QCOMPARE(builder.addClassInfo("bar", "value2"), 1); + QCOMPARE(builder.classInfoName(0), QByteArray("foo")); + QCOMPARE(builder.classInfoValue(0), QByteArray("value1")); + QCOMPARE(builder.classInfoName(1), QByteArray("bar")); + QCOMPARE(builder.classInfoValue(1), QByteArray("value2")); + QCOMPARE(builder.classInfoCount(), 2); + + // Perform index-based lookup. + QCOMPARE(builder.indexOfClassInfo("foo"), 0); + QCOMPARE(builder.indexOfClassInfo("bar"), 1); + QCOMPARE(builder.indexOfClassInfo("baz"), -1); + + // Remove the first one and check again. + builder.removeClassInfo(0); + QCOMPARE(builder.classInfoName(0), QByteArray("bar")); + QCOMPARE(builder.classInfoValue(0), QByteArray("value2")); + QCOMPARE(builder.classInfoCount(), 1); + + // Perform index-based lookup again. + QCOMPARE(builder.indexOfClassInfo("foo"), -1); + QCOMPARE(builder.indexOfClassInfo("bar"), 0); + QCOMPARE(builder.indexOfClassInfo("baz"), -1); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassInfos)); +} + +void tst_QMetaObjectBuilder::relatedMetaObject() +{ + QMetaObjectBuilder builder; + + // Add two related meta objects and check their attributes. + QCOMPARE(builder.addRelatedMetaObject(&QObject::staticMetaObject), 0); + QCOMPARE(builder.addRelatedMetaObject(&staticMetaObject), 1); + QVERIFY(builder.relatedMetaObject(0) == &QObject::staticMetaObject); + QVERIFY(builder.relatedMetaObject(1) == &staticMetaObject); + QCOMPARE(builder.relatedMetaObjectCount(), 2); + + // Remove the first one and check again. + builder.removeRelatedMetaObject(0); + QVERIFY(builder.relatedMetaObject(0) == &staticMetaObject); + QCOMPARE(builder.relatedMetaObjectCount(), 1); + + // Check that nothing else changed. + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::RelatedMetaObjects)); +} + +static int smetacall(QMetaObject::Call, int, void **) +{ + return 0; +} + +void tst_QMetaObjectBuilder::staticMetacall() +{ + QMetaObjectBuilder builder; + QVERIFY(!builder.staticMetacallFunction()); + builder.setStaticMetacallFunction(smetacall); + QVERIFY(builder.staticMetacallFunction() == smetacall); + QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall)); +} + +// Dummy class that has something of every type of thing moc can generate. +class SomethingOfEverything : public QObject +{ + Q_OBJECT + Q_CLASSINFO("ci_foo", "ABC") + Q_CLASSINFO("ci_bar", "DEF") + Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged) + Q_PROPERTY(QString prop2 READ prop WRITE setProp) + Q_PROPERTY(SomethingEnum eprop READ eprop) + Q_PROPERTY(SomethingFlagEnum fprop READ fprop) + Q_PROPERTY(QLocale::Language language READ language) + Q_ENUMS(SomethingEnum) + Q_FLAGS(SomethingFlagEnum) +public: + Q_INVOKABLE SomethingOfEverything() {} + ~SomethingOfEverything() {} + + enum SomethingEnum + { + GHI, + JKL = 10 + }; + + enum SomethingFlagEnum + { + XYZ = 1, + UVW = 8 + }; + + Q_INVOKABLE Q_SCRIPTABLE void method1() {} + + QString prop() const { return QString(); } + void setProp(const QString& v) { Q_UNUSED(v); } + + SomethingOfEverything::SomethingEnum eprop() const { return GHI; } + SomethingOfEverything::SomethingFlagEnum fprop() const { return XYZ; } + QLocale::Language language() const { return QLocale::English; } + +public slots: + void slot1(const QString&) {} + void slot2(int, const QString&) {} + +private slots: + void slot3() {} + +protected slots: + Q_SCRIPTABLE void slot4(int) {} + void slot5(int a, const QString& b) { Q_UNUSED(a); Q_UNUSED(b); } + +signals: + void sig1(); + void sig2(int x, const QString& y); + void propChanged(const QString&); +}; + +// Copy the entire contents of a static QMetaObject and then check +// that QMetaObjectBuilder will produce an exact copy as output. +void tst_QMetaObjectBuilder::copyMetaObject() +{ + QMetaObjectBuilder builder(&QObject::staticMetaObject); + QMetaObject *meta = builder.toMetaObject(); + QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject)); + qFree(meta); + + QMetaObjectBuilder builder2(&staticMetaObject); + meta = builder2.toMetaObject(); + QVERIFY(sameMetaObject(meta, &staticMetaObject)); + qFree(meta); + + QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject); + meta = builder3.toMetaObject(); + QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject)); + qFree(meta); +} + +// Serialize and deserialize a meta object and check that +// it round-trips to the exact same value. +void tst_QMetaObjectBuilder::serialize() +{ + QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject); + QMetaObject *meta = builder.toMetaObject(); + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append); + builder.serialize(stream); + + QMetaObjectBuilder builder2; + QDataStream stream2(data); + QMap<QByteArray, const QMetaObject *> references; + references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject); + builder2.deserialize(stream2, references); + builder2.setStaticMetacallFunction(builder.staticMetacallFunction()); + QMetaObject *meta2 = builder2.toMetaObject(); + + QVERIFY(sameMetaObject(meta, meta2)); + qFree(meta); + qFree(meta2); +} + +// Check that the only changes to a "builder" relative to the default +// state is specified by "members". +bool tst_QMetaObjectBuilder::checkForSideEffects + (const QMetaObjectBuilder& builder, + QMetaObjectBuilder::AddMembers members) +{ + if ((members & QMetaObjectBuilder::ClassName) == 0) { + if (!builder.className().isEmpty()) + return false; + } + + if ((members & QMetaObjectBuilder::SuperClass) == 0) { + if (builder.superClass() != &QObject::staticMetaObject) + return false; + } + + if ((members & QMetaObjectBuilder::Methods) == 0) { + if (builder.methodCount() != 0) + return false; + } + + if ((members & QMetaObjectBuilder::Constructors) == 0) { + if (builder.constructorCount() != 0) + return false; + } + + if ((members & QMetaObjectBuilder::Properties) == 0) { + if (builder.propertyCount() != 0) + return false; + } + + if ((members & QMetaObjectBuilder::Enumerators) == 0) { + if (builder.enumeratorCount() != 0) + return false; + } + + if ((members & QMetaObjectBuilder::ClassInfos) == 0) { + if (builder.classInfoCount() != 0) + return false; + } + + if ((members & QMetaObjectBuilder::RelatedMetaObjects) == 0) { + if (builder.relatedMetaObjectCount() != 0) + return false; + } + + if ((members & QMetaObjectBuilder::StaticMetacall) == 0) { + if (builder.staticMetacallFunction() != 0) + return false; + } + + return true; +} + +static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2) +{ + if (QByteArray(method1.signature()) != QByteArray(method2.signature())) + return false; + + if (QByteArray(method1.typeName()) != QByteArray(method2.typeName())) + return false; + + if (method1.parameterNames() != method2.parameterNames()) + return false; + + if (QByteArray(method1.tag()) != QByteArray(method2.tag())) + return false; + + if (method1.access() != method2.access()) + return false; + + if (method1.methodType() != method2.methodType()) + return false; + + if (method1.attributes() != method2.attributes()) + return false; + + return true; +} + +static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2) +{ + if (QByteArray(prop1.name()) != QByteArray(prop2.name())) + return false; + + if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName())) + return false; + + if (prop1.isReadable() != prop2.isReadable() || + prop1.isWritable() != prop2.isWritable() || + prop1.isResettable() != prop2.isResettable() || + prop1.isDesignable() != prop2.isDesignable() || + prop1.isScriptable() != prop2.isScriptable() || + prop1.isStored() != prop2.isStored() || + prop1.isEditable() != prop2.isEditable() || + prop1.isUser() != prop2.isUser() || + prop1.isFlagType() != prop2.isFlagType() || + prop1.isEnumType() != prop2.isEnumType() || + prop1.hasNotifySignal() != prop2.hasNotifySignal() || + prop1.hasStdCppSet() != prop2.hasStdCppSet()) + return false; + + if (prop1.hasNotifySignal()) { + if (prop1.notifySignalIndex() != prop2.notifySignalIndex()) + return false; + } + + return true; +} + +static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2) +{ + if (QByteArray(enum1.name()) != QByteArray(enum2.name())) + return false; + + if (enum1.isFlag() != enum2.isFlag()) + return false; + + if (enum1.keyCount() != enum2.keyCount()) + return false; + + for (int index = 0; index < enum1.keyCount(); ++index) { + if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index))) + return false; + if (enum1.value(index) != enum2.value(index)) + return false; + } + + if (QByteArray(enum1.scope()) != QByteArray(enum2.scope())) + return false; + + return true; +} + +// Determine if two meta objects are identical. +bool tst_QMetaObjectBuilder::sameMetaObject + (const QMetaObject *meta1, const QMetaObject *meta2) +{ + int index; + + if (strcmp(meta1->className(), meta2->className()) != 0) + return false; + + if (meta1->superClass() != meta2->superClass()) + return false; + + if (meta1->constructorCount() != meta2->constructorCount() || + meta1->methodCount() != meta2->methodCount() || + meta1->enumeratorCount() != meta2->enumeratorCount() || + meta1->propertyCount() != meta2->propertyCount() || + meta1->classInfoCount() != meta2->classInfoCount()) + return false; + + for (index = 0; index < meta1->constructorCount(); ++index) { + if (!sameMethod(meta1->constructor(index), meta2->constructor(index))) + return false; + } + + for (index = 0; index < meta1->methodCount(); ++index) { + if (!sameMethod(meta1->method(index), meta2->method(index))) + return false; + } + + for (index = 0; index < meta1->propertyCount(); ++index) { + if (!sameProperty(meta1->property(index), meta2->property(index))) + return false; + } + + for (index = 0; index < meta1->enumeratorCount(); ++index) { + if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index))) + return false; + } + + for (index = 0; index < meta1->classInfoCount(); ++index) { + if (QByteArray(meta1->classInfo(index).name()) != + QByteArray(meta2->classInfo(index).name())) + return false; + if (QByteArray(meta1->classInfo(index).value()) != + QByteArray(meta2->classInfo(index).value())) + return false; + } + + const QMetaObject **objects1 = 0; + const QMetaObject **objects2 = 0; + if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] >= 2) { + QMetaObjectExtraData *extra1 = (QMetaObjectExtraData *)(meta1->d.extradata); + QMetaObjectExtraData *extra2 = (QMetaObjectExtraData *)(meta2->d.extradata); + if (extra1 && !extra2) + return false; + if (extra2 && !extra1) + return false; + if (extra1 && extra2) { + if (extra1->static_metacall != extra2->static_metacall) + return false; + objects1 = extra1->objects; + objects2 = extra1->objects; + } + } else if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] == 1) { + objects1 = (const QMetaObject **)(meta1->d.extradata); + objects2 = (const QMetaObject **)(meta2->d.extradata); + } + if (objects1 && !objects2) + return false; + if (objects2 && !objects1) + return false; + if (objects1 && objects2) { + while (*objects1 != 0 && *objects2 != 0) { + if (*objects1 != *objects2) + return false; + ++objects1; + ++objects2; + } + } + + return true; +} + +QTEST_MAIN(tst_QMetaObjectBuilder) + +#include "tst_qmetaobjectbuilder.moc" diff --git a/tests/auto/declarative/qmlcontext/tst_qmlcontext.cpp b/tests/auto/declarative/qmlcontext/tst_qmlcontext.cpp index 69d9091..3c60b2b 100644 --- a/tests/auto/declarative/qmlcontext/tst_qmlcontext.cpp +++ b/tests/auto/declarative/qmlcontext/tst_qmlcontext.cpp @@ -44,6 +44,7 @@ #include <QmlEngine> #include <QmlContext> #include <QmlComponent> +#include <QmlExpression> class tst_qmlcontext : public QObject { @@ -58,6 +59,7 @@ private slots: void parentContext(); void setContextProperty(); void addDefaultObject(); + void destruction(); private: QmlEngine engine; @@ -111,6 +113,14 @@ void tst_qmlcontext::resolvedUrl() QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl()); } + + // Absolute + { + QmlContext ctxt(&engine); + + QCOMPARE(ctxt.resolvedUrl(QUrl("http://www.nokia.com/main2.qml")), QUrl("http://www.nokia.com/main2.qml")); + QCOMPARE(ctxt.resolvedUrl(QUrl("file:///main2.qml")), QUrl("file:///main2.qml")); + } } void tst_qmlcontext::engineMethod() @@ -256,10 +266,10 @@ void tst_qmlcontext::setContextProperty() // Static context properties ctxt.setContextProperty("a", QVariant(10)); ctxt.setContextProperty("b", QVariant(9)); + ctxt2.setContextProperty("d", &obj2); ctxt2.setContextProperty("b", QVariant(19)); ctxt2.setContextProperty("c", QVariant(QString("Hello World!"))); ctxt.setContextProperty("d", &obj1); - ctxt2.setContextProperty("d", &obj2); ctxt.setContextProperty("e", &obj1); TEST_CONTEXT_PROPERTY(&ctxt2, a, QVariant(10)); @@ -334,6 +344,26 @@ void tst_qmlcontext::setContextProperty() delete obj; } + + // Setting an object-variant context property + { + QmlComponent component(&engine); + component.setData("import Qt 4.6; Object { id: root; property int a: 10; property int test: ctxtProp.a; property var obj: root; }", QUrl()); + + QmlContext ctxt(engine.rootContext()); + ctxt.setContextProperty("ctxtProp", QVariant()); + + QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Result of expression 'ctxtProp' [undefined] is not an object."); + QObject *obj = component.create(&ctxt); + + QVariant v = obj->property("obj"); + + ctxt.setContextProperty("ctxtProp", v); + + QCOMPARE(obj->property("test"), QVariant(10)); + + delete obj; + } } void tst_qmlcontext::addDefaultObject() @@ -382,6 +412,23 @@ void tst_qmlcontext::addDefaultObject() } } +void tst_qmlcontext::destruction() +{ + QmlContext *ctxt = new QmlContext(&engine); + + QObject obj; + QmlEngine::setContextForObject(&obj, ctxt); + QmlExpression expr(ctxt, "a", 0); + + QCOMPARE(ctxt, QmlEngine::contextForObject(&obj)); + QCOMPARE(ctxt, expr.context()); + + delete ctxt; ctxt = 0; + + QCOMPARE(ctxt, QmlEngine::contextForObject(&obj)); + QCOMPARE(ctxt, expr.context()); +} + QTEST_MAIN(tst_qmlcontext) #include "tst_qmlcontext.moc" |