diff options
author | Martin Jones <martin.jones@nokia.com> | 2009-08-12 01:33:05 (GMT) |
---|---|---|
committer | Martin Jones <martin.jones@nokia.com> | 2009-08-12 01:33:05 (GMT) |
commit | 10408036279e8102c3dd2870a6c71280c43da614 (patch) | |
tree | 57d307a842a8d2527d18e0c212295199a04ff771 | |
parent | 6fc7ce61ba1b623421ca3ca8ee2315746be0a37b (diff) | |
parent | eae40ec9e65326bf268979afe1399d1fb8548105 (diff) | |
download | Qt-10408036279e8102c3dd2870a6c71280c43da614.zip Qt-10408036279e8102c3dd2870a6c71280c43da614.tar.gz Qt-10408036279e8102c3dd2870a6c71280c43da614.tar.bz2 |
Merge branch 'kinetic-declarativeui' of git@scm.dev.nokia.troll.no:qt/kinetic into kinetic-declarativeui
69 files changed, 2325 insertions, 1047 deletions
diff --git a/demos/declarative/flickr/content/MediaLineEdit.qml b/demos/declarative/flickr/content/MediaLineEdit.qml index b8d30ce..4a55ff5 100644 --- a/demos/declarative/flickr/content/MediaLineEdit.qml +++ b/demos/declarative/flickr/content/MediaLineEdit.qml @@ -47,14 +47,14 @@ Item { ] - Image { + BorderImage { id: Image source: "pics/button.sci" anchors.left: Container.left anchors.right: Container.right } - Image { + BorderImage { id: Pressed source: "pics/button-pressed.sci" opacity: 0 diff --git a/demos/declarative/webbrowser/webbrowser.qml b/demos/declarative/webbrowser/webbrowser.qml index 28e5f16..7a7d9e2 100644 --- a/demos/declarative/webbrowser/webbrowser.qml +++ b/demos/declarative/webbrowser/webbrowser.qml @@ -17,8 +17,8 @@ Item { } function toggleZoom() { if(WebBrowser.state == "ZoomedOut") { - Flick.centerX = WebView.mouseX; - Flick.centerY = WebView.mouseY; + Flick.centerX = MyWebView.mouseX; + Flick.centerY = MyWebView.mouseY; WebBrowser.state = "Normal"; } else { zoomOut(); @@ -48,8 +48,8 @@ Item { RectSoftShadow { x: -Flick.xPosition y: -Flick.yPosition - width: WebView.width*WebView.scale - height: Flick.y+WebView.height*WebView.scale + width: MyWebView.width*MyWebView.scale + height: Flick.y+MyWebView.height*MyWebView.scale } Item { id: HeaderSpace @@ -70,7 +70,7 @@ Item { Text { id: HeaderText - text: WebView.title!='' || WebView.progress == 1.0 ? WebView.title : 'Loading...' + text: MyWebView.title!='' || MyWebView.progress == 1.0 ? MyWebView.title : 'Loading...' elide: "ElideRight" color: "white" @@ -111,7 +111,7 @@ Item { Image { id: UrlBoxhl source: "content/pics/addressbar-filled.sci" - width: parent.width*WebView.progress + width: parent.width*MyWebView.progress height: parent.height opacity: 1-Header.progressOff clip: true @@ -132,7 +132,7 @@ Item { TextEdit { id: EditUrl - text: WebView.url == '' ? ' ' : WebView.url + text: MyWebView.url == '' ? ' ' : MyWebView.url wrap: false font.size: 11 color: "#555555" @@ -151,12 +151,12 @@ Item { states: [ State { name: "Normal" - when: WebView.progress == 1.0 + when: MyWebView.progress == 1.0 SetProperties { target: Header; progressOff: 1 } }, State { name: "ProgressShown" - when: WebView.progress < 1.0 + when: MyWebView.progress < 1.0 SetProperties { target: Header; progressOff: 0; } } ] @@ -175,8 +175,8 @@ Item { Flickable { id: Flick width: parent.width - viewportWidth: Math.max(parent.width,WebView.width*WebView.scale) - viewportHeight: Math.max(parent.height,WebView.height*WebView.scale) + viewportWidth: Math.max(parent.width,MyWebView.width*MyWebView.scale) + viewportHeight: Math.max(parent.height,MyWebView.height*MyWebView.scale) anchors.top: HeaderSpace.bottom anchors.bottom: Footer.top anchors.left: parent.left @@ -186,7 +186,7 @@ Item { property real centerY : 0 WebView { - id: WebView + id: MyWebView cacheSize: 4000000 url: WebBrowser.url @@ -207,7 +207,7 @@ Item { id: WebViewTint color: "black" opacity: 0 - anchors.fill: WebView + anchors.fill: MyWebView MouseRegion { anchors.fill: WebViewTint onClicked: { proxy.focus=false } @@ -246,13 +246,13 @@ Item { states: [ State { name: "Enabled" - when: WebView.back.enabled==true + when: MyWebView.back.enabled==true SetProperties { target: back_e; opacity: 1 } SetProperties { target: back_d; opacity: 0 } }, State { name: "Disabled" - when: WebView.back.enabled==false + when: MyWebView.back.enabled==false SetProperties { target: back_e; opacity: 0 } SetProperties { target: back_d; opacity: 1 } } @@ -268,7 +268,7 @@ Item { ] MouseRegion { anchors.fill: back_e - onClicked: { if (WebView.back.enabled) WebView.back.trigger() } + onClicked: { if (MyWebView.back.enabled) MyWebView.back.trigger() } } } Image { @@ -279,7 +279,7 @@ Item { } MouseRegion { anchors.fill: reload - onClicked: { WebView.reload.trigger() } + onClicked: { MyWebView.reload.trigger() } } Item { id: forwardbutton @@ -302,13 +302,13 @@ Item { states: [ State { name: "Enabled" - when: WebView.forward.enabled==true + when: MyWebView.forward.enabled==true SetProperties { target: forward_e; opacity: 1 } SetProperties { target: forward_d; opacity: 0 } }, State { name: "Disabled" - when: WebView.forward.enabled==false + when: MyWebView.forward.enabled==false SetProperties { target: forward_e; opacity: 0 } SetProperties { target: forward_d; opacity: 1 } } @@ -324,7 +324,7 @@ Item { ] MouseRegion { anchors.fill: parent - onClicked: { if (WebView.forward.enabled) WebView.forward.trigger() } + onClicked: { if (MyWebView.forward.enabled) MyWebView.forward.trigger() } } } } @@ -332,26 +332,26 @@ Item { states: [ State { name: "Normal" - SetProperties { target: WebView; zoomedOut: 0 } - SetProperties { target: Flick; explicit: true; xPosition: Math.min(WebView.width-Flick.width,Math.max(0,Flick.centerX-Flick.width/2)) } - SetProperties { target: Flick; explicit: true; yPosition: Math.min(WebView.height-Flick.height,Math.max(0,Flick.centerY-Flick.height/2)) } + SetProperties { target: MyWebView; zoomedOut: 0 } + SetProperties { target: Flick; explicit: true; xPosition: Math.min(MyWebView.width-Flick.width,Math.max(0,Flick.centerX-Flick.width/2)) } + SetProperties { target: Flick; explicit: true; yPosition: Math.min(MyWebView.height-Flick.height,Math.max(0,Flick.centerY-Flick.height/2)) } }, State { name: "ZoomedOut" - SetProperties { target: WebView; zoomedOut: 1 } + SetProperties { target: MyWebView; zoomedOut: 1 } } ] transitions: [ Transition { SequentialAnimation { SetPropertyAction { - target: WebView + target: MyWebView property: "smooth" value: false } ParallelAnimation { NumberAnimation { - target: WebView + target: MyWebView properties: "zoomedOut" easing: "easeInOutQuad" duration: 200 @@ -364,7 +364,7 @@ Item { } } SetPropertyAction { - target: WebView + target: MyWebView property: "smooth" value: !Flick.moving } diff --git a/doc/src/images/declarative-image_fillMode.gif b/doc/src/images/declarative-image_fillMode.gif Binary files differindex c81b4d7..eb0a9af 100644 --- a/doc/src/images/declarative-image_fillMode.gif +++ b/doc/src/images/declarative-image_fillMode.gif diff --git a/examples/declarative/border-image/BorderImage.qml b/examples/declarative/border-image/MyBorderImage.qml index a809d5d..f9531df 100644 --- a/examples/declarative/border-image/BorderImage.qml +++ b/examples/declarative/border-image/MyBorderImage.qml @@ -12,7 +12,7 @@ Item { id: Container width: 240; height: 240 - Image { + BorderImage { x: Container.width / 2 - width / 2 y: Container.height / 2 - height / 2 width: SequentialAnimation { @@ -26,11 +26,11 @@ Item { NumberAnimation { from: Container.maxHeight; to: Container.minHeight; duration: 2000; easing: "easeInOutQuad" } } source: Container.source - scaleGrid.horizontalTileRule: Container.horizontalMode - scaleGrid.verticalTileRule: Container.verticalMode - scaleGrid.top: Container.margin - scaleGrid.left: Container.margin - scaleGrid.bottom: Container.margin - scaleGrid.right: Container.margin + horizontalTileMode: Container.horizontalMode + verticalTileMode: Container.verticalMode + border.top: Container.margin + border.left: Container.margin + border.bottom: Container.margin + border.right: Container.margin } } diff --git a/examples/declarative/border-image/animated.qml b/examples/declarative/border-image/animated.qml index 58eb44c..ce4de16 100644 --- a/examples/declarative/border-image/animated.qml +++ b/examples/declarative/border-image/animated.qml @@ -5,47 +5,47 @@ Rect { color: "white" width: 1030; height: 540 - BorderImage { + MyBorderImage { x: 20; y: 20; minWidth: 120; maxWidth: 240 minHeight: 120; maxHeight: 240 source: "colors.png"; margin: 30 } - BorderImage { + MyBorderImage { x: 270; y: 20; minWidth: 120; maxWidth: 240 minHeight: 120; maxHeight: 240 source: "colors.png"; margin: 30 horizontalMode: "Repeat"; verticalMode: "Repeat" } - BorderImage { + MyBorderImage { x: 520; y: 20; minWidth: 120; maxWidth: 240 minHeight: 120; maxHeight: 240 source: "colors.png"; margin: 30 horizontalMode: "Stretch"; verticalMode: "Repeat" } - BorderImage { + MyBorderImage { x: 770; y: 20; minWidth: 120; maxWidth: 240 minHeight: 120; maxHeight: 240 source: "colors.png"; margin: 30 horizontalMode: "Round"; verticalMode: "Round" } - BorderImage { + MyBorderImage { x: 20; y: 280; minWidth: 60; maxWidth: 200 minHeight: 40; maxHeight: 200 source: "bw.png"; margin: 10 } - BorderImage { + MyBorderImage { x: 270; y: 280; minWidth: 60; maxWidth: 200 minHeight: 40; maxHeight: 200 source: "bw.png"; margin: 10 horizontalMode: "Repeat"; verticalMode: "Repeat" } - BorderImage { + MyBorderImage { x: 520; y: 280; minWidth: 60; maxWidth: 200 minHeight: 40; maxHeight: 200 source: "bw.png"; margin: 10 horizontalMode: "Stretch"; verticalMode: "Repeat" } - BorderImage { + MyBorderImage { x: 770; y: 280; minWidth: 60; maxWidth: 200 minHeight: 40; maxHeight: 200 source: "bw.png"; margin: 10 diff --git a/examples/declarative/border-image/borders.qml b/examples/declarative/border-image/borders.qml index a4a329b..e8c581e 100644 --- a/examples/declarative/border-image/borders.qml +++ b/examples/declarative/border-image/borders.qml @@ -5,12 +5,12 @@ Rect { color: "white" width: 520; height: 280 - Image { + BorderImage { x: 20; y: 20; width: 230; height: 240 smooth: true source: "colors-stretch.sci" } - Image { + BorderImage { x: 270; y: 20; width: 230; height: 240 smooth: true source: "colors-round.sci" diff --git a/examples/declarative/border-image/colors.png b/examples/declarative/border-image/colors.png Binary files differindex c0e137c..dfb62f3 100644 --- a/examples/declarative/border-image/colors.png +++ b/examples/declarative/border-image/colors.png diff --git a/examples/declarative/fillmode/fillmode.qml b/examples/declarative/fillmode/fillmode.qml index 6bf1c12..f2a87c8 100644 --- a/examples/declarative/fillmode/fillmode.qml +++ b/examples/declarative/fillmode/fillmode.qml @@ -10,8 +10,11 @@ Image { SetPropertyAction { value: "Stretch" } SetPropertyAction { target: Label; property: "text"; value: "Stretch" } PauseAnimation { duration: 1000 } - SetPropertyAction { value: "PreserveAspect" } - SetPropertyAction { target: Label; property: "text"; value: "PreserveAspect" } + SetPropertyAction { value: "PreserveAspectFit" } + SetPropertyAction { target: Label; property: "text"; value: "PreserveAspectFit" } + PauseAnimation { duration: 1000 } + SetPropertyAction { value: "PreserveAspectCrop" } + SetPropertyAction { target: Label; property: "text"; value: "PreserveAspectCrop" } PauseAnimation { duration: 1000 } SetPropertyAction { value: "Tile" } SetPropertyAction { target: Label; property: "text"; value: "Tile" } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index ab91799..36b2e8b 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -254,11 +254,13 @@ bool QObjectPrivate::isSender(const QObject *receiver, const char *signal) const QMutexLocker locker(signalSlotLock(q)); if (connectionLists) { if (signal_index < connectionLists->count()) { - const ConnectionList &connectionList = connectionLists->at(signal_index); - for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection *c = connectionList.at(i); + const QObjectPrivate::Connection *c = + connectionLists->at(signal_index).first; + + while (c) { if (c->receiver == receiver) return true; + c = c->nextConnectionList; } } } @@ -276,11 +278,12 @@ QObjectList QObjectPrivate::receiverList(const char *signal) const QMutexLocker locker(signalSlotLock(q)); if (connectionLists) { if (signal_index < connectionLists->count()) { - const ConnectionList &connectionList = connectionLists->at(signal_index); - for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection *c = connectionList.at(i); + const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first; + + while (c) { if (c->receiver) returnValue << c->receiver; + c = c->nextConnectionList; } } } @@ -305,7 +308,13 @@ void QObjectPrivate::addConnection(int signal, Connection *c) connectionLists->resize(signal + 1); ConnectionList &connectionList = (*connectionLists)[signal]; - connectionList.append(c); + if (connectionList.last) { + connectionList.last->nextConnectionList = c; + } else { + connectionList.first = c; + } + connectionList.last = c; + cleanConnectionLists(); } @@ -314,14 +323,32 @@ void QObjectPrivate::cleanConnectionLists() if (connectionLists->dirty && !connectionLists->inUse) { // remove broken connections for (int signal = -1; signal < connectionLists->count(); ++signal) { - QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal]; - for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = connectionList.at(i); - if (!c->receiver) { + QObjectPrivate::ConnectionList &connectionList = + (*connectionLists)[signal]; + + // Set to the last entry in the connection list that was *not* + // deleted. This is needed to update the list's last pointer + // at the end of the cleanup. + QObjectPrivate::Connection *last = 0; + + QObjectPrivate::Connection **prev = &connectionList.first; + QObjectPrivate::Connection *c = *prev; + while (c) { + if (c->receiver) { + last = c; + prev = &c->nextConnectionList; + c = *prev; + } else { + QObjectPrivate::Connection *next = c->nextConnectionList; + *prev = next; delete c; - connectionList.removeAt(i--); + c = next; } } + + // Correct the connection list's last pointer. As + // conectionList.last could equal last, this could be a noop + connectionList.last = last; } connectionLists->dirty = false; } @@ -780,17 +807,19 @@ QObject::~QObject() if (d->connectionLists) { ++d->connectionLists->inUse; for (int signal = -1; signal < d->connectionLists->count(); ++signal) { - QObjectPrivate::ConnectionList &connectionList = (*d->connectionLists)[signal]; - for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = connectionList[i]; + QObjectPrivate::ConnectionList &connectionList = + (*d->connectionLists)[signal]; + + while (QObjectPrivate::Connection *c = connectionList.first) { if (!c->receiver) { + connectionList.first = c->nextConnectionList; delete c; continue; } QMutex *m = signalSlotLock(c->receiver); bool needToUnlock = QOrderedMutexLocker::relock(locker.mutex(), m); - c = connectionList[i]; + if (c->receiver) { *c->prev = c->next; if (c->next) c->next->prev = c->prev; @@ -798,6 +827,7 @@ QObject::~QObject() if (needToUnlock) m->unlock(); + connectionList.first = c->nextConnectionList; delete c; } } @@ -2403,11 +2433,11 @@ int QObject::receivers(const char *signal) const QMutexLocker locker(signalSlotLock(this)); if (d->connectionLists) { if (signal_index < d->connectionLists->count()) { - const QObjectPrivate::ConnectionList &connectionList = - d->connectionLists->at(signal_index); - for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection *c = connectionList.at(i); + const QObjectPrivate::Connection *c = + d->connectionLists->at(signal_index).first; + while (c) { receivers += c->receiver ? 1 : 0; + c = c->nextConnectionList; } } } @@ -2852,11 +2882,13 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, if (type & Qt::UniqueConnection) { QObjectConnectionListVector *connectionLists = s->d_func()->connectionLists; if (connectionLists && connectionLists->count() > signal_index) { - QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; - for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c2 = connectionList.at(i); + const QObjectPrivate::Connection *c2 = + (*connectionLists)[signal_index].first; + + while (c2) { if (c2->receiver == receiver && c2->method == method_index) return false; + c2 = c2->nextConnectionList; } } type &= Qt::UniqueConnection - 1; @@ -2868,6 +2900,7 @@ bool QMetaObject::connect(const QObject *sender, int signal_index, c->method = method_index; c->connectionType = type; c->argumentTypes = types; + c->nextConnectionList = 0; c->prev = &r->d_func()->senders; c->next = *c->prev; *c->prev = c; @@ -2917,9 +2950,9 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, if (signal_index < 0) { // remove from all connection lists for (signal_index = -1; signal_index < connectionLists->count(); ++signal_index) { - QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; - for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = connectionList[i]; + QObjectPrivate::Connection *c = + (*connectionLists)[signal_index].first; + while (c) { if (c->receiver && (r == 0 || (c->receiver == r && (method_index < 0 || c->method == method_index)))) { @@ -2928,7 +2961,6 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, if (!receiverMutex && senderMutex != m) { // need to relock this receiver and sender in the correct order needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); - c = connectionList[i]; } if (c->receiver) { *c->prev = c->next; @@ -2943,12 +2975,13 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, success = true; connectionLists->dirty = true; } + c = c->nextConnectionList; } } } else if (signal_index < connectionLists->count()) { - QObjectPrivate::ConnectionList &connectionList = (*connectionLists)[signal_index]; - for (int i = 0; i < connectionList.count(); ++i) { - QObjectPrivate::Connection *c = connectionList[i]; + QObjectPrivate::Connection *c = + (*connectionLists)[signal_index].first; + while (c) { if (c->receiver && (r == 0 || (c->receiver == r && (method_index < 0 || c->method == method_index)))) { @@ -2957,7 +2990,6 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, if (!receiverMutex && senderMutex != m) { // need to relock this receiver and sender in the correct order needToUnlock = QOrderedMutexLocker::relock(senderMutex, m); - c = connectionList[i]; } if (c->receiver) { *c->prev = c->next; @@ -2971,6 +3003,7 @@ bool QMetaObject::disconnect(const QObject *sender, int signal_index, success = true; connectionLists->dirty = true; } + c = c->nextConnectionList; } } @@ -3135,9 +3168,14 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal signal = to_signal_index; continue; } - int count = connectionLists->at(signal).count(); - for (int i = 0; i < count; ++i) { - QObjectPrivate::Connection *c = connectionLists->at(signal)[i]; + + QObjectPrivate::Connection *c = connectionLists->at(signal).first; + if (!c) continue; + // We need to check against last here to ensure that signals added + // during the signal emission are not emitted in this emission. + QObjectPrivate::Connection *last = connectionLists->at(signal).last; + + do { if (!c->receiver) continue; @@ -3199,7 +3237,7 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal if (connectionLists->orphaned) break; - } + } while (c != last && (c = c->nextConnectionList) != 0); if (connectionLists->orphaned) break; @@ -3518,11 +3556,12 @@ void QObject::dumpObjectInfo() qDebug(" signal: %s", signal.signature()); // receivers - const QObjectPrivate::ConnectionList &connectionList = d->connectionLists->at(signal_index); - for (int i = 0; i < connectionList.count(); ++i) { - const QObjectPrivate::Connection *c = connectionList.at(i); + const QObjectPrivate::Connection *c = + d->connectionLists->at(signal_index).first; + while (c) { if (!c->receiver) { qDebug(" <Disconnected receiver>"); + c = c->nextConnectionList; continue; } const QMetaObject *receiverMetaObject = c->receiver->metaObject(); @@ -3531,6 +3570,7 @@ void QObject::dumpObjectInfo() receiverMetaObject->className(), c->receiver->objectName().isEmpty() ? "unnamed" : qPrintable(c->receiver->objectName()), method.signature()); + c = c->nextConnectionList; } } } else { diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h index e908753..d1a2714 100644 --- a/src/corelib/kernel/qobject_p.h +++ b/src/corelib/kernel/qobject_p.h @@ -163,12 +163,19 @@ public: int method; uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking QBasicAtomicPointer<int> argumentTypes; + // The next pointer for the singly-linked ConnectionList + Connection *nextConnectionList; //senders linked list Connection *next; Connection **prev; ~Connection(); }; - typedef QList<Connection *> ConnectionList; + // ConnectionList is a singly-linked list + struct ConnectionList { + ConnectionList() : first(0), last(0) {} + Connection *first; + Connection *last; + }; QObjectConnectionListVector *connectionLists; void addConnection(int signal, Connection *c); diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 2b5ea0a..4166944 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -161,6 +161,9 @@ static void construct(QVariant::Private *x, const void *copy) case QMetaType::Float: x->data.f = copy ? *static_cast<const float*>(copy) : 0.0f; break; + case QMetaType::QObjectStar: + x->data.o = copy ? *static_cast<QObject *const*>(copy) : 0; + break; case QVariant::LongLong: x->data.ll = copy ? *static_cast<const qlonglong *>(copy) : Q_INT64_C(0); break; @@ -257,6 +260,7 @@ static void clear(QVariant::Private *d) case QVariant::ULongLong: case QVariant::Double: case QMetaType::Float: + case QMetaType::QObjectStar: break; case QVariant::Invalid: case QVariant::UserType: @@ -326,6 +330,7 @@ static bool isNull(const QVariant::Private *d) case QVariant::Bool: case QVariant::Double: case QMetaType::Float: + case QMetaType::QObjectStar: break; } return d->is_null; @@ -419,6 +424,8 @@ static bool compare(const QVariant::Private *a, const QVariant::Private *b) return a->data.d == b->data.d; case QMetaType::Float: return a->data.f == b->data.f; + case QMetaType::QObjectStar: + return a->data.o == b->data.o; case QVariant::Date: return *v_cast<QDate>(a) == *v_cast<QDate>(b); case QVariant::Time: @@ -1048,6 +1055,9 @@ static void streamDebug(QDebug dbg, const QVariant &v) case QMetaType::Float: dbg.nospace() << qVariantValue<float>(v); break; + case QMetaType::QObjectStar: + dbg.nospace() << qVariantValue<QObject *>(v); + break; case QVariant::Double: dbg.nospace() << v.toDouble(); break; @@ -1361,7 +1371,7 @@ void QVariant::create(int type, const void *copy) QVariant::~QVariant() { - if (d.type > Char && d.type != QMetaType::Float && (!d.is_shared || !d.data.shared->ref.deref())) + if (d.type > Char && d.type != QMetaType::Float && d.type != QMetaType::QObjectStar && (!d.is_shared || !d.data.shared->ref.deref())) handler->clear(&d); } @@ -1377,7 +1387,7 @@ QVariant::QVariant(const QVariant &p) { if (d.is_shared) { d.data.shared->ref.ref(); - } else if (p.d.type > Char && p.d.type != QMetaType::Float) { + } else if (p.d.type > Char && p.d.type != QMetaType::Float && p.d.type != QMetaType::QObjectStar) { handler->construct(&d, p.constData()); d.is_null = p.d.is_null; } @@ -1733,7 +1743,7 @@ QVariant& QVariant::operator=(const QVariant &variant) if (variant.d.is_shared) { variant.d.data.shared->ref.ref(); d = variant.d; - } else if (variant.d.type > Char && variant.d.type != QMetaType::Float) { + } else if (variant.d.type > Char && variant.d.type != QMetaType::Float && variant.d.type != QMetaType::QObjectStar) { d.type = variant.d.type; handler->construct(&d, variant.constData()); d.is_null = variant.d.is_null; diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index a68939d..4489e95 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -358,6 +358,7 @@ class Q_CORE_EXPORT QVariant float f; qlonglong ll; qulonglong ull; + QObject *o; void *ptr; PrivateShared *shared; } data; diff --git a/src/declarative/extra/qfxparticles.cpp b/src/declarative/extra/qfxparticles.cpp index 26c176b..f05f233 100644 --- a/src/declarative/extra/qfxparticles.cpp +++ b/src/declarative/extra/qfxparticles.cpp @@ -53,6 +53,7 @@ #include <qfxpixmap.h> #include <private/qfxperf_p.h> #include <private/qmlanimation_p.h> +#include <QNetworkReply> #include "qfxparticles.h" #include <QPainter> @@ -404,6 +405,7 @@ public: bool emitting; QFxParticleMotion *motion; QFxParticlesPainter *paintItem; + QPointer<QNetworkReply> reply; QList<QFxParticle> particles; QTickAnimationProxy<QFxParticlesPrivate, &QFxParticlesPrivate::tick> clock; @@ -636,7 +638,7 @@ QUrl QFxParticles::source() const void QFxParticles::imageLoaded() { Q_D(QFxParticles); - d->image = QFxPixmap(d->url); + QFxPixmap::find(d->url, &d->image); d->paintItem->updateSize(); d->paintItem->update(); } @@ -645,7 +647,7 @@ void QFxParticles::setSource(const QUrl &name) { Q_D(QFxParticles); - if (name == d->url) + if ((d->url.isEmpty() == name.isEmpty()) && name == d->url) return; if (!d->url.isEmpty()) @@ -658,7 +660,14 @@ void QFxParticles::setSource(const QUrl &name) } else { d->url = name; Q_ASSERT(!name.isRelative()); - QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(imageLoaded())); + d->reply = QFxPixmap::get(qmlEngine(this), d->url, &d->image); + if (d->reply) + connect(d->reply, SIGNAL(finished()), this, SLOT(imageLoaded())); + else { + //### unify with imageLoaded + d->paintItem->updateSize(); + d->paintItem->update(); + } } } diff --git a/src/declarative/fx/fx.pri b/src/declarative/fx/fx.pri index d2b97d6..8b37009 100644 --- a/src/declarative/fx/fx.pri +++ b/src/declarative/fx/fx.pri @@ -9,9 +9,13 @@ HEADERS += \ fx/qfxflipable.h \ fx/qfxgridview.h \ fx/qfximage.h \ + fx/qfximagebase.h \ + fx/qfxborderimage.h \ fx/qfxpainteditem.h \ fx/qfxpainteditem_p.h \ fx/qfximage_p.h \ + fx/qfxborderimage_p.h \ + fx/qfximagebase_p.h \ fx/qfxitem.h \ fx/qfxitem_p.h \ fx/qfxfocusscope.h \ @@ -51,6 +55,8 @@ SOURCES += \ fx/qfxflipable.cpp \ fx/qfxgridview.cpp \ fx/qfximage.cpp \ + fx/qfxborderimage.cpp \ + fx/qfximagebase.cpp \ fx/qfxpainteditem.cpp \ fx/qfxitem.cpp \ fx/qfxfocusscope.cpp \ diff --git a/src/declarative/fx/qfxborderimage.cpp b/src/declarative/fx/qfxborderimage.cpp new file mode 100644 index 0000000..adb70a3 --- /dev/null +++ b/src/declarative/fx/qfxborderimage.cpp @@ -0,0 +1,410 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfxborderimage.h" +#include "qfxborderimage_p.h" +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QFile> +#include <QtDeclarative/qmlengine.h> + +QT_BEGIN_NAMESPACE + +QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,BorderImage,QFxBorderImage) + +/*! + \qmlclass BorderImage QFxBorderImage + \brief The BorderImage element allows you use an image as a border. + \inherits Item + + Example: + \qml + BorderImage { border.left: 20; border.right: 10 + border.top: 14; border.bottom: 14 + width: 160; height: 160 + source: "pics/qtlogo.png" + } + \endqml + */ + +/*! + \internal + \class QFxBorderImage BorderImage + \brief The QFxBorderImage class provides an image item that you can add to a QFxView. + + \ingroup group_coreitems + + Example: + \qml + BorderImage { source: "pics/star.png" } + \endqml + + A QFxBorderImage object can be instantiated in Qml using the tag \l BorderImage. +*/ + +QFxBorderImage::QFxBorderImage(QFxItem *parent) + : QFxImageBase(*(new QFxBorderImagePrivate), parent) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); +} + +QFxBorderImage::~QFxBorderImage() +{ + Q_D(QFxBorderImage); + if (d->sciReply) + d->sciReply->deleteLater(); + if (!d->sciurl.isEmpty()) + QFxPixmap::cancelGet(d->sciurl, this); +} +/*! + \qmlproperty enum BorderImage::status + + This property holds the status of image loading. It can be one of: + \list + \o Null - no image has been set + \o Ready - the image has been loaded + \o Loading - the image is currently being loaded + \o Error - an error occurred while loading the image + \endlist + + \sa progress +*/ + +/*! + \qmlproperty real BorderImage::progress + + This property holds the progress of image loading, from 0.0 (nothing loaded) + to 1.0 (finished). + + \sa status +*/ + +/*! + \qmlproperty bool BorderImage::smooth + + Set this property if you want the image to be smoothly filtered when scaled or + transformed. Smooth filtering gives better visual quality, but is slower. If + the image is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the image is stationary on + the screen. A common pattern when animating an image is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + +/*! + \qmlproperty url BorderImage::source + + BorderImage can handle any image format supported by Qt, loaded from any URL scheme supported by Qt. + + It can also handle .sci files, which are a Qml-specific format. A .sci file uses a simple text-based format that specifies + \list + \i the grid lines describing a \l {BorderImage::border.left}{scale grid}. + \i an image file. + \endlist + + The following .sci file sets grid line offsets of 10 on each side for the image \c picture.png: + \code + gridLeft: 10 + gridTop: 10 + gridBottom: 10 + gridRight: 10 + imageFile: picture.png + \endcode + + The URL may be absolute, or relative to the URL of the component. +*/ + +void QFxBorderImage::setSource(const QUrl &url) +{ + Q_D(QFxBorderImage); + //equality is fairly expensive, so we bypass for simple, common case + if ((d->url.isEmpty() == url.isEmpty()) && url == d->url) + return; + + if (d->sciReply) { + d->sciReply->deleteLater(); + d->sciReply = 0; + } + + if (!d->url.isEmpty()) + QFxPixmap::cancelGet(d->url, this); + if (!d->sciurl.isEmpty()) + QFxPixmap::cancelGet(d->sciurl, this); + + d->url = url; + d->sciurl = QUrl(); + if (d->progress != 0.0) { + d->progress = 0.0; + emit progressChanged(d->progress); + } + + if (url.isEmpty()) { + d->pix = QPixmap(); + d->status = Null; + d->progress = 1.0; + setImplicitWidth(0); + setImplicitHeight(0); + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); + } else { + d->status = Loading; + if (d->url.path().endsWith(QLatin1String(".sci"))) { +#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML + if (d->url.scheme() == QLatin1String("file")) { + QFile file(d->url.toLocalFile()); + file.open(QIODevice::ReadOnly); + setGridScaledImage(QFxGridScaledImage(&file)); + } else +#endif + { + QNetworkRequest req(d->url); + req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); + d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); + QObject::connect(d->sciReply, SIGNAL(finished()), + this, SLOT(sciRequestFinished())); + } + } else { + d->reply = QFxPixmap::get(qmlEngine(this), d->url, &d->pix); + if (d->reply) { + connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished())); + connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + } else { + //### should be unified with requestFinished + setImplicitWidth(d->pix.width()); + setImplicitHeight(d->pix.height()); + + if (d->status == Loading) + d->status = Ready; + d->progress = 1.0; + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); + } + } + } + + emit statusChanged(d->status); +} + +/*! + \qmlproperty int BorderImage::border.left + \qmlproperty int BorderImage::border.right + \qmlproperty int BorderImage::border.top + \qmlproperty int BorderImage::border.bottom + + \target ImagexmlpropertiesscaleGrid + + The 4 border lines (2 horizontal and 2 vertical) break an image into 9 sections, as shown below: + + \image declarative-scalegrid.png + + When the image is scaled: + \list + \i the corners (sections 1, 3, 7, and 9) are not scaled at all + \i the middle (section 5) is scaled according to BorderImage::horizontalTileMode and BorderImage::verticalTileMode + \i sections 2 and 8 are scaled according to BorderImage::horizontalTileMode + \i sections 4 and 6 are scaled according to BorderImage::verticalTileMode + \endlist + + Each border line (left, right, top, and bottom) specifies an offset from the respective side. For example, \c{border.bottom: 10} sets the bottom line 10 pixels up from the bottom of the image. + + The border lines can also be specified using a + \l {BorderImage::source}{.sci file}. +*/ + +QFxScaleGrid *QFxBorderImage::border() +{ + Q_D(QFxBorderImage); + return d->getScaleGrid(); +} + +/*! + \qmlproperty TileMode BorderImage::horizontalTileMode + \qmlproperty TileMode BorderImage::verticalTileMode + + This property describes how to repeat or stretch the middle parts of the border image. + + \list + \o Stretch - Scale the image to fit to the available area. + \o Repeat - Tile the image until there is no more space. May crop the last image. + \o Round - Like Repeat, but scales the images down to ensure that the last image is not cropped. + \endlist + + \sa examples/declarative/border-image +*/ +QFxBorderImage::TileMode QFxBorderImage::horizontalTileMode() const +{ + Q_D(const QFxBorderImage); + return d->horizontalTileMode; +} + +void QFxBorderImage::setHorizontalTileMode(TileMode t) +{ + Q_D(QFxBorderImage); + d->horizontalTileMode = t; +} + +QFxBorderImage::TileMode QFxBorderImage::verticalTileMode() const +{ + Q_D(const QFxBorderImage); + return d->verticalTileMode; +} + +void QFxBorderImage::setVerticalTileMode(TileMode t) +{ + Q_D(QFxBorderImage); + d->verticalTileMode = t; +} + +void QFxBorderImage::setGridScaledImage(const QFxGridScaledImage& sci) +{ + Q_D(QFxBorderImage); + if (!sci.isValid()) { + d->status = Error; + emit statusChanged(d->status); + } else { + QFxScaleGrid *sg = border(); + sg->setTop(sci.gridTop()); + sg->setBottom(sci.gridBottom()); + sg->setLeft(sci.gridLeft()); + sg->setRight(sci.gridRight()); + d->horizontalTileMode = sci.horizontalTileRule(); + d->verticalTileMode = sci.verticalTileRule(); + + d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); + d->reply = QFxPixmap::get(qmlEngine(this), d->sciurl, &d->pix); + if (d->reply) { + connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished())); + connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + } else { + //### should be unified with requestFinished + setImplicitWidth(d->pix.width()); + setImplicitHeight(d->pix.height()); + + if (d->status == Loading) + d->status = Ready; + d->progress = 1.0; + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); + } + } +} + +void QFxBorderImage::requestFinished() +{ + Q_D(QFxBorderImage); + if (d->url.path().endsWith(QLatin1String(".sci"))) { + QFxPixmap::find(d->sciurl, &d->pix); + } else { + if (d->reply) { + //###disconnect really needed? + disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + if (d->reply->error() != QNetworkReply::NoError) + d->status = Error; + } + QFxPixmap::find(d->url, &d->pix); + } + setImplicitWidth(d->pix.width()); + setImplicitHeight(d->pix.height()); + + if (d->status == Loading) + d->status = Ready; + d->progress = 1.0; + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); +} + +void QFxBorderImage::sciRequestFinished() +{ + Q_D(QFxBorderImage); + if (d->sciReply->error() != QNetworkReply::NoError) { + d->status = Error; + d->sciReply->deleteLater(); + d->sciReply = 0; + emit statusChanged(d->status); + } else { + QFxGridScaledImage sci(d->sciReply); + d->sciReply->deleteLater(); + d->sciReply = 0; + setGridScaledImage(sci); + } +} + +void QFxBorderImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) +{ + Q_D(QFxBorderImage); + if (d->pix.isNull()) + return; + + bool oldAA = p->testRenderHint(QPainter::Antialiasing); + bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); + if (d->smooth) + p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); + + QPixmap pix = d->pix; + + QMargins margins(border()->top(), border()->left(), border()->bottom(), border()->right()); + QTileRules rules((Qt::TileRule)d->horizontalTileMode, (Qt::TileRule)d->verticalTileMode); + qDrawBorderPixmap(p, QRect(0, 0, (int)d->width, (int)d->height), margins, pix, pix.rect(), margins, rules); + if (d->smooth) { + p->setRenderHint(QPainter::Antialiasing, oldAA); + p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); + } +} + +QFxBorderImage::QFxBorderImage(QFxBorderImagePrivate &dd, QFxItem *parent) + : QFxImageBase(dd, parent) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); +} + +QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxborderimage.h b/src/declarative/fx/qfxborderimage.h new file mode 100644 index 0000000..b0ec3bc --- /dev/null +++ b/src/declarative/fx/qfxborderimage.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXBORDERIMAGE_H +#define QFXBORDERIMAGE_H + +#include <QtNetwork/qnetworkreply.h> +#include "qfximagebase.h" + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QFxScaleGrid; +class QFxGridScaledImage; +class QFxBorderImagePrivate; +class Q_DECLARATIVE_EXPORT QFxBorderImage : public QFxImageBase +{ + Q_OBJECT + Q_ENUMS(TileMode) + + Q_PROPERTY(QFxScaleGrid *border READ border CONSTANT) + Q_PROPERTY(TileMode horizontalTileMode READ horizontalTileMode WRITE setHorizontalTileMode) + Q_PROPERTY(TileMode verticalTileMode READ verticalTileMode WRITE setVerticalTileMode) + +public: + QFxBorderImage(QFxItem *parent=0); + ~QFxBorderImage(); + + QFxScaleGrid *border(); + + enum TileMode { Stretch = Qt::Stretch, Repeat = Qt::Repeat, Round = Qt::Round }; + + TileMode horizontalTileMode() const; + void setHorizontalTileMode(TileMode); + + TileMode verticalTileMode() const; + void setVerticalTileMode(TileMode); + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + void setSource(const QUrl &url); + +protected: + QFxBorderImage(QFxBorderImagePrivate &dd, QFxItem *parent); + +private: + void setGridScaledImage(const QFxGridScaledImage& sci); + +private Q_SLOTS: + void requestFinished(); + void sciRequestFinished(); + +private: + Q_DISABLE_COPY(QFxBorderImage) + Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QFxBorderImage) +}; + +QT_END_NAMESPACE +QML_DECLARE_TYPE(QFxBorderImage) +QT_END_HEADER + +#endif // QFXBORDERIMAGE_H diff --git a/src/declarative/fx/qfxborderimage_p.h b/src/declarative/fx/qfxborderimage_p.h new file mode 100644 index 0000000..104f0f3 --- /dev/null +++ b/src/declarative/fx/qfxborderimage_p.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXBORDERIMAGE_P_H +#define QFXBORDERIMAGE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfximagebase_p.h" +#include "qfxscalegrid_p.h" + +QT_BEGIN_NAMESPACE + +class QNetworkReply; +class QFxBorderImagePrivate : public QFxImageBasePrivate +{ + Q_DECLARE_PUBLIC(QFxBorderImage) + +public: + QFxBorderImagePrivate() + : border(0), sciReply(0), + horizontalTileMode(QFxBorderImage::Stretch), + verticalTileMode(QFxBorderImage::Stretch) + { + } + + ~QFxBorderImagePrivate() + { + } + + QFxScaleGrid *getScaleGrid() + { + if (!border) + border = new QFxScaleGrid; + return border; + } + + QFxScaleGrid *border; + QUrl sciurl; + QNetworkReply *sciReply; + QFxBorderImage::TileMode horizontalTileMode; + QFxBorderImage::TileMode verticalTileMode; +}; + +QT_END_NAMESPACE + +#endif // QFXBORDERIMAGE_P_H diff --git a/src/declarative/fx/qfximage.cpp b/src/declarative/fx/qfximage.cpp index 792b015..ec3fdab 100644 --- a/src/declarative/fx/qfximage.cpp +++ b/src/declarative/fx/qfximage.cpp @@ -41,11 +41,6 @@ #include "qfximage.h" #include "qfximage_p.h" -#include <private/qfxperf_p.h> -#include <QNetworkRequest> -#include <QNetworkReply> -#include <QFile> -#include <QtDeclarative/qmlengine.h> #include <QKeyEvent> #include <QPainter> @@ -60,13 +55,10 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Image,QFxImage) \brief The Image element allows you to add bitmaps to a scene. \inherits Item - The Image element supports untransformed, stretched, tiled, and grid-scaled images. + The Image element supports untransformed, stretched and tiled. For an explanation of stretching and tiling, see the fillMode property description. - For an explanation of grid-scaling see the scaleGrid property description - or the QFxScaleGrid class description. - Examples: \table \row @@ -86,16 +78,6 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Image,QFxImage) } \endqml \row - \o \image declarative-qtlogo4.png - \o Grid-scaled (only with fillMode: Stretch) - \qml - Image { scaleGrid.left: 20; scaleGrid.right: 10 - scaleGrid.top: 14; scaleGrid.bottom: 14 - width: 160; height: 160 - source: "pics/qtlogo.png" - } - \endqml - \row \o \image declarative-qtlogo3.png \o fillMode: Tile \qml @@ -144,33 +126,26 @@ QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Image,QFxImage) */ QFxImage::QFxImage(QFxItem *parent) - : QFxItem(*(new QFxImagePrivate), parent) + : QFxImageBase(*(new QFxImagePrivate), parent) { setFlag(QGraphicsItem::ItemHasNoContents, false); } QFxImage::QFxImage(QFxImagePrivate &dd, QFxItem *parent) - : QFxItem(dd, parent) + : QFxImageBase(dd, parent) { setFlag(QGraphicsItem::ItemHasNoContents, false); } QFxImage::~QFxImage() { - Q_D(QFxImage); - if (d->sciReply) - d->sciReply->deleteLater(); - if (!d->url.isEmpty()) - QFxPixmap::cancelGet(d->url, this); - if (!d->sciurl.isEmpty()) - QFxPixmap::cancelGet(d->sciurl, this); } /*! - \property QFxImage::image + \property QFxImage::pixmap \brief the image displayed in this item. - This property contains the image currently being displayed by this item, + This property contains the pixmap currently being displayed by this item, which may be empty if nothing is currently displayed. Setting the source property overrides any setting of this property. */ @@ -194,37 +169,6 @@ void QFxImage::setPixmap(const QPixmap &pix) } /*! - \qmlproperty int Image::scaleGrid.left - \qmlproperty int Image::scaleGrid.right - \qmlproperty int Image::scaleGrid.top - \qmlproperty int Image::scaleGrid.bottom - - \target ImagexmlpropertiesscaleGrid - - A scale grid uses 4 grid lines (2 horizontal and 2 vertical) to break an image into 9 sections, as shown below: - - \image declarative-scalegrid.png - - When the image is scaled: - \list - \i the corners (sections 1, 3, 7, and 9) are not scaled at all - \i the middle (section 5) is scaled both horizontally and vertically - \i sections 2 and 8 are scaled horizontally - \i sections 4 and 6 are scaled vertically - \endlist - - Each scale grid property (left, right, top, and bottom) specifies an offset from the respective side. For example, \c scaleGrid.bottom="10" sets the bottom scale grid line 10 pixels up from the bottom of the image. - - A scale grid can also be specified using a - \l {Image::source}{.sci file}. -*/ -QFxScaleGrid *QFxImage::scaleGrid() -{ - Q_D(QFxImage); - return d->getScaleGrid(); -} - -/*! \qmlproperty FillMode Image::fillMode Set this property to define what happens when the image set for the item is smaller @@ -232,17 +176,15 @@ QFxScaleGrid *QFxImage::scaleGrid() \list \o Stretch - the image is scaled to fit - \o PreserveAspect - the image is scaled uniformly to fit + \o PreserveAspectFit - the image is scaled uniformly to fit without cropping + \o PreserveAspectCrop - the image is scaled uniformly to fill, cropping if necessary \o Tile - the image is duplicated horizontally and vertically \o TileVertically - the image is stretched horizontally and tiled vertically \o TileHorizontally - the image is stretched vertically and tiled horizontally \endlist \image declarative-image_fillMode.gif - - Only fillMode: Stretch can be used with scaleGrid. Other settings - will cause a run-time warning. - + \sa examples/declarative/fillmode \sa examples/declarative/aspectratio */ QFxImage::FillMode QFxImage::fillMode() const @@ -261,105 +203,6 @@ void QFxImage::setFillMode(FillMode mode) emit fillModeChanged(); } -void QFxImage::componentComplete() -{ - QFxItem::componentComplete(); -} - -/*! - \property QFxImage::scaleGrid - \brief the 3x3 grid used to scale an image, excluding the corners. -*/ - -void QFxImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) -{ - Q_D(QFxImage); - if (d->pix.isNull()) - return; - - bool oldAA = p->testRenderHint(QPainter::Antialiasing); - bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); - if (d->smooth) - p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); - - QPixmap pix = d->pix; - - if (!d->scaleGrid || d->scaleGrid->isNull()) { - if (width() != pix.width() || height() != pix.height()) { - if (d->fillMode >= Tile) { - p->save(); - p->setClipRect(0, 0, width(), height(), Qt::IntersectClip); - - if (d->fillMode == Tile) { - const int pw = pix.width(); - const int ph = pix.height(); - int yy = 0; - - while(yy < height()) { - int xx = 0; - while(xx < width()) { - p->drawPixmap(xx, yy, pix); - xx += pw; - } - yy += ph; - } - } else if (d->fillMode == TileVertically) { - const int ph = pix.height(); - int yy = 0; - - while(yy < height()) { - p->drawPixmap(QRect(0, yy, width(), ph), pix); - yy += ph; - } - } else { - const int pw = pix.width(); - int xx = 0; - - while(xx < width()) { - p->drawPixmap(QRect(xx, 0, pw, height()), pix); - xx += pw; - } - } - - p->restore(); - } else { - qreal widthScale = width() / qreal(pix.width()); - qreal heightScale = height() / qreal(pix.height()); - - QTransform scale; - - if (d->fillMode == PreserveAspect) { - if (widthScale < heightScale) { - heightScale = widthScale; - scale.translate(0, (height() - heightScale * pix.height()) / 2); - } else if(heightScale < widthScale) { - widthScale = heightScale; - scale.translate((width() - widthScale * pix.width()) / 2, 0); - } - } - - scale.scale(widthScale, heightScale); - QTransform old = p->transform(); - p->setWorldTransform(scale * old); - p->drawPixmap(0, 0, pix); - p->setWorldTransform(old); - } - } else { - p->drawPixmap(0, 0, pix); - } - } else { - QMargins margins(d->scaleGrid->top(), d->scaleGrid->left(), d->scaleGrid->bottom(), d->scaleGrid->right()); - QTileRules rules((Qt::TileRule)d->scaleGrid->horizontalTileRule(), - (Qt::TileRule)d->scaleGrid->verticalTileRule()); - qDrawBorderPixmap(p, QRect(0, 0, (int)d->width, (int)d->height), margins, pix, pix.rect(), margins, rules); - } - - if (d->smooth) { - p->setRenderHint(QPainter::Antialiasing, oldAA); - p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); - } -} - /*! \qmlproperty enum Image::status @@ -374,12 +217,6 @@ void QFxImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) \sa progress */ -QFxImage::Status QFxImage::status() const -{ - Q_D(const QFxImage); - return d->status; -} - /*! \qmlproperty real Image::progress @@ -389,193 +226,115 @@ QFxImage::Status QFxImage::status() const \sa status */ -qreal QFxImage::progress() const -{ - Q_D(const QFxImage); - return d->progress; -} - /*! - \qmlproperty url Image::source - - Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt. + \qmlproperty bool Image::smooth - It can also handle .sci files, which are a Qml-specific format. A .sci file uses a simple text-based format that specifies - \list - \i the grid lines describing a \l {Image::scaleGrid.left}{scale grid}. - \i an image file. - \endlist - - The following .sci file sets grid line offsets of 10 on each side for the image \c picture.png: - \code - gridLeft: 10 - gridTop: 10 - gridBottom: 10 - gridRight: 10 - imageFile: picture.png - \endcode + Set this property if you want the image to be smoothly filtered when scaled or + transformed. Smooth filtering gives better visual quality, but is slower. If + the image is displayed at its natural size, this property has no visual or + performance effect. - The URL may be absolute, or relative to the URL of the component. + \note Generally scaling artifacts are only visible if the image is stationary on + the screen. A common pattern when animating an image is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. */ /*! - \property QFxImage::source - \brief the url of the image to be displayed in this item. + \qmlproperty url Image::source - The content specified can be of any image type loadable by QImage. Alternatively, - you can specify an sci format file, which specifies both an image and it's scale grid. + Image can handle any image format supported by Qt, loaded from any URL scheme supported by Qt. + + The URL may be absolute, or relative to the URL of the component. */ -QUrl QFxImage::source() const -{ - Q_D(const QFxImage); - return d->url; -} -void QFxImage::setSource(const QUrl &url) +void QFxImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) { -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer<QFxPerf::PixmapLoad> perf; -#endif Q_D(QFxImage); - if (url == d->url) + if (d->pix.isNull()) return; - if (d->sciReply) { - d->sciReply->deleteLater(); - d->sciReply = 0; - } + bool oldAA = p->testRenderHint(QPainter::Antialiasing); + bool oldSmooth = p->testRenderHint(QPainter::SmoothPixmapTransform); + if (d->smooth) + p->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, d->smooth); - if (!d->url.isEmpty()) - QFxPixmap::cancelGet(d->url, this); - if (!d->sciurl.isEmpty()) - QFxPixmap::cancelGet(d->sciurl, this); - - d->url = url; - d->sciurl = QUrl(); - if (d->progress != 0.0) { - d->progress = 0.0; - emit progressChanged(d->progress); - } + QPixmap pix = d->pix; - if (url.isEmpty()) { - d->pix = QPixmap(); - d->status = Null; - d->progress = 1.0; - setImplicitWidth(0); - setImplicitHeight(0); - emit statusChanged(d->status); - emit sourceChanged(d->url); - emit progressChanged(1.0); - update(); - } else { - d->status = Loading; - if (d->url.path().endsWith(QLatin1String(".sci"))) { -#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML - if (d->url.scheme() == QLatin1String("file")) { - QFile file(d->url.toLocalFile()); - file.open(QIODevice::ReadOnly); - setGridScaledImage(QFxGridScaledImage(&file)); - } else -#endif - { - QNetworkRequest req(d->url); - req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache); - d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); - QObject::connect(d->sciReply, SIGNAL(finished()), - this, SLOT(sciRequestFinished())); - } - } else { - d->reply = QFxPixmap::get(qmlEngine(this), d->url, this, SLOT(requestFinished())); - if (d->reply) { - connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); + if (width() != pix.width() || height() != pix.height()) { + if (d->fillMode >= Tile) { + p->save(); + p->setClipRect(0, 0, width(), height(), Qt::IntersectClip); + + if (d->fillMode == Tile) { + const int pw = pix.width(); + const int ph = pix.height(); + int yy = 0; + + while(yy < height()) { + int xx = 0; + while(xx < width()) { + p->drawPixmap(xx, yy, pix); + xx += pw; + } + yy += ph; + } + } else if (d->fillMode == TileVertically) { + const int ph = pix.height(); + int yy = 0; + + while(yy < height()) { + p->drawPixmap(QRect(0, yy, width(), ph), pix); + yy += ph; + } } else { - d->progress = 1.0; - emit progressChanged(d->progress); + const int pw = pix.width(); + int xx = 0; + + while(xx < width()) { + p->drawPixmap(QRect(xx, 0, pw, height()), pix); + xx += pw; + } } - } - } - emit statusChanged(d->status); -} + p->restore(); + } else { + qreal widthScale = width() / qreal(pix.width()); + qreal heightScale = height() / qreal(pix.height()); + + QTransform scale; + + if (d->fillMode == PreserveAspectFit) { + if (widthScale < heightScale) { + heightScale = widthScale; + scale.translate(0, (height() - heightScale * pix.height()) / 2); + } else if(heightScale < widthScale) { + widthScale = heightScale; + scale.translate((width() - widthScale * pix.width()) / 2, 0); + } + } else if (d->fillMode == PreserveAspectCrop) { + if (widthScale < heightScale) { + widthScale = heightScale; + scale.translate((width() - widthScale * pix.width()) / 2, 0); + } else if(heightScale < widthScale) { + heightScale = widthScale; + scale.translate(0, (height() - heightScale * pix.height()) / 2); + } + } -void QFxImage::requestFinished() -{ - Q_D(QFxImage); - if (d->url.path().endsWith(QLatin1String(".sci"))) { - d->pix = QFxPixmap(d->sciurl); - } else { - if (d->reply) { - disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); - if (d->reply->error() != QNetworkReply::NoError) - d->status = Error; + scale.scale(widthScale, heightScale); + QTransform old = p->transform(); + p->setWorldTransform(scale * old); + p->drawPixmap(0, 0, pix); + p->setWorldTransform(old); } - d->pix = QFxPixmap(d->url); - } - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); - - if (d->status == Loading) - d->status = Ready; - d->progress = 1.0; - emit statusChanged(d->status); - emit sourceChanged(d->url); - emit progressChanged(1.0); - update(); -} - -void QFxImage::sciRequestFinished() -{ - Q_D(QFxImage); - if (d->sciReply->error() != QNetworkReply::NoError) { - d->status = Error; - d->sciReply->deleteLater(); - d->sciReply = 0; - emit statusChanged(d->status); } else { - QFxGridScaledImage sci(d->sciReply); - d->sciReply->deleteLater(); - d->sciReply = 0; - setGridScaledImage(sci); + p->drawPixmap(0, 0, pix); } -} - -void QFxImage::requestProgress(qint64 received, qint64 total) -{ - Q_D(QFxImage); - if (d->status == Loading && total > 0) { - d->progress = qreal(received)/total; - emit progressChanged(d->progress); - } -} -void QFxImage::setGridScaledImage(const QFxGridScaledImage& sci) -{ - Q_D(QFxImage); - if (!sci.isValid()) { - d->status = Error; - emit statusChanged(d->status); - } else { - QFxScaleGrid *sg = scaleGrid(); - sg->setTop(sci.gridTop()); - sg->setBottom(sci.gridBottom()); - sg->setLeft(sci.gridLeft()); - sg->setRight(sci.gridRight()); - sg->setHorizontalTileRule(sci.horizontalTileRule()); - sg->setVerticalTileRule(sci.verticalTileRule()); - - d->sciurl = d->url.resolved(QUrl(sci.pixmapUrl())); - d->reply = QFxPixmap::get(qmlEngine(this), d->sciurl, this, SLOT(requestFinished())); - if (d->reply) { - connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); - } else { - d->progress = 1.0; - emit progressChanged(d->progress); - } + if (d->smooth) { + p->setRenderHint(QPainter::Antialiasing, oldAA); + p->setRenderHint(QPainter::SmoothPixmapTransform, oldSmooth); } } - QT_END_NAMESPACE diff --git a/src/declarative/fx/qfximage.h b/src/declarative/fx/qfximage.h index fc9cfe0..c8e21ea 100644 --- a/src/declarative/fx/qfximage.h +++ b/src/declarative/fx/qfximage.h @@ -42,30 +42,20 @@ #ifndef QFXIMAGE_H #define QFXIMAGE_H -#include <QtDeclarative/qfxitem.h> #include <QtNetwork/qnetworkreply.h> - +#include "qfximagebase.h" QT_BEGIN_HEADER - QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QFxImagePrivate; -class QFxScaleGrid; -class QFxGridScaledImage; -class Q_DECLARATIVE_EXPORT QFxImage : public QFxItem +class QFxImagePrivate; +class Q_DECLARATIVE_EXPORT QFxImage : public QFxImageBase { Q_OBJECT - Q_ENUMS(Status) Q_ENUMS(FillMode) - Q_PROPERTY(Status status READ status NOTIFY statusChanged) - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) - - Q_PROPERTY(QFxScaleGrid *scaleGrid READ scaleGrid) Q_PROPERTY(QPixmap pixmap READ pixmap WRITE setPixmap DESIGNABLE false) Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged); @@ -73,48 +63,28 @@ public: QFxImage(QFxItem *parent=0); ~QFxImage(); - enum FillMode { Stretch, PreserveAspect, Tile, TileVertically, TileHorizontally }; + enum FillMode { Stretch, PreserveAspectFit, PreserveAspectCrop, Tile, TileVertically, TileHorizontally }; FillMode fillMode() const; void setFillMode(FillMode); QPixmap pixmap() const; void setPixmap(const QPixmap &); - enum Status { Null, Ready, Loading, Error }; - Status status() const; - qreal progress() const; - - QUrl source() const; - virtual void setSource(const QUrl &url); - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); Q_SIGNALS: - void sourceChanged(const QUrl &); - void statusChanged(Status); - void progressChanged(qreal progress); void fillModeChanged(); protected: QFxImage(QFxImagePrivate &dd, QFxItem *parent); - virtual void componentComplete(); - -private Q_SLOTS: - void requestFinished(); - void sciRequestFinished(); - void requestProgress(qint64,qint64); private: Q_DISABLE_COPY(QFxImage) Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QFxImage) - void setGridScaledImage(const QFxGridScaledImage& sci); - QFxScaleGrid *scaleGrid(); }; QT_END_NAMESPACE - QML_DECLARE_TYPE(QFxImage) - QT_END_HEADER #endif // QFXIMAGE_H diff --git a/src/declarative/fx/qfximage_p.h b/src/declarative/fx/qfximage_p.h index 2ce41f8..8bdcc14 100644 --- a/src/declarative/fx/qfximage_p.h +++ b/src/declarative/fx/qfximage_p.h @@ -54,54 +54,22 @@ // #include "qfxitem_p.h" -#include "qfxscalegrid_p.h" - -#include <QtCore/qpointer.h> +#include "qfximagebase_p.h" QT_BEGIN_NAMESPACE -class QSvgRenderer; -class QWebPage; -class QNetworkReply; -class QIODevice; - -class QFxImagePrivate : public QFxItemPrivate +class QFxImagePrivate : public QFxImageBasePrivate { Q_DECLARE_PUBLIC(QFxImage) public: QFxImagePrivate() - : scaleGrid(0), - fillMode(QFxImage::Stretch), - status(QFxImage::Null), sciReply(0), - progress(0.0) - { - } - - ~QFxImagePrivate() + : fillMode(QFxImage::Stretch) { - delete scaleGrid; } - void setContent(QIODevice* dev, const QString &url); - - QFxScaleGrid *getScaleGrid() - { - if (!scaleGrid) - scaleGrid = new QFxScaleGrid; - return scaleGrid; - } - - QFxScaleGrid *scaleGrid; - QPixmap pix; - QFxImage::FillMode fillMode; - QFxImage::Status status; - QUrl url; - QUrl sciurl; - QNetworkReply *sciReply; - QPointer<QNetworkReply> reply; - qreal progress; + }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfximagebase.cpp b/src/declarative/fx/qfximagebase.cpp new file mode 100644 index 0000000..f96ff6f --- /dev/null +++ b/src/declarative/fx/qfximagebase.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfximagebase.h" +#include "qfximagebase_p.h" +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QFile> +#include <QtDeclarative/qmlengine.h> +#include <QtDeclarative/qfxpixmap.h> + +QT_BEGIN_NAMESPACE + +QFxImageBase::QFxImageBase(QFxItem *parent) + : QFxItem(*(new QFxImageBasePrivate), parent) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); +} + +QFxImageBase::QFxImageBase(QFxImageBasePrivate &dd, QFxItem *parent) + : QFxItem(dd, parent) +{ + setFlag(QGraphicsItem::ItemHasNoContents, true); +} + +QFxImageBase::~QFxImageBase() +{ + Q_D(QFxImageBase); + if (!d->url.isEmpty()) + QFxPixmap::cancelGet(d->url, this); +} + +QFxImageBase::Status QFxImageBase::status() const +{ + Q_D(const QFxImageBase); + return d->status; +} + + +qreal QFxImageBase::progress() const +{ + Q_D(const QFxImageBase); + return d->progress; +} + + +/*! + \property QFxImage::source + \brief the url of the image to be displayed in this item. + + The content specified can be of any image type loadable by QImage. Alternatively, + you can specify an sci format file, which specifies both an image and it's scale grid. +*/ +QUrl QFxImageBase::source() const +{ + Q_D(const QFxImageBase); + return d->url; +} + +void QFxImageBase::setSource(const QUrl &url) +{ + Q_D(QFxImageBase); + //equality is fairly expensive, so we bypass for simple, common case + if ((d->url.isEmpty() == url.isEmpty()) && url == d->url) + return; + + if (!d->url.isEmpty()) + QFxPixmap::cancelGet(d->url, this); + + d->url = url; + if (d->progress != 0.0) { + d->progress = 0.0; + emit progressChanged(d->progress); + } + + if (url.isEmpty()) { + d->pix = QPixmap(); + d->status = Null; + d->progress = 1.0; + setImplicitWidth(0); + setImplicitHeight(0); + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); + } else { + d->status = Loading; + d->reply = QFxPixmap::get(qmlEngine(this), d->url, &d->pix); + if (d->reply) { + connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished())); + connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + } else { + //### should be unified with requestFinished + setImplicitWidth(d->pix.width()); + setImplicitHeight(d->pix.height()); + + if (d->status == Loading) + d->status = Ready; + d->progress = 1.0; + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); + } + } + + emit statusChanged(d->status); +} + +void QFxImageBase::requestFinished() +{ + Q_D(QFxImageBase); + if (d->reply) { + //###disconnect really needed? + disconnect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); + if (d->reply->error() != QNetworkReply::NoError) + d->status = Error; + } + QFxPixmap::find(d->url, &d->pix); + setImplicitWidth(d->pix.width()); + setImplicitHeight(d->pix.height()); + + if (d->status == Loading) + d->status = Ready; + d->progress = 1.0; + emit statusChanged(d->status); + emit sourceChanged(d->url); + emit progressChanged(1.0); + update(); +} + +void QFxImageBase::requestProgress(qint64 received, qint64 total) +{ + Q_D(QFxImageBase); + if (d->status == Loading && total > 0) { + d->progress = qreal(received)/total; + emit progressChanged(d->progress); + } +} + + +QT_END_NAMESPACE diff --git a/src/declarative/fx/qfximagebase.h b/src/declarative/fx/qfximagebase.h new file mode 100644 index 0000000..ce9c0c3 --- /dev/null +++ b/src/declarative/fx/qfximagebase.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXIMAGEBASE_H +#define QFXIMAGEBASE_H + +#include <QtDeclarative/qfxitem.h> + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE + +class QFxImageBasePrivate; +class QFxImageBase : public QFxItem +{ + Q_OBJECT + Q_ENUMS(Status) + + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) + +public: + QFxImageBase(QFxItem *parent = 0); + ~QFxImageBase(); + enum Status { Null, Ready, Loading, Error }; + Status status() const; + qreal progress() const; + + QUrl source() const; + virtual void setSource(const QUrl &url); + +Q_SIGNALS: + void sourceChanged(const QUrl &); + void statusChanged(Status); + void progressChanged(qreal progress); + +protected: + QFxImageBase(QFxImageBasePrivate &dd, QFxItem *parent); + +private Q_SLOTS: + virtual void requestFinished(); + void requestProgress(qint64,qint64); + +private: + Q_DISABLE_COPY(QFxImageBase) + Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr, QFxImageBase) +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QFXIMAGEBASE_H diff --git a/src/declarative/fx/qfximagebase_p.h b/src/declarative/fx/qfximagebase_p.h new file mode 100644 index 0000000..b468b90 --- /dev/null +++ b/src/declarative/fx/qfximagebase_p.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFXIMAGEBASE_P_H +#define QFXIMAGEBASE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfxitem_p.h" +#include <QtCore/QPointer> + +QT_BEGIN_NAMESPACE + +class QNetworkReply; +class QFxImageBasePrivate : public QFxItemPrivate +{ + Q_DECLARE_PUBLIC(QFxImageBase) + +public: + QFxImageBasePrivate() + : status(QFxImageBase::Null), + progress(0.0) + { + } + + QPixmap pix; + QFxImageBase::Status status; + QUrl url; + QPointer<QNetworkReply> reply; + qreal progress; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index cae5c72..c68d0da 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -2188,20 +2188,6 @@ void QFxItem::setTransformOrigin(TransformOrigin origin) } /*! - \qmlproperty bool Item::smooth - - Set this property if you want the item to be smoothly scaled or - transformed. Smooth filtering gives better visual quality, but is slower. If - the item is displayed at its natural size, this property has no visual or - performance effect. - Currently, only the \c Image, \c Text , \c TextEdit and \c LineEdit items implement smooth filtering. - - \note Generally scaling artifacts are only visible if the item is stationary on - the screen. A common pattern when animating an item is to disable smooth - filtering at the beginning of the animation and reenable it at the conclusion. - */ - -/*! \property QFxItem::smooth \brief whether the item is smoothly transformed. diff --git a/src/declarative/fx/qfxlineedit.cpp b/src/declarative/fx/qfxlineedit.cpp index 0bb93b6..e1d9f14 100644 --- a/src/declarative/fx/qfxlineedit.cpp +++ b/src/declarative/fx/qfxlineedit.cpp @@ -140,13 +140,66 @@ void QFxLineEdit::setColor(const QColor &c) d->color = c; } -QFxText::HAlignment QFxLineEdit::hAlign() const + +/*! + \qmlproperty color LineEdit::highlightColor + + The text highlight color, used behind selections. +*/ + +/*! + \property QFxLineEdit::highlightColor + \brief the line edit's default text highlight color +*/ +QColor QFxLineEdit::highlightColor() const +{ + Q_D(const QFxLineEdit); + return d->highlightColor; +} + +void QFxLineEdit::setHighlightColor(const QColor &color) +{ + Q_D(QFxLineEdit); + if (d->highlightColor == color) + return; + + d->highlightColor = color; + //TODO: implement +} + +/*! + \qmlproperty color LineEdit::highlightedTextColor + + The highlighted text color, used in selections. +*/ + +/*! + \property QFxLineEdit::highlightedTextColor + \brief the line edit's default highlighted text color +*/ +QColor QFxLineEdit::highlightedTextColor() const +{ + Q_D(const QFxLineEdit); + return d->highlightedTextColor; +} + +void QFxLineEdit::setHighlightedTextColor(const QColor &color) +{ + Q_D(QFxLineEdit); + if (d->highlightedTextColor == color) + return; + + d->highlightedTextColor = color; + //TODO: implement +} + +QFxLineEdit::HAlignment QFxLineEdit::hAlign() const { Q_D(const QFxLineEdit); return d->hAlign; } -void QFxLineEdit::setHAlign(QFxText::HAlignment align) +void QFxLineEdit::setHAlign(HAlignment align) { Q_D(QFxLineEdit); d->hAlign = align; @@ -177,6 +230,29 @@ void QFxLineEdit::setMaxLength(int ml) } /*! + \qmlproperty LineEdit::cursorVisible + \brief If true the text edit shows a cursor. + + This property is set and unset when the line edit gets focus, but it can also + be set directly (useful, for example, if a KeyProxy might forward keys to it). +*/ +bool QFxLineEdit::isCursorVisible() const +{ + Q_D(const QFxLineEdit); + return d->cursorVisible; +} + +void QFxLineEdit::setCursorVisible(bool on) +{ + Q_D(QFxLineEdit); + if (d->cursorVisible == on) + return; + d->cursorVisible = on; + d->control->setCursorBlinkPeriod(on?QApplication::cursorFlashTime():0); + updateAll();//TODO: Only update cursor rect +} + +/*! \qmlproperty LineEdit::cursorPosition \brief The position of the cursor in the LineEdit. */ @@ -380,20 +456,6 @@ void QFxLineEdit::moveCursor() d->cursorItem->setX(d->control->cursorToX() - d->hscroll); } -/* -int QFxLineEdit::scrollDuration() const -{ - Q_D(const QFxLineEdit); - return d->scrollDur; -} - -void QFxLineEdit::setScrollDuration(int s) -{ - Q_D(QFxLineEdit); - d->scrollDur = s; - //Need to update cur anims as well -} -*/ int QFxLineEdit::xToPos(int x) { Q_D(const QFxLineEdit); @@ -403,14 +465,8 @@ int QFxLineEdit::xToPos(int x) void QFxLineEdit::focusChanged(bool hasFocus) { Q_D(QFxLineEdit); - if(d->focused && !hasFocus){ - d->focused = false; - d->control->setCursorBlinkPeriod(0); - updateAll();//Only need the cursor rect - }else{ - d->focused = hasFocus; - updateAll();//Only need the cursor rect - } + d->focused = hasFocus; + setCursorVisible(hasFocus); } void QFxLineEdit::keyPressEvent(QKeyEvent* ev) @@ -424,8 +480,8 @@ void QFxLineEdit::keyPressEvent(QKeyEvent* ev) void QFxLineEdit::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QFxLineEdit); - setFocus(true); - d->control->setCursorBlinkPeriod(QApplication::cursorFlashTime()); + setFocus(true);//###Should we make 'focusOnPress' be optional like TextEdit? + setCursorVisible(true); d->focused = true; d->control->processEvent(event); //event->accept(); @@ -459,7 +515,7 @@ void QFxLineEdit::drawContents(QPainter *p, const QRect &r) p->save(); p->setPen(QPen(d->color)); int flags = QLineControl::DrawText; - if(!isReadOnly() && d->focused && !d->cursorItem) + if(!isReadOnly() && d->cursorVisible && !d->cursorItem) flags |= QLineControl::DrawCursor; if (d->control->hasSelectedText()) flags |= QLineControl::DrawSelections; @@ -469,13 +525,26 @@ void QFxLineEdit::drawContents(QPainter *p, const QRect &r) p->restore(); } +/*! + \qmlproperty bool LineEdit::smooth + + Set this property if you want the text to be smoothly scaled or + transformed. Smooth filtering gives better visual quality, but is slower. If + the item is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the item is stationary on + the screen. A common pattern when animating an item is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + void QFxLineEditPrivate::init() { Q_Q(QFxLineEdit); control->setCursorWidth(1); control->setPasswordCharacter(QLatin1Char('*')); control->setLayoutDirection(Qt::LeftToRight); - q->setSmoothTransform(true); + q->setSmoothTransform(smooth); q->setAcceptedMouseButtons(Qt::LeftButton); q->setFlag(QGraphicsItem::ItemHasNoContents, false); q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); diff --git a/src/declarative/fx/qfxlineedit.h b/src/declarative/fx/qfxlineedit.h index 846ef52..f78dbfc 100644 --- a/src/declarative/fx/qfxlineedit.h +++ b/src/declarative/fx/qfxlineedit.h @@ -58,29 +58,43 @@ class QValidator; class Q_DECLARATIVE_EXPORT QFxLineEdit : public QFxPaintedItem { Q_OBJECT + Q_ENUMS(HAlignment) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) - Q_PROPERTY(QmlFont *font READ font CONSTANT) Q_PROPERTY(QColor color READ color WRITE setColor) - Q_PROPERTY(QFxText::HAlignment hAlign READ hAlign WRITE setHAlign) + Q_PROPERTY(QColor highlightColor READ highlightColor WRITE setHighlightColor) + Q_PROPERTY(QColor highlightedTextColor READ highlightedTextColor WRITE setHighlightedTextColor) + Q_PROPERTY(QmlFont *font READ font CONSTANT) + Q_PROPERTY(HAlignment hAlign READ hAlign WRITE setHAlign) - Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly); - Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength); - Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged); + Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly) + Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible) + Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) + Q_PROPERTY(QmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate) Q_PROPERTY(int selectionStart READ selectionStart WRITE setSelectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd WRITE setSelectionEnd NOTIFY selectionEndChanged) - Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged); + Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) - Q_PROPERTY(QObject* validator READ validator WRITE setValidator); - Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask); - Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged); - Q_PROPERTY(uint echoMode READ echoMode WRITE setEchoMode); + Q_PROPERTY(int maxLength READ maxLength WRITE setMaxLength) + Q_PROPERTY(QObject* validator READ validator WRITE setValidator) + Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask) + Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged) + Q_PROPERTY(uint echoMode READ echoMode WRITE setEchoMode) - Q_PROPERTY(QmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate); public: QFxLineEdit(QFxItem* parent=0); ~QFxLineEdit(); + enum HAlignment { + AlignLeft = Qt::AlignLeft, + AlignRight = Qt::AlignRight, + AlignHCenter = Qt::AlignHCenter + }; + + //### Should we have this function, x based properties, + //### or copy TextEdit with x instead of QTextCursor? + Q_INVOKABLE int xToPos(int x); + QString text() const; void setText(const QString &); @@ -89,17 +103,20 @@ public: QColor color() const; void setColor(const QColor &c); - //### Should we have this function or x variants of properties? - Q_INVOKABLE int xToPos(int x); + QColor highlightColor() const; + void setHighlightColor(const QColor &c); - QFxText::HAlignment hAlign() const; - void setHAlign(QFxText::HAlignment align); + QColor highlightedTextColor() const; + void setHighlightedTextColor(const QColor &c); + + HAlignment hAlign() const; + void setHAlign(HAlignment align); bool isReadOnly() const; void setReadOnly(bool); - int maxLength() const; - void setMaxLength(int ml); + bool isCursorVisible() const; + void setCursorVisible(bool on); int cursorPosition() const; void setCursorPosition(int cp); @@ -112,6 +129,9 @@ public: QString selectedText() const; + int maxLength() const; + void setMaxLength(int ml); + QObject * validator() const; void setValidator(QObject* v); diff --git a/src/declarative/fx/qfxlineedit_p.h b/src/declarative/fx/qfxlineedit_p.h index a18dea7..a087a32 100644 --- a/src/declarative/fx/qfxlineedit_p.h +++ b/src/declarative/fx/qfxlineedit_p.h @@ -65,9 +65,8 @@ class QFxLineEditPrivate : public QFxPaintedItemPrivate public: QFxLineEditPrivate() : control(new QLineControl(QString())), font(0), color((QRgb)0), style(QFxText::Normal), - styleColor((QRgb)0), - hAlign(QFxText::AlignLeft), vAlign(QFxText::AlignTop), - hscroll(0), oldScroll(0), focused(false) + styleColor((QRgb)0), hAlign(QFxLineEdit::AlignLeft), + hscroll(0), oldScroll(0), focused(false), cursorVisible(false) { } @@ -82,10 +81,11 @@ public: QmlFont *font; QColor color; + QColor highlightColor; + QColor highlightedTextColor; QFxText::TextStyle style; QColor styleColor; - QFxText::HAlignment hAlign; - QFxText::VAlignment vAlign; + QFxLineEdit::HAlignment hAlign; QPointer<QmlComponent> cursorComponent; QPointer<QFxItem> cursorItem; @@ -97,6 +97,7 @@ public: int hscroll; int oldScroll; bool focused; + bool cursorVisible; }; QT_END_NAMESPACE diff --git a/src/declarative/fx/qfxpixmap.cpp b/src/declarative/fx/qfxpixmap.cpp index 6647b21..43e94e5 100644 --- a/src/declarative/fx/qfxpixmap.cpp +++ b/src/declarative/fx/qfxpixmap.cpp @@ -81,14 +81,7 @@ public: } }; -class QFxPixmapPrivate -{ -public: - QFxPixmapPrivate() {} - - QPixmap pixmap; - - bool readImage(QIODevice *dev) +static bool readImage(QIODevice *dev, QPixmap *pixmap) { QImageReader imgio(dev); @@ -114,13 +107,12 @@ public: if (!sz.isValid()) img = img.scaled(limit,Qt::KeepAspectRatio); #endif - pixmap = QPixmap::fromImage(img); + *pixmap = QPixmap::fromImage(img); return true; } else { return false; } } -}; /*! \internal @@ -131,25 +123,26 @@ public: This class is NOT reentrant. The pixmap cache will grow indefinately. */ -QFxPixmap::QFxPixmap() -: d(new QFxPixmapPrivate) -{ -} -QFxPixmap::QFxPixmap(const QUrl &url) -: d(new QFxPixmapPrivate) + +bool QFxPixmap::find(const QUrl& url, QPixmap *pixmap) { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer<QFxPerf::PixmapLoad> perf; #endif + QString key = url.toString(); - if (!QPixmapCache::find(key,&d->pixmap)) { + if (!QPixmapCache::find(key,pixmap)) { #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML if (url.scheme()==QLatin1String("file")) { QFile f(url.toLocalFile()); - if (f.open(QIODevice::ReadOnly)) - if (!d->readImage(&f)) + if (f.open(QIODevice::ReadOnly)) { + if (!readImage(&f, pixmap)) { qWarning() << "Format error loading" << url; + *pixmap = QPixmap(); + } + } else + *pixmap = QPixmap(); } else #endif { @@ -158,53 +151,20 @@ QFxPixmap::QFxPixmap(const QUrl &url) // API usage error qWarning() << "QFxPixmap: URL not loaded" << url; } else { - if ((*iter)->reply->error()) + if ((*iter)->reply->error()) { qWarning() << "Network error loading" << url << (*iter)->reply->errorString(); - else - if (!d->readImage((*iter)->reply)) + *pixmap = QPixmap(); + } else + if (!readImage((*iter)->reply, pixmap)) { qWarning() << "Format error loading" << url; + *pixmap = QPixmap(); + } (*iter)->release(); } } - QPixmapCache::insert(key, d->pixmap); + QPixmapCache::insert(key, *pixmap); } -} - -QFxPixmap::QFxPixmap(const QFxPixmap &o) -: d(new QFxPixmapPrivate) -{ - d->pixmap = o.d->pixmap; -} - -QFxPixmap::~QFxPixmap() -{ - delete d; -} - -QFxPixmap &QFxPixmap::operator=(const QFxPixmap &o) -{ - d->pixmap = o.d->pixmap; - return *this; -} - -bool QFxPixmap::isNull() const -{ - return d->pixmap.isNull(); -} - -int QFxPixmap::width() const -{ - return d->pixmap.width(); -} - -int QFxPixmap::height() const -{ - return d->pixmap.height(); -} - -QFxPixmap::operator const QPixmap &() const -{ - return d->pixmap; + return true; } /*! @@ -215,20 +175,28 @@ QFxPixmap::operator const QPixmap &() const Returns a QNetworkReply if the image is not immediately available, otherwise returns 0. The QNetworkReply must not be stored - it may be destroyed at any time. */ -QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, const char* slot) +QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QPixmap *pixmap) { #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML if (url.scheme()==QLatin1String("file")) { - QObject dummy; - QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot); + QString key = url.toString(); + if (!QPixmapCache::find(key,pixmap)) { + QFile f(url.toLocalFile()); + if (f.open(QIODevice::ReadOnly)) { + if (!readImage(&f, pixmap)) { + qWarning() << "Format error loading" << url; + *pixmap = QPixmap(); + } + } else + *pixmap = QPixmap(); + QPixmapCache::insert(key, *pixmap); + } return 0; } #endif QString key = url.toString(); - if (QPixmapCache::find(key,0)) { - QObject dummy; - QObject::connect(&dummy, SIGNAL(destroyed()), obj, slot); + if (QPixmapCache::find(key,pixmap)) { return 0; } @@ -242,7 +210,6 @@ QNetworkReply *QFxPixmap::get(QmlEngine *engine, const QUrl& url, QObject* obj, (*iter)->addRef(); } - QObject::connect((*iter)->reply, SIGNAL(finished()), obj, slot); return (*iter)->reply; } diff --git a/src/declarative/fx/qfxpixmap.h b/src/declarative/fx/qfxpixmap.h index f63299b..ec8d2be 100644 --- a/src/declarative/fx/qfxpixmap.h +++ b/src/declarative/fx/qfxpixmap.h @@ -54,29 +54,13 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QmlEngine; class QNetworkReply; -class QFxPixmapPrivate; -class Q_DECLARATIVE_EXPORT QFxPixmap +class Q_DECLARATIVE_EXPORT QFxPixmap //### rename QFxPixmapCache { public: - QFxPixmap(); - QFxPixmap(const QUrl& url); // url must have been passed to QFxPixmap::get, and finished. - QFxPixmap(const QFxPixmap &); - virtual ~QFxPixmap(); - - QFxPixmap &operator=(const QFxPixmap &); - - static QNetworkReply *get(QmlEngine *, const QUrl& url, QObject*, const char* slot); + static QNetworkReply *get(QmlEngine *, const QUrl& url, QPixmap *pixmap); static void cancelGet(const QUrl& url, QObject* obj); - bool isNull() const; - - int width() const; - int height() const; - - operator const QPixmap &() const; - -private: - QFxPixmapPrivate *d; + static bool find(const QUrl& url, QPixmap *pixmap); // url must have been passed to QFxPixmap::get, and finished. Or must be a local file. }; diff --git a/src/declarative/fx/qfxrect.cpp b/src/declarative/fx/qfxrect.cpp index 29321b8..0bd240e 100644 --- a/src/declarative/fx/qfxrect.cpp +++ b/src/declarative/fx/qfxrect.cpp @@ -591,6 +591,19 @@ void QFxRect::drawRect(QPainter &p) } } +/*! + \qmlproperty bool Rect::smooth + + Set this property if you want the item to be smoothly scaled or + transformed. Smooth filtering gives better visual quality, but is slower. If + the item is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the item is stationary on + the screen. A common pattern when animating an item is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + QRectF QFxRect::boundingRect() const { Q_D(const QFxRect); diff --git a/src/declarative/fx/qfxscalegrid.cpp b/src/declarative/fx/qfxscalegrid.cpp index 8eb9890..4856c15 100644 --- a/src/declarative/fx/qfxscalegrid.cpp +++ b/src/declarative/fx/qfxscalegrid.cpp @@ -74,8 +74,7 @@ QT_BEGIN_NAMESPACE */ QML_DEFINE_NOCREATE_TYPE(QFxScaleGrid) -QFxScaleGrid::QFxScaleGrid() : QObject(), _left(0), _top(0), _right(0), _bottom(0), - _horizontalTileRule(Stretch), _verticalTileRule(Stretch) +QFxScaleGrid::QFxScaleGrid() : QObject(), _left(0), _top(0), _right(0), _bottom(0) { } @@ -124,20 +123,9 @@ void QFxScaleGrid::setBottom(int pos) _bottom = pos; } -void QFxScaleGrid::setHorizontalTileRule(TileRule r) -{ - _horizontalTileRule = r; -} - -void QFxScaleGrid::setVerticalTileRule(TileRule r) -{ - _verticalTileRule = r; -} - - QFxGridScaledImage::QFxGridScaledImage() : _l(-1), _r(-1), _t(-1), _b(-1), - _h(QFxScaleGrid::Stretch), _v(QFxScaleGrid::Stretch) + _h(QFxBorderImage::Stretch), _v(QFxBorderImage::Stretch) { } @@ -159,7 +147,7 @@ QFxGridScaledImage &QFxGridScaledImage::operator=(const QFxGridScaledImage &o) } QFxGridScaledImage::QFxGridScaledImage(QIODevice *data) -: _l(-1), _r(-1), _t(-1), _b(-1), _h(QFxScaleGrid::Stretch), _v(QFxScaleGrid::Stretch) +: _l(-1), _r(-1), _t(-1), _b(-1), _h(QFxBorderImage::Stretch), _v(QFxBorderImage::Stretch) { int l = -1; int r = -1; @@ -203,17 +191,17 @@ QFxGridScaledImage::QFxGridScaledImage(QIODevice *data) _pix = imgFile; } -QFxScaleGrid::TileRule QFxGridScaledImage::stringToRule(const QString &s) +QFxBorderImage::TileMode QFxGridScaledImage::stringToRule(const QString &s) { if (s == QLatin1String("Stretch")) - return QFxScaleGrid::Stretch; + return QFxBorderImage::Stretch; if (s == QLatin1String("Repeat")) - return QFxScaleGrid::Repeat; + return QFxBorderImage::Repeat; if (s == QLatin1String("Round")) - return QFxScaleGrid::Round; + return QFxBorderImage::Round; qWarning() << "Unknown tile rule specified. Using Stretch"; - return QFxScaleGrid::Stretch; + return QFxBorderImage::Stretch; } bool QFxGridScaledImage::isValid() const diff --git a/src/declarative/fx/qfxscalegrid_p.h b/src/declarative/fx/qfxscalegrid_p.h index 483ade1..9d0a84c 100644 --- a/src/declarative/fx/qfxscalegrid_p.h +++ b/src/declarative/fx/qfxscalegrid_p.h @@ -47,6 +47,7 @@ #include <QtDeclarative/qfxglobal.h> #include <QtDeclarative/qfxpixmap.h> #include <QtDeclarative/qml.h> +#include "qfxborderimage.h" QT_BEGIN_HEADER @@ -54,6 +55,7 @@ QT_BEGIN_HEADER QT_BEGIN_NAMESPACE QT_MODULE(Declarative) + class Q_DECLARATIVE_EXPORT QFxScaleGrid : public QObject { Q_OBJECT @@ -63,8 +65,6 @@ class Q_DECLARATIVE_EXPORT QFxScaleGrid : public QObject Q_PROPERTY(int top READ top WRITE setTop) Q_PROPERTY(int right READ right WRITE setRight) Q_PROPERTY(int bottom READ bottom WRITE setBottom) - Q_PROPERTY(TileRule horizontalTileRule READ horizontalTileRule WRITE setHorizontalTileRule) - Q_PROPERTY(TileRule verticalTileRule READ verticalTileRule WRITE setVerticalTileRule) public: QFxScaleGrid(); @@ -84,21 +84,11 @@ public: int bottom() const { return _bottom; } void setBottom(int); - enum TileRule { Stretch = Qt::Stretch, Repeat = Qt::Repeat, Round = Qt::Round }; - - TileRule horizontalTileRule() const { return _horizontalTileRule; } - void setHorizontalTileRule(TileRule); - - TileRule verticalTileRule() const { return _verticalTileRule; } - void setVerticalTileRule(TileRule); - private: int _left; int _top; int _right; int _bottom; - TileRule _horizontalTileRule; - TileRule _verticalTileRule; }; class Q_DECLARATIVE_EXPORT QFxGridScaledImage @@ -113,21 +103,21 @@ public: int gridRight() const; int gridTop() const; int gridBottom() const; - QFxScaleGrid::TileRule horizontalTileRule() const { return _h; } - QFxScaleGrid::TileRule verticalTileRule() const { return _v; } + QFxBorderImage::TileMode horizontalTileRule() const { return _h; } + QFxBorderImage::TileMode verticalTileRule() const { return _v; } QString pixmapUrl() const; private: - static QFxScaleGrid::TileRule stringToRule(const QString &); + static QFxBorderImage::TileMode stringToRule(const QString &); private: int _l; int _r; int _t; int _b; - QFxScaleGrid::TileRule _h; - QFxScaleGrid::TileRule _v; + QFxBorderImage::TileMode _h; + QFxBorderImage::TileMode _v; QString _pix; }; diff --git a/src/declarative/fx/qfxtext.cpp b/src/declarative/fx/qfxtext.cpp index 0c3f4e9..c3872c4 100644 --- a/src/declarative/fx/qfxtext.cpp +++ b/src/declarative/fx/qfxtext.cpp @@ -809,6 +809,19 @@ void QFxText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *) } } +/*! + \qmlproperty bool Text::smooth + + Set this property if you want the text to be smoothly scaled or + transformed. Smooth filtering gives better visual quality, but is slower. If + the item is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the item is stationary on + the screen. A common pattern when animating an item is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + void QFxText::componentComplete() { Q_D(QFxText); diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index 85e0a5a..fcc9e69 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -329,7 +329,7 @@ void QFxTextEdit::setHighlightColor(const QColor &color) QColor QFxTextEdit::highlightedTextColor() const { Q_D(const QFxTextEdit); - return d->highlightColor; + return d->highlightedTextColor; } void QFxTextEdit::setHighlightedTextColor(const QColor &color) @@ -1001,11 +1001,24 @@ void QFxTextEdit::updateImgCache(const QRectF &r) emit update(); } +/*! + \qmlproperty bool TextEdit::smooth + + Set this property if you want the text to be smoothly scaled or + transformed. Smooth filtering gives better visual quality, but is slower. If + the item is displayed at its natural size, this property has no visual or + performance effect. + + \note Generally scaling artifacts are only visible if the item is stationary on + the screen. A common pattern when animating an item is to disable smooth + filtering at the beginning of the animation and reenable it at the conclusion. +*/ + void QFxTextEditPrivate::init() { Q_Q(QFxTextEdit); - q->setSmoothTransform(true); + q->setSmoothTransform(smooth); q->setAcceptedMouseButtons(Qt::LeftButton); q->setFlag(QGraphicsItem::ItemHasNoContents, false); q->setFlag(QGraphicsItem::ItemAcceptsInputMethod); diff --git a/src/declarative/fx/qfxwebview.cpp b/src/declarative/fx/qfxwebview.cpp index 47199ef..37e5d59 100644 --- a/src/declarative/fx/qfxwebview.cpp +++ b/src/declarative/fx/qfxwebview.cpp @@ -139,7 +139,7 @@ class QFxWebViewPrivate : public QFxPaintedItemPrivate public: QFxWebViewPrivate() : QFxPaintedItemPrivate(), page(0), idealwidth(0), idealheight(0), interactive(true), lastPress(0), lastRelease(0), mouseX(0), mouseY(0), - progress(1.0), pending(PendingNone) + progress(1.0), pending(PendingNone), windowObjects(this) { } @@ -158,8 +158,21 @@ public: QString pending_string; QByteArray pending_data; mutable QFxWebSettings settings; -}; + void updateWindowObjects(); + class WindowObjectList : public QmlConcreteList<QObject *> + { + public: + WindowObjectList(QFxWebViewPrivate *p) + : priv(p) {} + virtual void append(QObject *v) { + QmlConcreteList<QObject *>::append(v); + priv->updateWindowObjects(); + } + private: + QFxWebViewPrivate *priv; + } windowObjects; +}; /*! \qmlclass WebView @@ -258,6 +271,7 @@ void QFxWebView::componentComplete() break; } d->pending = QFxWebViewPrivate::PendingNone; + d->updateWindowObjects(); } /*! @@ -416,6 +430,15 @@ void QFxWebView::setInteractive(bool i) emit interactiveChanged(); } +/*! + Evaluates the \a scriptSource JavaScript inside the main frame + context and returns the result of the last executed statement. +*/ +QVariant QFxWebView::evaluateJavaScript(const QString &scriptSource) +{ + return this->page()->mainFrame()->evaluateJavaScript(scriptSource); +} + void QFxWebView::expandToWebPage() { Q_D(QFxWebView); @@ -500,6 +523,56 @@ void QFxWebView::setCacheSize(int pixels) d->max_imagecache_size = pixels; } +QmlList<QObject *> *QFxWebView::javaScriptWindowObjects() +{ + Q_D(QFxWebView); + return &d->windowObjects; +} + +class QFxWebViewAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString windowObjectName READ windowObjectName WRITE setWindowObjectName) +public: + QFxWebViewAttached(QObject *parent) + : QObject(parent) + { + } + + QString windowObjectName() const + { + return m_windowObjectName; + } + + void setWindowObjectName(const QString &n) + { + m_windowObjectName = n; + } + +private: + QString m_windowObjectName; +}; + +QFxWebViewAttached *QFxWebView::qmlAttachedProperties(QObject *o) +{ + return new QFxWebViewAttached(o); +} + +void QFxWebViewPrivate::updateWindowObjects() +{ + Q_Q(QFxWebView); + if (!q->isComponentComplete() || !page) + return; + + for (int ii = 0; ii < windowObjects.count(); ++ii) { + QObject *object = windowObjects.at(ii); + QFxWebViewAttached *attached = static_cast<QFxWebViewAttached *>(qmlAttachedPropertiesObject<QFxWebView>(object)); + if (attached && !attached->windowObjectName().isEmpty()) { + page->mainFrame()->addToJavaScriptWindowObject(attached->windowObjectName(), object); + } + } +} + void QFxWebView::drawContents(QPainter *p, const QRect &r) { page()->mainFrame()->render(p,r); @@ -778,6 +851,12 @@ void QFxWebView::setStatusBarMessage(const QString& s) emit statusChanged(); } +void QFxWebView::windowObjectCleared() +{ + Q_D(QFxWebView); + d->updateWindowObjects(); +} + QString QFxWebView::status() const { Q_D(const QFxWebView); @@ -871,6 +950,8 @@ void QFxWebView::setPage(QWebPage *page) connect(d->page,SIGNAL(loadProgress(int)),this,SLOT(doLoadProgress(int))); connect(d->page,SIGNAL(loadFinished(bool)),this,SLOT(doLoadFinished(bool))); connect(d->page,SIGNAL(statusBarMessage(QString)),this,SLOT(setStatusBarMessage(QString))); + + connect(d->page->mainFrame(),SIGNAL(javaScriptWindowObjectCleared()),this,SLOT(windowObjectCleared())); } void QFxWebView::load(const QNetworkRequest &request, diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h index 1200162..8df3d18 100644 --- a/src/declarative/fx/qfxwebview.h +++ b/src/declarative/fx/qfxwebview.h @@ -74,6 +74,7 @@ private: }; +class QFxWebViewAttached; class Q_DECLARATIVE_EXPORT QFxWebView : public QFxPaintedItem { Q_OBJECT @@ -103,6 +104,8 @@ class Q_DECLARATIVE_EXPORT QFxWebView : public QFxPaintedItem Q_PROPERTY(QObject* settings READ settingsObject CONSTANT) + Q_PROPERTY(QmlList<QObject *>* javaScriptWindowObjects READ javaScriptWindowObjects CONSTANT) + public: QFxWebView(QFxItem *parent=0); ~QFxWebView(); @@ -160,6 +163,10 @@ public: int cacheSize() const; void setCacheSize(int pixels); + QmlList<QObject *> *javaScriptWindowObjects(); + + static QFxWebViewAttached *qmlAttachedProperties(QObject *); + Q_SIGNALS: void idealWidthChanged(); void idealHeightChanged(); @@ -178,12 +185,16 @@ Q_SIGNALS: void singleClick(); void doubleClick(); +public Q_SLOTS: + QVariant evaluateJavaScript (const QString&); + private Q_SLOTS: void expandToWebPage(); void paintPage(const QRect&); void doLoadProgress(int p); void doLoadFinished(bool ok); void setStatusBarMessage(const QString&); + void windowObjectCleared(); protected: QFxWebView(QFxWebViewPrivate &dd, QFxItem *parent); diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 75e5692..575876f 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -29,7 +29,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlenginedebug.cpp \ qml/qmlrewrite.cpp \ qml/qmlbasicscript.cpp \ - qml/qmlvaluetype.cpp + qml/qmlvaluetype.cpp \ + qml/qmlbindingoptimizations.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -75,7 +76,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlenginedebug_p.h \ qml/qmlrewrite_p.h \ qml/qpodvector_p.h \ - qml/qmlvaluetype_p.h + qml/qmlvaluetype_p.h \ + qml/qmlbindingoptimizations_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlbasicscript.cpp b/src/declarative/qml/qmlbasicscript.cpp index ca137c7..f3f9289 100644 --- a/src/declarative/qml/qmlbasicscript.cpp +++ b/src/declarative/qml/qmlbasicscript.cpp @@ -243,12 +243,7 @@ struct QmlBasicScriptCompiler To see if the QmlBasicScript engine can handle a binding, call compile() and check the return value, or isValid() afterwards. - To evaluate the binding, the QmlBasicScript instance needs some memory in - which to cache state. This may be allocated by calling newScriptState() - and destroyed by calling deleteScriptState(). The state data is then passed - to the run() method when evaluating the binding. - - To further accelerate binding, QmlBasicScript can return a precompiled + To accelerate binding, QmlBasicScript can return a precompiled version of itself that can be saved for future use. Call compileData() to get an opaque pointer to the compiled state, and compileDataSize() for the size of this data in bytes. This data can be saved and passed to future @@ -320,22 +315,6 @@ void QmlBasicScript::clear() } /*! - Return the script state memory for this script instance. This memory should - only be destroyed by calling deleteScriptState(). - */ -void *QmlBasicScript::newScriptState() -{ - return 0; -} - -/*! - Delete the \a data previously allocated by newScriptState(). - */ -void QmlBasicScript::deleteScriptState(void *) -{ -} - -/*! Dump the script instructions to stderr for debugging. */ void QmlBasicScript::dump() @@ -635,23 +614,10 @@ bool QmlBasicScriptCompiler::compileBinaryExpression(AST::Node *node) } /*! - \enum QmlBasicScript::CacheState - \value NoChange The query has not change. Any previous monitoring is still - valid. - \value Incremental The query has been incrementally changed. Any previous - monitoring is still valid, but needs to have the fresh properties added to - it. - \value Reset The entire query has been reset from the beginning. Any previous - monitoring is now invalid. -*/ - -/*! - Run the script in \a context and return the result. \a voidCache should - contain state memory previously acquired from newScript. + Run the script in \a context and return the result. */ -QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *cached) +QVariant QmlBasicScript::run(QmlContext *context, QObject *me) { - Q_UNUSED(voidCache); if (!isValid()) return QVariant(); @@ -660,8 +626,6 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c QStack<QVariant> stack; - CacheState state = NoChange; - for (int idx = 0; idx < d->instructionCount; ++idx) { const ScriptInstruction &instr = d->instructions()[idx]; @@ -671,31 +635,26 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c stack.push(QVariant::fromValue(contextPrivate->idValues[instr.fetch.idx].data())); enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(context, -1, contextPrivate->notifyIndex + instr.fetch.idx); - state = Reset; } break; case ScriptInstruction::FetchContextConstant: { - QObject *obj = contextPrivate->defaultObjects.at(0); - - stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); - if (obj && instr.constant.notify != 0) + stack.push(fetch_value(me, instr.constant.idx, instr.constant.type)); + if (me && instr.constant.notify != 0) enginePrivate->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); - state = Reset; + QmlEnginePrivate::CapturedProperty(me, instr.constant.idx, instr.constant.notify); } break; case ScriptInstruction::FetchRootConstant: { - QObject *obj = contextPrivate->defaultObjects.at(1); + QObject *obj = contextPrivate->defaultObjects.at(0); stack.push(fetch_value(obj, instr.constant.idx, instr.constant.type)); if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); - state = Reset; } break; @@ -708,7 +667,6 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c if (obj && instr.constant.notify != 0) enginePrivate->capturedProperties << QmlEnginePrivate::CapturedProperty(obj, instr.constant.idx, instr.constant.notify); - state = Reset; } break; @@ -733,14 +691,46 @@ QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *c } } - *cached = Reset; - if (stack.isEmpty()) return QVariant(); else return stack.top(); } +bool QmlBasicScript::isSingleIdFetch() const +{ + if (!isValid()) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::LoadIdObject; +} + +int QmlBasicScript::singleIdFetchIndex() const +{ + if (!isSingleIdFetch()) + return -1; + + return d->instructions()[0].fetch.idx; +} + +bool QmlBasicScript::isSingleContextProperty() const +{ + if (!isValid()) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::FetchContextConstant; +} + +int QmlBasicScript::singleContextPropertyIndex() const +{ + if (!isSingleContextProperty()) + return -1; + + return d->instructions()[0].constant.idx; +} + /*! Return a pointer to the script's compile data, or null if there is no data. */ diff --git a/src/declarative/qml/qmlbasicscript_p.h b/src/declarative/qml/qmlbasicscript_p.h index 539227f..5ad7735 100644 --- a/src/declarative/qml/qmlbasicscript_p.h +++ b/src/declarative/qml/qmlbasicscript_p.h @@ -95,12 +95,14 @@ public: void clear(); void dump(); - void *newScriptState(); - void deleteScriptState(void *); - enum CacheState { NoChange, Incremental, Reset }; - QVariant run(QmlContext *, void *, CacheState *); + QVariant run(QmlContext *, QObject *); + bool isSingleIdFetch() const; + int singleIdFetchIndex() const; + + bool isSingleContextProperty() const; + int singleContextPropertyIndex() const; private: int flags; QmlBasicScriptPrivate *d; diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 41cef49..45d20f4 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -47,6 +47,8 @@ #include <QVariant> #include <private/qfxperf_p.h> #include <QtCore/qdebug.h> +#include <private/qmlcontext_p.h> +#include <private/qmldeclarativedata_p.h> Q_DECLARE_METATYPE(QList<QObject *>); @@ -55,7 +57,7 @@ QT_BEGIN_NAMESPACE QML_DEFINE_NOCREATE_TYPE(QmlBinding); QmlBindingPrivate::QmlBindingPrivate() -: inited(false), updating(false), enabled(true), mePtr(0) +: updating(false), enabled(false) { } @@ -73,9 +75,6 @@ QmlBinding::QmlBinding(const QString &str, QObject *obj, QmlContext *ctxt, QObje QmlBinding::~QmlBinding() { - Q_D(QmlBinding); - if(d->mePtr) - *(d->mePtr) = 0; } void QmlBinding::setTarget(const QmlMetaProperty &prop) @@ -92,25 +91,6 @@ QmlMetaProperty QmlBinding::property() const return d->property; } -void QmlBinding::init() -{ - Q_D(QmlBinding); - - if (d->inited) - return; - d->inited = true; - update(); -} - -void QmlBinding::forceUpdate() -{ - Q_D(QmlBinding); - if (!d->inited) - init(); - else - update(); -} - void QmlBinding::update() { Q_D(QmlBinding); @@ -118,7 +98,7 @@ void QmlBinding::update() #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer<QFxPerf::BindableValueUpdate> bu; #endif - if (!d->inited || !d->enabled) + if (!d->enabled) return; if (!d->updating) { @@ -168,6 +148,21 @@ void QmlBinding::setEnabled(bool e) Q_D(QmlBinding); d->enabled = e; setTrackChange(e); + + if (e) { + addToObject(d->property.object()); + update(); + } else { + removeFromObject(); + } + + QmlAbstractBinding::setEnabled(e); +} + +int QmlBinding::propertyIndex() +{ + Q_D(QmlBinding); + return d->property.coreIndex(); } bool QmlBinding::enabled() const @@ -177,4 +172,54 @@ bool QmlBinding::enabled() const return d->enabled; } +QString QmlBinding::expression() const +{ + return QmlExpression::expression(); +} + +QmlAbstractBinding::QmlAbstractBinding() +: m_mePtr(0), m_prevBinding(0), m_nextBinding(0) +{ +} + +QmlAbstractBinding::~QmlAbstractBinding() +{ + removeFromObject(); + if (m_mePtr) + *m_mePtr = 0; +} + +void QmlAbstractBinding::addToObject(QObject *object) +{ + removeFromObject(); + + if (object) { + QmlDeclarativeData *data = QmlDeclarativeData::get(object, true); + m_nextBinding = data->bindings; + if (m_nextBinding) m_nextBinding->m_prevBinding = &m_nextBinding; + m_prevBinding = &data->bindings; + data->bindings = this; + } +} + +void QmlAbstractBinding::removeFromObject() +{ + if (m_prevBinding) { + *m_prevBinding = m_nextBinding; + if (m_nextBinding) m_nextBinding->m_prevBinding = m_prevBinding; + m_prevBinding = 0; + m_nextBinding = 0; + } +} + +QString QmlAbstractBinding::expression() const +{ + return QLatin1String("<Unknown>"); +} + +void QmlAbstractBinding::setEnabled(bool e) +{ + if (e) m_mePtr = 0; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index c2182d5..63b8a15 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -54,9 +54,36 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) +class QmlAbstractBinding +{ +public: + QmlAbstractBinding(); + virtual ~QmlAbstractBinding(); + + virtual QString expression() const; + + virtual void setEnabled(bool) = 0; + virtual int propertyIndex() = 0; + + virtual void update() = 0; + + void addToObject(QObject *); + void removeFromObject(); + +private: + friend class QmlDeclarativeData; + friend class QmlMetaProperty; + friend class QmlVME; + + QmlAbstractBinding **m_mePtr; + QmlAbstractBinding **m_prevBinding; + QmlAbstractBinding *m_nextBinding; +}; + class QmlContext; class QmlBindingPrivate; -class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression +class Q_DECLARATIVE_EXPORT QmlBinding : public QmlExpression, + public QmlAbstractBinding { Q_OBJECT public: @@ -67,12 +94,13 @@ public: void setTarget(const QmlMetaProperty &); QmlMetaProperty property() const; - void init(); - void forceUpdate(); - - void setEnabled(bool); bool enabled() const; + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool); + virtual int propertyIndex(); + virtual QString expression() const; + public Q_SLOTS: void update(); diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h index ec1a04a..963e2c1 100644 --- a/src/declarative/qml/qmlbinding_p.h +++ b/src/declarative/qml/qmlbinding_p.h @@ -65,13 +65,10 @@ class QmlBindingPrivate : public QmlExpressionPrivate public: QmlBindingPrivate(); - bool inited:1; bool updating:1; bool enabled:1; QmlMetaProperty property; - - QmlBinding **mePtr; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp new file mode 100644 index 0000000..e1f4a90 --- /dev/null +++ b/src/declarative/qml/qmlbindingoptimizations.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlbindingoptimizations_p.h" +#include <private/qmlcontext_p.h> + +QT_BEGIN_NAMESPACE + +/* + The QmlBinding_Id optimization handles expressions of the type: + + property: id + + where id is a local context id, and property is an object property. + Coercian between id and property must be checked outside the QmlBinding_Id - + it assumes that they coerce successfully. + + The QmlBinding_Id class avoids any signal slot connections, through the + special "bindings" linked list maintained in the + QmlContextPrivate::ContextGuard instance for each id object. +*/ +QmlBinding_Id::QmlBinding_Id(QObject *object, int propertyIdx, + QmlContext *context, int id) +: m_prev(0), m_next(0), m_object(object), m_propertyIdx(propertyIdx), m_id(id) +{ + QmlAbstractExpression::setContext(context); +} + +void QmlBinding_Id::setEnabled(bool e) +{ + if (e) { + addToObject(m_object); + update(); + } else { + removeFromObject(); + } + + QmlAbstractBinding::setEnabled(e); +} + +int QmlBinding_Id::propertyIndex() +{ + return m_propertyIdx; +} + +void QmlBinding_Id::update() +{ + QmlContextPrivate *ctxtPriv = + static_cast<QmlContextPrivate *>(QObjectPrivate::get(context())); + + if (ctxtPriv) { + + if (!m_prev) { + m_next = ctxtPriv->idValues[m_id].bindings; + if (m_next) m_next->m_prev = &m_next; + + m_prev = &ctxtPriv->idValues[m_id].bindings; + ctxtPriv->idValues[m_id].bindings = this; + } + + QObject *o = ctxtPriv->idValues[m_id].data(); + void *a[] = { &o, 0 }; + QMetaObject::metacall(m_object, QMetaObject::WriteProperty, + m_propertyIdx, a); + } +} + +void QmlBinding_Id::reset() +{ + if (m_prev) { + *m_prev = m_next; + if (m_next) m_next->m_prev = m_prev; + m_next = 0; + m_prev = 0; + } + + QObject *o = 0; + void *a[] = { &o, 0 }; + QMetaObject::metacall(m_object, QMetaObject::WriteProperty, + m_propertyIdx, a); +} + +/* + The QmlBinding_ObjectProperty optimization handles expressions of the type: + + property: objectProperty + + where both property and objectProperty are object properties on the target + object. Coercian between the two must be checked outside the + QmlBinding_ObjectProperty - it assumes that they coerce successfully. + + Due to dot properties, property does not have to be on the same object as + objectProperty. For example: + + anchors.fill: parent +*/ +QmlBinding_ObjProperty::QmlBinding_ObjProperty(QObject *object, int propertyIdx, + QObject *context, int contextIdx, + int notifyIdx) +: m_enabled(false), m_object(object), m_propertyIdx(propertyIdx), + m_context(context), m_contextIdx(contextIdx), m_notifyIdx(notifyIdx) +{ +} + +void QmlBinding_ObjProperty::setEnabled(bool e) +{ + m_enabled = e; + if (e) { + addToObject(m_object); + update(); + } else { + removeFromObject(); + } + + QmlAbstractBinding::setEnabled(e); +} + +int QmlBinding_ObjProperty::propertyIndex() +{ + return m_propertyIdx; +} + +void QmlBinding_ObjProperty::update() +{ + if (!m_enabled) + return; + + QObject *value = 0; + void *a[] = { &value, 0 }; + + // Read + QMetaObject::metacall(m_context, QMetaObject::ReadProperty, + m_contextIdx, a); + + // Write + QMetaObject::metacall(m_object, QMetaObject::WriteProperty, + m_propertyIdx, a); + + // Connect notify if needed. Only need to connect once, so we set + // m_notifyIdx back to -1 afterwards + static int slotIdx = -1; + if (m_notifyIdx != -1) { + if (slotIdx == -1) + slotIdx = QmlBinding_ObjProperty::staticMetaObject.indexOfMethod("update()"); + + QMetaObject::connect(m_context, m_notifyIdx, this, slotIdx); + m_notifyIdx = -1; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlbindingoptimizations_p.h new file mode 100644 index 0000000..2d2ffec --- /dev/null +++ b/src/declarative/qml/qmlbindingoptimizations_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDINGOPTIMIZATIONS_P_H +#define QMLBINDINGOPTIMIZATIONS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qmlexpression_p.h> +#include <QtDeclarative/qmlbinding.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class QmlBinding_Id : public QmlAbstractExpression, + public QmlAbstractBinding +{ +public: + QmlBinding_Id(QObject *object, int propertyIdx, + QmlContext *context, int id); + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool); + virtual int propertyIndex(); + virtual void update(); + + void reset(); + +private: + QmlBinding_Id **m_prev; + QmlBinding_Id *m_next; + + QObject *m_object; + int m_propertyIdx; + int m_id; +}; + +class QmlBinding_ObjProperty : public QObject, + public QmlAbstractExpression, + public QmlAbstractBinding +{ + Q_OBJECT +public: + QmlBinding_ObjProperty(QObject *object, int propertyIdx, + QObject *context, int contextIdx, int notifyIdx); + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool); + virtual int propertyIndex(); + +private slots: + virtual void update(); + +private: + bool m_enabled; + QObject *m_object; + int m_propertyIdx; + QObject *m_context; + int m_contextIdx; + int m_notifyIdx; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLBINDINGOPTIMIZATIONS_P_H + diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 6ef7cc2..75ed94b 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -1394,6 +1394,7 @@ void QmlCompiler::addId(const QString &id, QmlParser::Object *obj) Q_ASSERT(obj->id == id); obj->idIndex = compileState.ids.count(); compileState.ids.insert(id, obj); + compileState.idIndexes.insert(obj->idIndex, obj); } void QmlCompiler::addBindingReference(const BindingReference &ref) @@ -1904,7 +1905,7 @@ bool QmlCompiler::buildDynamicMeta(QmlParser::Object *obj, DynamicMetaMode mode) dynamicData.append((char *)&propertyData, sizeof(propertyData)); builder.addSignal(p.name + "Changed()"); - builder.addProperty(p.name, type, ii); + builder.addProperty(p.name, type, ii).setScriptable(true); } if (mode == ResolveAliases) { @@ -2064,7 +2065,41 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, const BindingReference &ref = compileState.bindings.value(binding); QmlInstruction store; - store.type = QmlInstruction::StoreCompiledBinding; + + QmlBasicScript bs; + if (ref.isBasicScript) + bs.load(ref.compiledData.constData() + sizeof(quint32)); + + if (bs.isSingleIdFetch()) { + int idIndex = bs.singleIdFetchIndex(); + QmlParser::Object *idObj = compileState.idIndexes.value(idIndex); + if (canCoerce(prop->type, idObj)) { + store.type = QmlInstruction::StoreIdOptBinding; + store.assignIdOptBinding.id = idIndex; + store.assignIdOptBinding.property = prop->index; + output->bytecode << store; + return; + } + } else if (bs.isSingleContextProperty()) { + int propIndex = bs.singleContextPropertyIndex(); + + QMetaProperty p = + ref.bindingContext.object->metaObject()->property(propIndex); + if ((p.notifySignalIndex() != -1 || p.isConstant()) && + canCoerce(prop->type, p.userType())) { + + store.type = QmlInstruction::StoreObjPropBinding; + store.assignObjPropBinding.property = prop->index; + store.assignObjPropBinding.contextIdx = propIndex; + store.assignObjPropBinding.context = ref.bindingContext.stack; + store.assignObjPropBinding.notifyIdx = p.notifySignalIndex(); + + output->bytecode << store; + return; + } + } + + store.type = QmlInstruction::StoreBinding; store.assignBinding.value = output->indexForByteArray(ref.compiledData); store.assignBinding.context = ref.bindingContext.stack; store.assignBinding.owner = ref.bindingContext.owner; @@ -2109,6 +2144,7 @@ bool QmlCompiler::completeComponentBuild() binding.compiledData = QByteArray(bs.compileData(), bs.compileDataSize()); type = QmlExpressionPrivate::BasicScriptEngineData; + binding.isBasicScript = true; } else { type = QmlExpressionPrivate::PreTransformedQtScriptData; @@ -2122,6 +2158,7 @@ bool QmlCompiler::completeComponentBuild() QByteArray((const char *)&length, sizeof(quint32)) + QByteArray((const char *)expression.constData(), expression.length() * sizeof(QChar)); + binding.isBasicScript = false; } binding.compiledData.prepend(QByteArray((const char *)&type, sizeof(quint32))); @@ -2138,8 +2175,7 @@ bool QmlCompiler::completeComponentBuild() */ bool QmlCompiler::canCoerce(int to, QmlParser::Object *from) { - const QMetaObject *toMo = - QmlMetaType::rawMetaObjectForType(to); + const QMetaObject *toMo = QmlMetaType::rawMetaObjectForType(to); const QMetaObject *fromMo = from->metaObject(); while (fromMo) { @@ -2150,6 +2186,23 @@ bool QmlCompiler::canCoerce(int to, QmlParser::Object *from) return false; } +/*! + Returns true if from can be assigned to a (QObject) property of type + to. +*/ +bool QmlCompiler::canCoerce(int to, int from) +{ + const QMetaObject *toMo = QmlMetaType::rawMetaObjectForType(to); + const QMetaObject *fromMo = QmlMetaType::rawMetaObjectForType(from); + + while (fromMo) { + if (fromMo == toMo) + return true; + fromMo = fromMo->superClass(); + } + return false; +} + QmlType *QmlCompiler::toQmlType(QmlParser::Object *from) { // ### Optimize diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 094c05a..4f56169 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -226,6 +226,7 @@ private: static int findSignalByName(const QMetaObject *, const QByteArray &name); static bool canCoerce(int to, QmlParser::Object *from); + static bool canCoerce(int to, int from); static QmlType *toQmlType(QmlParser::Object *from); QStringList deferredProperties(QmlParser::Object *); @@ -236,6 +237,7 @@ private: QmlParser::Variant expression; QmlParser::Property *property; QmlParser::Value *value; + bool isBasicScript; QByteArray compiledData; BindingContext bindingContext; }; @@ -247,6 +249,7 @@ private: : parserStatusCount(0), savedObjects(0), pushedProperties(0), root(0) {} QHash<QString, QmlParser::Object *> ids; + QHash<int, QmlParser::Object *> idIndexes; int parserStatusCount; int savedObjects; int pushedProperties; diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index d4e383d..c30efca 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -533,11 +533,11 @@ void QmlComponent::completeCreate() QFxPerfTimer<QFxPerf::BindInit> bi; #endif for (int ii = 0; ii < d->bindValues.count(); ++ii) { - QmlEnginePrivate::SimpleList<QmlBinding> bv = + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bv = d->bindValues.at(ii); for (int jj = 0; jj < bv.count; ++jj) { if(bv.at(jj)) - bv.at(jj)->init(); + bv.at(jj)->setEnabled(true); } QmlEnginePrivate::clear(bv); } diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index a7a3230..4b459c2 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -88,7 +88,7 @@ public: int count; QmlCompiledData *cc; - QList<QmlEnginePrivate::SimpleList<QmlBinding> > bindValues; + QList<QmlEnginePrivate::SimpleList<QmlAbstractBinding> > bindValues; QList<QmlEnginePrivate::SimpleList<QmlParserStatus> > parserStatus; bool completePending; diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 8a2732d..451dbcc 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -47,6 +47,7 @@ #include <qscriptengine.h> #include <QtCore/qvarlengtharray.h> #include <QtCore/qdebug.h> +#include <private/qmlbindingoptimizations_p.h> // 6-bits #define MAXIMUM_DEFAULT_OBJECTS 63 @@ -82,6 +83,9 @@ void QmlContextPrivate::destroyed(ContextGuard *guard) if (parent && QObjectPrivate::get(parent)->wasDeleted) return; + while(guard->bindings) + guard->bindings->reset(); + for (int ii = 0; ii < idValueCount; ++ii) { if (&idValues[ii] == guard) { QMetaObject::activate(q, ii + notifyIndex, 0); @@ -106,8 +110,6 @@ void QmlContextPrivate::init() else scopeChain = parent->d_func()->scopeChain; scopeChain.prepend(scopeObj); - - contextData.context = q; } void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) @@ -278,26 +280,23 @@ QmlContext::~QmlContext() (*iter)->d_func()->parent = 0; } - QmlExpressionPrivate *expression = d->expressions; + QmlAbstractExpression *expression = d->expressions; while (expression) { - QmlExpressionPrivate *nextExpression = expression->nextExpression; + QmlAbstractExpression *nextExpression = expression->m_nextExpression; - expression->ctxt = 0; - expression->prevExpression = 0; - expression->nextExpression = 0; + expression->m_context = 0; + expression->m_prevExpression = 0; + expression->m_nextExpression = 0; expression = nextExpression; } for (int ii = 0; ii < d->contextObjects.count(); ++ii) { QObjectPrivate *p = QObjectPrivate::get(d->contextObjects.at(ii)); - QmlSimpleDeclarativeData *data = - static_cast<QmlSimpleDeclarativeData *>(p->declarativeData); - if(data && (data->flags & QmlSimpleDeclarativeData::Extended)) { + QmlDeclarativeData *data = + static_cast<QmlDeclarativeData *>(p->declarativeData); + if(data) data->context = 0; - } else { - p->declarativeData = 0; - } } d->contextObjects.clear(); diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h index 1f29ca2..70a81fc 100644 --- a/src/declarative/qml/qmlcontext.h +++ b/src/declarative/qml/qmlcontext.h @@ -89,7 +89,6 @@ private: friend class QmlComponent; friend class QmlScriptPrivate; friend class QmlBoundSignalProxy; - friend class QmlSimpleDeclarativeData; QmlContext(QmlContext *parent, QObject *objParent, bool); QmlContext(QmlEngine *, bool); }; diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 60655ae..84d990c 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -68,6 +68,8 @@ class QmlExpression; class QmlEngine; class QmlExpression; class QmlExpressionPrivate; +class QmlAbstractExpression; +class QmlBinding_Id; class QmlContextPrivate : public QObjectPrivate { @@ -104,18 +106,19 @@ public: void invalidateEngines(); QSet<QmlContext *> childContexts; - QmlExpressionPrivate *expressions; + QmlAbstractExpression *expressions; - QmlSimpleDeclarativeData contextData; QObjectList contextObjects; struct ContextGuard : public QGuard<QObject> { + ContextGuard() : priv(0), bindings(0) {} QmlContextPrivate *priv; + QmlBinding_Id *bindings; ContextGuard &operator=(QObject *obj) { (QGuard<QObject>&)*this = obj; return *this; } - void objectDestroyed(QObject *o) { priv->destroyed(this); } + void objectDestroyed(QObject *) { priv->destroyed(this); } }; ContextGuard *idValues; int idValueCount; diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index b473e77..5a51eb7 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -57,113 +57,36 @@ QT_BEGIN_NAMESPACE -class QmlSimpleDeclarativeData : public QDeclarativeData -{ -public: - QmlSimpleDeclarativeData() : flags(0), context(0) {} - - virtual void destroyed(QObject *); - enum Flag { Instance = 0x00000001, Extended = 0x00000002 }; - quint32 flags; - QmlContext *context; - - static inline QmlSimpleDeclarativeData *get(QObject *object, - bool create = false); -}; - class QmlCompiledData; -class QmlInstanceDeclarativeData : public QmlSimpleDeclarativeData +class QmlAbstractBinding; +class QmlDeclarativeData : public QDeclarativeData { public: - QmlInstanceDeclarativeData() : deferredComponent(0) { flags |= Instance; } + QmlDeclarativeData(QmlContext *context = 0); virtual void destroyed(QObject *); - QmlCompiledData *deferredComponent; - unsigned int deferredIdx; - - static inline QmlInstanceDeclarativeData *get(QObject *object, - bool create = false); -}; - -class QmlExtendedDeclarativeData : public QmlInstanceDeclarativeData -{ -public: - QmlExtendedDeclarativeData() { flags |= Extended; } - - QHash<int, QObject *> attachedProperties; - - static inline QmlExtendedDeclarativeData *get(QObject *object, - bool create = false); -}; - -QmlSimpleDeclarativeData * -QmlSimpleDeclarativeData::get(QObject *object, bool create) -{ - QObjectPrivate *priv = QObjectPrivate::get(object); - - if (create && !priv->declarativeData) - priv->declarativeData = new QmlInstanceDeclarativeData; - - return static_cast<QmlSimpleDeclarativeData *>(priv->declarativeData); -} - -QmlInstanceDeclarativeData * -QmlInstanceDeclarativeData::get(QObject *object, bool create) -{ - QObjectPrivate *priv = QObjectPrivate::get(object); - - QmlSimpleDeclarativeData *simple = - static_cast<QmlSimpleDeclarativeData *>(priv->declarativeData); - - if (simple && (simple->flags & Instance)) { - return static_cast<QmlInstanceDeclarativeData *>(simple); - } else if (create && simple) { - QmlInstanceDeclarativeData *rv = new QmlInstanceDeclarativeData; - rv->context = simple->context; - simple->destroyed(object); - priv->declarativeData = rv; - return rv; - } else if (create) { - QmlInstanceDeclarativeData *rv = new QmlInstanceDeclarativeData; - priv->declarativeData = rv; - return rv; - } - return 0; -} - -QmlExtendedDeclarativeData * -QmlExtendedDeclarativeData::get(QObject *object, bool create) -{ - QObjectPrivate *priv = QObjectPrivate::get(object); + QmlContext *context; + QmlAbstractBinding *bindings; - QmlSimpleDeclarativeData *simple = - static_cast<QmlSimpleDeclarativeData *>(priv->declarativeData); + QmlCompiledData *deferredComponent; // Can't this be found from the context? + unsigned int deferredIdx; - if (simple && (simple->flags & Extended)) { - return static_cast<QmlExtendedDeclarativeData *>(simple); - } else if (create && simple) { - QmlExtendedDeclarativeData *rv = new QmlExtendedDeclarativeData; - rv->context = simple->context; + QHash<int, QObject *> *attachedProperties; - if (simple->flags & Instance) { - QmlInstanceDeclarativeData *instance = - static_cast<QmlInstanceDeclarativeData *>(priv->declarativeData); - rv->deferredComponent = instance->deferredComponent; - rv->deferredIdx = instance->deferredIdx; - delete simple; + static QmlDeclarativeData *get(const QObject *object, bool create = false) { + QObjectPrivate *priv = + QObjectPrivate::get(const_cast<QObject *>(object)); + if (priv && priv->declarativeData) { + return static_cast<QmlDeclarativeData *>(priv->declarativeData); + } else if (create && priv) { + priv->declarativeData = new QmlDeclarativeData; + return static_cast<QmlDeclarativeData *>(priv->declarativeData); } else { - simple->destroyed(object); + return 0; } - priv->declarativeData = rv; - return rv; - } else if (create) { - QmlExtendedDeclarativeData *rv = new QmlExtendedDeclarativeData; - priv->declarativeData = rv; - return rv; } - return 0; -} +}; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 68ad655..bdbf2e7 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -121,16 +121,8 @@ QmlEnginePrivate::~QmlEnginePrivate() clear(parserStatus[ii]); } -void QmlEnginePrivate::clear(SimpleList<QmlBinding> &bvs) +void QmlEnginePrivate::clear(SimpleList<QmlAbstractBinding> &bvs) { - for (int ii = 0; ii < bvs.count; ++ii) { - QmlBinding *bv = bvs.at(ii); - if(bv) { - QmlBindingPrivate *p = - static_cast<QmlBindingPrivate *>(QObjectPrivate::get(bv)); - p->mePtr = 0; - } - } bvs.clear(); } @@ -427,8 +419,8 @@ QmlContext *QmlEngine::contextForObject(const QObject *object) QObjectPrivate *priv = QObjectPrivate::get(const_cast<QObject *>(object)); - QmlSimpleDeclarativeData *data = - static_cast<QmlSimpleDeclarativeData *>(priv->declarativeData); + QmlDeclarativeData *data = + static_cast<QmlDeclarativeData *>(priv->declarativeData); return data?data->context:0; } @@ -444,8 +436,8 @@ void QmlEngine::setContextForObject(QObject *object, QmlContext *context) { QObjectPrivate *priv = QObjectPrivate::get(object); - QmlSimpleDeclarativeData *data = - static_cast<QmlSimpleDeclarativeData *>(priv->declarativeData); + QmlDeclarativeData *data = + static_cast<QmlDeclarativeData *>(priv->declarativeData); if (data && data->context) { qWarning("QmlEngine::setContextForObject(): Object already has a QmlContext"); @@ -453,7 +445,7 @@ void QmlEngine::setContextForObject(QObject *object, QmlContext *context) } if (!data) { - priv->declarativeData = &context->d_func()->contextData; + priv->declarativeData = new QmlDeclarativeData(context); } else { data->context = context; } @@ -463,7 +455,7 @@ void QmlEngine::setContextForObject(QObject *object, QmlContext *context) void qmlExecuteDeferred(QObject *object) { - QmlInstanceDeclarativeData *data = QmlInstanceDeclarativeData::get(object); + QmlDeclarativeData *data = QmlDeclarativeData::get(object); if (data && data->deferredComponent) { QmlVME vme; @@ -487,10 +479,9 @@ QmlEngine *qmlEngine(const QObject *obj) QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool create) { - QmlExtendedDeclarativeData *edata = - QmlExtendedDeclarativeData::get(const_cast<QObject *>(object), true); + QmlDeclarativeData *data = QmlDeclarativeData::get(object); - QObject *rv = edata->attachedProperties.value(id); + QObject *rv = data->attachedProperties?data->attachedProperties->value(id):0; if (rv || !create) return rv; @@ -500,23 +491,38 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre rv = pf(const_cast<QObject *>(object)); - if (rv) - edata->attachedProperties.insert(id, rv); + if (rv) { + if (!data->attachedProperties) + data->attachedProperties = new QHash<int, QObject *>(); + data->attachedProperties->insert(id, rv); + } return rv; } -void QmlSimpleDeclarativeData::destroyed(QObject *object) +QmlDeclarativeData::QmlDeclarativeData(QmlContext *ctxt) +: context(ctxt), bindings(0), deferredComponent(0), attachedProperties(0) { - if (context) - context->d_func()->contextObjects.removeAll(object); } -void QmlInstanceDeclarativeData::destroyed(QObject *object) +void QmlDeclarativeData::destroyed(QObject *object) { - QmlSimpleDeclarativeData::destroyed(object); if (deferredComponent) deferredComponent->release(); + if (attachedProperties) + delete attachedProperties; + if (context) + static_cast<QmlContextPrivate *>(QObjectPrivate::get(context))->contextObjects.removeAll(object); + + QmlAbstractBinding *binding = bindings; + while (binding) { + QmlAbstractBinding *next = binding->m_nextBinding; + binding->m_prevBinding = 0; + binding->m_nextBinding = 0; + delete binding; + binding = next; + } + delete this; } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 602321d..d2e3ef4 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -86,6 +86,7 @@ class QmlValueTypeScriptClass; class QScriptEngineDebugger; class QNetworkReply; class QNetworkAccessManager; +class QmlAbstractBinding; class QmlEnginePrivate : public QObjectPrivate { @@ -160,10 +161,10 @@ public: } }; - static void clear(SimpleList<QmlBinding> &); + static void clear(SimpleList<QmlAbstractBinding> &); static void clear(SimpleList<QmlParserStatus> &); - QList<SimpleList<QmlBinding> > bindValues; + QList<SimpleList<QmlAbstractBinding> > bindValues; QList<SimpleList<QmlParserStatus> > parserStatus; QmlComponent *rootComponent; diff --git a/src/declarative/qml/qmlenginedebug.cpp b/src/declarative/qml/qmlenginedebug.cpp index c26f3b7..0e78cad 100644 --- a/src/declarative/qml/qmlenginedebug.cpp +++ b/src/declarative/qml/qmlenginedebug.cpp @@ -97,7 +97,7 @@ QmlEngineDebugServer::propertyData(QObject *obj, int propIdx) rv.type = QmlObjectProperty::Unknown; rv.name = prop.name(); - QmlBinding *binding = QmlMetaProperty(obj, rv.name).binding(); + QmlAbstractBinding *binding = QmlMetaProperty(obj, rv.name).binding(); if (binding) rv.binding = binding->expression(); diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index a9175ea..f8e78d7 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -51,33 +51,23 @@ Q_DECLARE_METATYPE(QList<QObject *>); QT_BEGIN_NAMESPACE QmlExpressionPrivate::QmlExpressionPrivate() -: nextExpression(0), prevExpression(0), ctxt(0), expressionFunctionValid(false), expressionRewritten(false), sseData(0), me(0), trackChange(true), line(-1), guardList(0), guardListLength(0) +: expressionFunctionValid(false), expressionRewritten(false), me(0), + trackChange(true), line(-1), guardList(0), guardListLength(0) { } void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, QObject *me) { - Q_Q(QmlExpression); - expression = expr; - this->ctxt = ctxt; - if (ctxt) { - QmlContextPrivate *cp = ctxt->d_func(); - nextExpression = cp->expressions; - if (nextExpression) nextExpression->prevExpression = &nextExpression; - prevExpression = &cp->expressions; - cp->expressions = this; - } + QmlAbstractExpression::setContext(ctxt); this->me = me; } void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, QObject *me) { - Q_Q(QmlExpression); - quint32 *data = (quint32 *)expr; Q_ASSERT(*data == BasicScriptEngineData || *data == PreTransformedQtScriptData); @@ -88,21 +78,12 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, expressionRewritten = true; } - this->ctxt = ctxt; - if (ctxt) { - QmlContextPrivate *cp = ctxt->d_func(); - nextExpression = cp->expressions; - if (nextExpression) nextExpression->prevExpression = &nextExpression; - prevExpression = &cp->expressions; - cp->expressions = this; - } + QmlAbstractExpression::setContext(ctxt); this->me = me; } QmlExpressionPrivate::~QmlExpressionPrivate() { - sse.deleteScriptState(sseData); - sseData = 0; if (guardList) { delete [] guardList; guardList = 0; } } @@ -161,12 +142,6 @@ QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, */ QmlExpression::~QmlExpression() { - Q_D(QmlExpression); - if (d->prevExpression) { - *(d->prevExpression) = d->nextExpression; - if (d->nextExpression) - d->nextExpression->prevExpression = d->prevExpression; - } } /*! @@ -176,7 +151,7 @@ QmlExpression::~QmlExpression() QmlEngine *QmlExpression::engine() const { Q_D(const QmlExpression); - return d->ctxt?d->ctxt->engine():0; + return d->context()?d->context()->engine():0; } /*! @@ -186,7 +161,7 @@ QmlEngine *QmlExpression::engine() const QmlContext *QmlExpression::context() const { Q_D(const QmlExpression); - return d->ctxt; + return d->context(); } /*! @@ -215,10 +190,6 @@ void QmlExpression::clearExpression() void QmlExpression::setExpression(const QString &expression) { Q_D(QmlExpression); - if (d->sseData) { - d->sse.deleteScriptState(d->sseData); - d->sseData = 0; - } d->clearGuards(); @@ -230,22 +201,13 @@ void QmlExpression::setExpression(const QString &expression) d->sse.clear(); } -QVariant QmlExpressionPrivate::evalSSE(QmlBasicScript::CacheState &cacheState) +QVariant QmlExpressionPrivate::evalSSE() { #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer<QFxPerf::BindValueSSE> perfsse; #endif - QmlContextPrivate *ctxtPriv = ctxt->d_func(); - if (me) - ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount , me); - - if (!sseData) - sseData = sse.newScriptState(); - QVariant rv = sse.run(ctxt, sseData, &cacheState); - - if (me) - ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); + QVariant rv = sse.run(context(), me); return rv; } @@ -256,8 +218,8 @@ QVariant QmlExpressionPrivate::evalQtScript() QFxPerfTimer<QFxPerf::BindValueQt> perfqt; #endif - QmlContextPrivate *ctxtPriv = ctxt->d_func(); - QmlEngine *engine = ctxt->engine(); + QmlContextPrivate *ctxtPriv = context()->d_func(); + QmlEngine *engine = context()->engine(); if (me) ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me); @@ -360,15 +322,13 @@ QVariant QmlExpression::value() Q_D(QmlExpression); QVariant rv; - if (!d->ctxt || !engine() || (!d->sse.isValid() && d->expression.isEmpty())) + if (!d->context() || (!d->sse.isValid() && d->expression.isEmpty())) return rv; #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer<QFxPerf::BindValue> perf; #endif - QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset; - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine()); QmlExpression *lastCurrentExpression = ep->currentExpression; @@ -378,7 +338,7 @@ QVariant QmlExpression::value() ep->currentExpression = this; if (d->sse.isValid()) { - rv = d->evalSSE(cacheState); + rv = d->evalSSE(); } else { rv = d->evalQtScript(); } @@ -589,5 +549,52 @@ void QmlExpressionPrivate::updateGuards(const QPODVector<QmlEnginePrivate::Captu calling QmlExpression::value()) before this signal will be emitted. */ +QmlAbstractExpression::QmlAbstractExpression() +: m_context(0), m_prevExpression(0), m_nextExpression(0) +{ +} + +QmlAbstractExpression::~QmlAbstractExpression() +{ + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + } +} + +QmlContext *QmlAbstractExpression::context() const +{ + return m_context; +} + +void QmlAbstractExpression::setContext(QmlContext *context) +{ + if (m_prevExpression) { + *m_prevExpression = m_nextExpression; + if (m_nextExpression) + m_nextExpression->m_prevExpression = m_prevExpression; + m_prevExpression = 0; + m_nextExpression = 0; + } + + m_context = context; + + if (m_context) { + QmlContextPrivate *cp = + static_cast<QmlContextPrivate *>(QObjectPrivate::get(m_context)); + m_nextExpression = cp->expressions; + if (m_nextExpression) + m_nextExpression->m_prevExpression = &m_nextExpression; + m_prevExpression = &cp->expressions; + cp->expressions = this; + } +} + +bool QmlAbstractExpression::isValid() const +{ + return m_context != 0; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index f607898..997bf8d 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -61,19 +61,33 @@ QT_BEGIN_NAMESPACE +class QmlAbstractExpression +{ +public: + QmlAbstractExpression(); + virtual ~QmlAbstractExpression(); + + bool isValid() const; + + QmlContext *context() const; + void setContext(QmlContext *); + +private: + friend class QmlContext; + QmlContext *m_context; + QmlAbstractExpression **m_prevExpression; + QmlAbstractExpression *m_nextExpression; +}; + class QmlExpression; class QString; -class QmlExpressionPrivate : public QObjectPrivate +class QmlExpressionPrivate : public QObjectPrivate, public QmlAbstractExpression { Q_DECLARE_PUBLIC(QmlExpression) public: QmlExpressionPrivate(); ~QmlExpressionPrivate(); - // Forms the QmlContext "expressions" linked list - QmlExpressionPrivate *nextExpression; - QmlExpressionPrivate **prevExpression; - enum CompiledDataType { BasicScriptEngineData = 1, PreTransformedQtScriptData = 2 @@ -82,21 +96,19 @@ public: void init(QmlContext *, const QString &, QObject *); void init(QmlContext *, void *, QmlRefCount *, QObject *); - QmlContext *ctxt; QString expression; bool expressionFunctionValid:1; bool expressionRewritten:1; QScriptValue expressionFunction; QmlBasicScript sse; - void *sseData; QObject *me; bool trackChange; QString fileName; int line; - QVariant evalSSE(QmlBasicScript::CacheState &cacheState); + QVariant evalSSE(); QVariant evalQtScript(); struct SignalGuard : public QGuard<QObject> { diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index 889a057..fd912ac 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -140,7 +140,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) case QmlInstruction::AssignCustomType: qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; break; - case QmlInstruction::StoreCompiledBinding: + case QmlInstruction::StoreBinding: qWarning() << idx << "\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context; break; case QmlInstruction::StoreValueSource: diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index e6b8de6..7f3498f 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -122,9 +122,11 @@ public: // Unresolved single assignment // AssignSignalObject, /* assignSignalObject */ - AssignCustomType, /* assignCustomType */ + AssignCustomType, /* assignCustomType */ - StoreCompiledBinding, /* assignBinding */ + StoreBinding, /* assignBinding */ + StoreIdOptBinding, /* assignIdOptBinding */ + StoreObjPropBinding, /* assignObjPropBinding */ StoreValueSource, /* assignValueSource */ BeginObject, /* begin */ @@ -189,6 +191,16 @@ public: } assignBinding; struct { int property; + int id; + } assignIdOptBinding; + struct { + int property; + int contextIdx; + short context; + short notifyIdx; + } assignObjPropBinding; + struct { + int property; } fetch; struct { int property; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 09ca872..d986077 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -51,6 +51,7 @@ #include <QtCore/qdebug.h> #include <QtDeclarative/qmlengine.h> #include <private/qmlengine_p.h> +#include <private/qmldeclarativedata_p.h> Q_DECLARE_METATYPE(QList<QObject *>); @@ -509,20 +510,21 @@ QMetaProperty QmlMetaProperty::property() const Returns the binding associated with this property, or 0 if no binding exists. */ -QmlBinding *QmlMetaProperty::binding() const +QmlAbstractBinding *QmlMetaProperty::binding() const { if (!isProperty() || (type() & Attached) || !d->object) return 0; - const QObjectList &children = object()->children(); - for (QObjectList::ConstIterator iter = children.begin(); - iter != children.end(); ++iter) { - QObject *child = *iter; - if (child->metaObject() == &QmlBinding::staticMetaObject) { - QmlBinding *v = static_cast<QmlBinding *>(child); - if (v->property() == *this && v->enabled()) - return v; - } + QmlDeclarativeData *data = QmlDeclarativeData::get(d->object); + if (!data) + return 0; + + QmlAbstractBinding *binding = data->bindings; + while (binding) { + // ### This wont work for value types + if (binding->propertyIndex() == d->coreIdx) + return binding; + binding = binding->m_nextBinding; } return 0; } @@ -534,41 +536,32 @@ QmlBinding *QmlMetaProperty::binding() const \a binding will be enabled, and the returned binding (if any) will be disabled. */ -QmlBinding *QmlMetaProperty::setBinding(QmlBinding *binding) const +QmlAbstractBinding * +QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const { if (!isProperty() || (type() & Attached) || !d->object) return 0; - const QObjectList &children = object()->children(); - for (QObjectList::ConstIterator iter = children.begin(); - iter != children.end(); ++iter) { - QObject *child = *iter; - if (child->metaObject() == &QmlBinding::staticMetaObject) { - QmlBinding *v = static_cast<QmlBinding *>(child); - if (v->property() == *this && v->enabled()) { - - v->setEnabled(false); - - if (binding) { - binding->setParent(object()); - binding->setTarget(*this); - binding->setEnabled(true); - binding->forceUpdate(); - } + QmlDeclarativeData *data = QmlDeclarativeData::get(d->object, true); - return v; + QmlAbstractBinding *binding = data->bindings; + while (binding) { + // ### This wont work for value types + if (binding->propertyIndex() == d->coreIdx) { + binding->setEnabled(false); - } + if (newBinding) + newBinding->setEnabled(true); + + return binding; // ### QmlAbstractBinding; } - } - if (binding) { - binding->setParent(object()); - binding->setTarget(*this); - binding->setEnabled(true); - binding->forceUpdate(); + binding = binding->m_nextBinding; } + if (newBinding) + newBinding->setEnabled(true); + return 0; } @@ -901,12 +894,11 @@ void QmlMetaProperty::write(const QVariant &value) const if (!d->object) return; - QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); if (type() & SignalProperty) { d->writeSignalProperty(value); - } else if (prop.name()) { + } else if (d->coreIdx != -1) { d->writeValueProperty(value); diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index 434ff55..7b9ff47 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QObject; -class QmlBinding; +class QmlAbstractBinding; class QStringList; class QVariant; struct QMetaObject; @@ -122,8 +122,8 @@ public: QMetaProperty property() const; - QmlBinding *binding() const; - QmlBinding *setBinding(QmlBinding *) const; + QmlAbstractBinding *binding() const; + QmlAbstractBinding *setBinding(QmlAbstractBinding *) const; static QmlMetaProperty createProperty(QObject *, const QString &); diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index 50bc676..512650f 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -798,6 +798,9 @@ QmlMetaType::TypeCategory QmlMetaType::typeCategory(int userType) { if (userType < 0) return Unknown; + if (userType == QMetaType::QObjectStar) + return Object; + QReadLocker lock(metaTypeDataLock()); QmlMetaTypeData *data = metaTypeData(); if (userType < data->objects.size() && data->objects.testBit(userType)) @@ -812,6 +815,9 @@ QmlMetaType::TypeCategory QmlMetaType::typeCategory(int userType) bool QmlMetaType::isObject(int userType) { + if (userType == QMetaType::QObjectStar) + return true; + QReadLocker lock(metaTypeDataLock()); QmlMetaTypeData *data = metaTypeData(); return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index bf3b31a..79b1d89 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -65,6 +65,7 @@ #include <QtCore/qvarlengtharray.h> #include <private/qmlbinding_p.h> #include <private/qmlcontext_p.h> +#include <private/qmlbindingoptimizations_p.h> QT_BEGIN_NAMESPACE @@ -111,7 +112,7 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledData *comp, int start, int cou void QmlVME::runDeferred(QObject *object) { - QmlInstanceDeclarativeData *data = QmlInstanceDeclarativeData::get(object); + QmlDeclarativeData *data = QmlDeclarativeData::get(object); if (!data || !data->context || !data->deferredComponent) return; @@ -138,7 +139,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData const QList<float> &floatData = comp->floatData; - QmlEnginePrivate::SimpleList<QmlBinding> bindValues; + QmlEnginePrivate::SimpleList<QmlAbstractBinding> bindValues; QmlEnginePrivate::SimpleList<QmlParserStatus> parserStatus; QStack<ListInstance> qliststack; @@ -154,7 +155,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData case QmlInstruction::Init: { if (instr.init.bindingsSize) - bindValues = QmlEnginePrivate::SimpleList<QmlBinding>(instr.init.bindingsSize); + bindValues = QmlEnginePrivate::SimpleList<QmlAbstractBinding>(instr.init.bindingsSize); if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList<QmlParserStatus>(instr.init.parserStatusSize); @@ -528,7 +529,7 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData } break; - case QmlInstruction::StoreCompiledBinding: + case QmlInstruction::StoreBinding: { QObject *target = stack.at(stack.count() - 1 - instr.assignBinding.owner); @@ -540,15 +541,41 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData QmlBinding *bind = new QmlBinding((void *)datas.at(instr.assignBinding.value).constData(), comp, context, ctxt, 0); bindValues.append(bind); - QmlBindingPrivate *p = - static_cast<QmlBindingPrivate *>(QObjectPrivate::get(bind)); - p->mePtr = &bindValues.values[bindValues.count - 1]; - QFx_setParent_noEvent(bind, target); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->addToObject(target); bind->setTarget(mp); } break; + case QmlInstruction::StoreIdOptBinding: + { + QObject *target = stack.top(); + + QmlBinding_Id *bind = + new QmlBinding_Id(target, instr.assignIdOptBinding.property, + ctxt, instr.assignIdOptBinding.id); + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->addToObject(target); + } + break; + + case QmlInstruction::StoreObjPropBinding: + { + QObject *target = stack.top(); + QObject *context = + stack.at(stack.count() - 1 - instr.assignObjPropBinding.context); + + QmlBinding_ObjProperty *bind = + new QmlBinding_ObjProperty(target, instr.assignObjPropBinding.property, context, instr.assignObjPropBinding.contextIdx, instr.assignObjPropBinding.notifyIdx); + + bindValues.append(bind); + bind->m_mePtr = &bindValues.values[bindValues.count - 1]; + bind->addToObject(target); + } + break; + case QmlInstruction::StoreValueSource: { QmlPropertyValueSource *vs = @@ -725,8 +752,8 @@ QObject *QmlVME::run(QStack<QObject *> &stack, QmlContext *ctxt, QmlCompiledData { if (instr.defer.deferCount) { QObject *target = stack.top(); - QmlInstanceDeclarativeData *data = - QmlInstanceDeclarativeData::get(target, true); + QmlDeclarativeData *data = + QmlDeclarativeData::get(target, true); comp->addref(); data->deferredComponent = comp; data->deferredIdx = ii; diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp index 33a31a4..9ce63b1 100644 --- a/src/declarative/qml/qmlvmemetaobject.cpp +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -168,8 +168,7 @@ int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) QmlContextPrivate *ctxtPriv = (QmlContextPrivate *)QObjectPrivate::get(ctxt); - QObject *target = - *(QObject **)ctxtPriv->propertyValues[d->contextIdx].data(); + QObject *target = ctxtPriv->idValues[d->contextIdx].data(); if (!target) return -1; if (c == QMetaObject::ReadProperty && !aConnected.testBit(id)) { diff --git a/src/declarative/util/qmlsetproperties.cpp b/src/declarative/util/qmlsetproperties.cpp index 1cd4a79..482405c 100644 --- a/src/declarative/util/qmlsetproperties.cpp +++ b/src/declarative/util/qmlsetproperties.cpp @@ -334,9 +334,10 @@ QmlSetProperties::ActionList QmlSetProperties::actions() if (d->isExplicit) { a.toValue = d->expressions.at(ii).second->value(); } else { - a.toBinding = new QmlBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this)); + QmlBinding *newBinding = new QmlBinding(d->expressions.at(ii).second->expression(), object(), qmlContext(this)); + newBinding->setTarget(prop); + a.toBinding = newBinding; a.deletableToBinding = true; - a.toBinding->setTarget(prop); } list << a; diff --git a/src/declarative/util/qmlstate.h b/src/declarative/util/qmlstate.h index 9eb7aee..46659c6 100644 --- a/src/declarative/util/qmlstate.h +++ b/src/declarative/util/qmlstate.h @@ -70,8 +70,8 @@ public: QVariant fromValue; QVariant toValue; - QmlBinding *fromBinding; - QmlBinding *toBinding; + QmlAbstractBinding *fromBinding; + QmlAbstractBinding *toBinding; ActionEvent *event; //strictly for matching diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h index b601b57..63fc6da 100644 --- a/src/declarative/util/qmlstate_p.h +++ b/src/declarative/util/qmlstate_p.h @@ -83,7 +83,7 @@ public: QmlMetaProperty property; QVariant value; - QmlBinding *binding; + QmlAbstractBinding *binding; QObject *specifiedObject; QString specifiedProperty; ActionEvent *event; diff --git a/src/declarative/util/qmlstategroup.cpp b/src/declarative/util/qmlstategroup.cpp index 3a07fbe..bb40a8b 100644 --- a/src/declarative/util/qmlstategroup.cpp +++ b/src/declarative/util/qmlstategroup.cpp @@ -274,7 +274,7 @@ void QmlStateGroupPrivate::setCurrentStateInternal(const QString &state, } if (oldState == 0 || newState == 0) { - if (!nullState) { nullState = new QmlState(q); } + if (!nullState) { nullState = new QmlState; QFx_setParent_noEvent(nullState, q); } if (!oldState) oldState = nullState; if (!newState) newState = nullState; } diff --git a/src/declarative/util/qmltransitionmanager.cpp b/src/declarative/util/qmltransitionmanager.cpp index f04a821..3e2e05f 100644 --- a/src/declarative/util/qmltransitionmanager.cpp +++ b/src/declarative/util/qmltransitionmanager.cpp @@ -94,7 +94,6 @@ void QmlTransitionManagerPrivate::applyBindings() foreach(const Action &action, bindingsList) { if (action.toBinding) { action.property.setBinding(action.toBinding); - action.toBinding->forceUpdate(); } else if (action.event) { if (action.reverseEvent) action.event->reverse(); @@ -146,7 +145,6 @@ void QmlTransitionManager::transition(const QList<Action> &list, const Action &action = applyList.at(ii); if (action.toBinding) { action.property.setBinding(action.toBinding); - action.toBinding->forceUpdate(); } else if (!action.event) { action.property.write(action.toValue); } else if (action.event->isReversable()) { |