summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-04-30 03:01:04 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-04-30 03:01:04 (GMT)
commitd85c0c07b72476d801db3f1cb622cb32ab50dcc4 (patch)
tree1fa3a51cfd493fa7cde45f0b61f5f27891e51769
parent27cce9ae6c889c1803e46e45375ffb411490989d (diff)
downloadQt-d85c0c07b72476d801db3f1cb622cb32ab50dcc4.zip
Qt-d85c0c07b72476d801db3f1cb622cb32ab50dcc4.tar.gz
Qt-d85c0c07b72476d801db3f1cb622cb32ab50dcc4.tar.bz2
Prototype custom parsers for non-xml qml language
ListModel has been ported (under the name ListModel2) to demonstrate. ListModel2 behaves the same as ListModel, except that list "objects" must be called "ListElement" instead of a freeform name.
-rw-r--r--demos/declarative/mediabrowser/dummydata/PhonesModel.qml236
-rw-r--r--src/declarative/qml/qml.pri1
-rw-r--r--src/declarative/qml/qmlcompiler.cpp128
-rw-r--r--src/declarative/qml/qmlcompiler_p.h1
-rw-r--r--src/declarative/qml/qmlcustomparser.cpp129
-rw-r--r--src/declarative/qml/qmlcustomparser.h46
-rw-r--r--src/declarative/qml/qmlcustomparser_p.h79
-rw-r--r--src/declarative/qml/qmlinstruction_p.h1
-rw-r--r--src/declarative/qml/qmlmetatype.cpp17
-rw-r--r--src/declarative/qml/qmlmetatype.h32
-rw-r--r--src/declarative/qml/qmlvme.cpp5
-rw-r--r--src/declarative/util/qmllistmodel.cpp387
-rw-r--r--src/declarative/util/qmllistmodel.h34
13 files changed, 658 insertions, 438 deletions
diff --git a/demos/declarative/mediabrowser/dummydata/PhonesModel.qml b/demos/declarative/mediabrowser/dummydata/PhonesModel.qml
index d4f6269..eb68fdb 100644
--- a/demos/declarative/mediabrowser/dummydata/PhonesModel.qml
+++ b/demos/declarative/mediabrowser/dummydata/PhonesModel.qml
@@ -1,137 +1,99 @@
-<ListModel id="PhonesModel">
- <Phone>
- <title>Nokia N97</title>
- <thumb>http://www.forum.nokia.com/devices/pics/N97_main.jpg</thumb>
- <description>
- The Nokia N97 is a S60 5th Edition mobile computer with a large 3,5?, bright nHD (640 x 360 pixels and 16:9 aspect ratio) TFT color display with resistive touch screen and tactile feedback. The device provides excellent user experience for internet and entertainment by combining qwerty keyboard with touch UI and Home screen functionality. Use the N97 to connect to mobile broadband using WLAN or HSDPA (3.5G). Find directions and locations with the integrated A-GPS and included maps. Additional features include game titles with N-Gage, a 5 mega pixel camera with dual LED flash and automatic geotagging of images and videos.
- </description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>360 x 640
- <tr><td>Color Depth <td>24 bit
- <tr><td>Device Size <td>117.2 x 55.3 x 15.9 mm
- <tr><td>Volume <td>88 cc
- <tr><td>Weight <td>150 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/N97</url>
- <rating>5</rating>
- </Phone>
- <Phone>
- <title>Nokia 5800 XpressMusic</title>
- <thumb>http://www.forum.nokia.com/devices/pics/5800_main.jpg</thumb>
- <description>
- The Nokia 5800 XpressMusic is a S60 5th Edition device with a resistive touch screen and tactile feedback. The device has a large 3,2?, bright nHD (640 x 360 pixels and 16:9 aspect ratio) color display. The device has variety of input methods: stylus, plectrum and finger touch support for text input and UI control (alphanumeric keypad, full and mini qwerty keyboard, handwriting recognition). Use the Nokia 5800 XpressMusic to connect to mobile broadband using WLAN or HSDPA (3.5G). Find directions and locations with the integrated A-GPS and included maps. Additional features include a 3.2 megapixel camera with dual LED flash, Bluetooth 2.0 +EDR, and USB 2.0 High-Speed. Supported WCDMA frequencies depend on the region where the device is available.
- </description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>360 x 640
- <tr><td>Color Depth <td>24 bit
- <tr><td>Device Size <td>111 x 51.7 x 15.5 mm
- <tr><td>Volume <td>83 cc
- <tr><td>Weight <td>109 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/5800_XpressMusic</url>
- <rating>5</rating>
- </Phone>
- <Phone>
- <title>E75</title>
- <thumb>http://www.forum.nokia.com/devices/pics/E75_main.jpg</thumb>
- <description>The Nokia E75 is a GSM/WCDMA dual-mode business smartphone supporting WCDMA/HSDPA, EGSM, and WLAN. The device features a side slider qwerty keyboard for optimal email experience. Enjoy videos, music, and graphics on the 2.4? QVGA display and orientation sensor. Find directions and locations with the integrated A-GPS and included maps. Take photos with a 3.2-megapixel autofocus camera. Additional features include USB charging with simultaneous data transfer, Bluetooth 2.0 +EDR, and USB 2.0 High-Speed. Supported WCDMA frequencies depend on the region where the device is available.</description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>240 x 320
- <tr><td>Color Depth <td>24 bit
- <tr><td>Device Size <td>111.8 x 501 x 14.4 mm
- <tr><td>Volume <td>69 cc
- <tr><td>Weight <td>139 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/E75</url>
- <rating>5</rating>
- </Phone>
- <Phone>
- <title>Nokia N810</title>
- <thumb>http://www.forum.nokia.com/devices/pics/n810_main.jpg</thumb>
- <description>
- The Nokia N810 features include Voice-over-IP (VoIP) Internet and video calling, Instant Messaging, an integrated slide-out QWERTY keyboard and touch screen. The N810 lets you stay connected on the go with WLAN or Bluetooth 2.0 +EDR and a Bluetooth enabled mobile phone. The hi-resolution 4.13", 800 x 480 screen and the integrated web cam add to the internet experience. Use the Nokia N810 to play music and videos with the built-in stereo speakers or use the 3.5mm stereo plug with headphones. The Nokia N810 also has an integrated GPS receiver which allows you to pinpoint your position and find points-of-interests using pre-loaded maps.
- </description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>800 x 480
- <tr><td>Color Depth <td>16 bit
- <tr><td>Device Size <td>128 x 72 x 14 mm
- <tr><td>Weight <td>225 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/N810</url>
- <rating>5</rating>
- </Phone>
- <Phone>
- <title>Nokia 6260 slide</title>
- <thumb>http://www.forum.nokia.com/devices/pics/6260slide_main.jpg</thumb>
- <description>
- The Nokia 6260 slide is a Series 40 6th Edition phone, supporting quad-band GSM 850/900/1800/1900, triple-band WCDMA 900/1900/2100 and WLAN. Other key features include integrated A-GPS with included maps, a 5.0 megapixel camera with LED flash and Carl Zeiss optics, WebKit Open Source Browser, Flash Lite 3.0, Bluetooth 2.1 + EDR and MIDP Java 2.1 with additional Java APIs. Supported WCDMA frequencies depend on the region where the device is available.
- </description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>320 x 480
- <tr><td>Color Depth <td>24 bit
- <tr><td>Device Size <td>99.4 x 46.5 x 15.4 mm
- <tr><td>Volume <td>64.5 cc
- <tr><td>Weight <td>114 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/6260_slide</url>
- <rating>5</rating>
- </Phone>
- <Phone>
- <title>Nokia 2330 classic</title>
- <thumb>http://www.forum.nokia.com/devices/pics/2330_main.jpg</thumb>
- <description>
- The Nokia 2330 classic is a Dual-band GPRS phone for EGSM 900/1800 or GSM 850/1900 (for some markets) that includes a VGA camera, Stereo FM radio with recording feature, Bluetooth 2.0, Mail on Ovi and MIDP 2.1 APIs for application creation.
- </description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>128 x 160
- <tr><td>Color Depth <td>16 bit
- <tr><td>Device Size <td>107 x 46 x 13.8 mm
- <tr><td>Weight <td>80 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/2330_classic</url>
- <rating>5</rating>
- </Phone>
- <Phone>
- <title>Nokia 2355</title>
- <thumb>http://www.forum.nokia.com/devices/pics/2355_main.jpg</thumb>
- <description>
- The Nokia 2355 CDMA phone features a 64K color display, FM radio, integrated flashlight, WAP 2.0 browsing, MMS, Java(tm) and Brew. It's stylishly polished fold design will keep you in the spotlight.
- </description>
- <specifications>
- <![CDATA[
- <table width=300>
- <tr><td width=50%>Resolution <td width=50%>128 x 128
- <tr><td>Color Depth <td>16 bit
- <tr><td>Device Size <td>81 x 43 x 22 mm
- <tr><td>Weight <td>78 g
- </table>
- ]]>
- </specifications>
- <url>http://www.forum.nokia.com/devices/2355</url>
- <rating>5</rating>
- </Phone>
-</ListModel>
+ListModel2 {
+ id: "PhonesModel"
+
+ ListElement {
+ title: "Nokia N97"
+ thumb: "http://www.forum.nokia.com/devices/pics/N97_main.jpg"
+ description: "The Nokia N97 is a S60 5th Edition mobile computer with a large 3,5?, bright nHD (640 x 360 pixels and 16:9 aspect ratio) TFT color display with resistive touch screen and tactile feedback. The device provides excellent user experience for internet and entertainment by combining qwerty keyboard with touch UI and Home screen functionality. Use the N97 to connect to mobile broadband using WLAN or HSDPA (3.5G). Find directions and locations with the integrated A-GPS and included maps. Additional features include game titles with N-Gage, a 5 mega pixel camera with dual LED flash and automatic geotagging of images and videos."
+ specifications: "<table width=300>\
+ <tr><td width=50%>Resolution <td width=50%>360 x 640 \
+ <tr><td>Color Depth <td>24 bit \
+ <tr><td>Device Size <td>117.2 x 55.3 x 15.9 mm \
+ <tr><td>Volume <td>88 cc \
+ <tr><td>Weight <td>150 g \
+ </table>"
+ url: "http://www.forum.nokia.com/devices/N97"
+ rating: 5
+ }
+ ListElement {
+ title: "Nokia 5800 XpressMusic"
+ thumb: "http://www.forum.nokia.com/devices/pics/5800_main.jpg"
+ description: "The Nokia 5800 XpressMusic is a S60 5th Edition device with a resistive touch screen and tactile feedback. The device has a large 3,2?, bright nHD (640 x 360 pixels and 16:9 aspect ratio) color display. The device has variety of input methods: stylus, plectrum and finger touch support for text input and UI control (alphanumeric keypad, full and mini qwerty keyboard, handwriting recognition). Use the Nokia 5800 XpressMusic to connect to mobile broadband using WLAN or HSDPA (3.5G). Find directions and locations with the integrated A-GPS and included maps. Additional features include a 3.2 megapixel camera with dual LED flash, Bluetooth 2.0 +EDR, and USB 2.0 High-Speed. Supported WCDMA frequencies depend on the region where the device is available."
+ specifications: " <table width=300> \
+ <tr><td width=50%>Resolution <td width=50%>360 x 640 \
+ <tr><td>Color Depth <td>24 bit \
+ <tr><td>Device Size <td>111 x 51.7 x 15.5 mm \
+ <tr><td>Volume <td>83 cc \
+ <tr><td>Weight <td>109 g \
+ </table>"
+ url: "http://www.forum.nokia.com/devices/5800_XpressMusic"
+ rating: 5
+ }
+ ListElement {
+ title: "E75"
+ thumb: "http://www.forum.nokia.com/devices/pics/E75_main.jpg"
+ description: "The Nokia E75 is a GSM/WCDMA dual-mode business smartphone supporting WCDMA/HSDPA, EGSM, and WLAN. The device features a side slider qwerty keyboard for optimal email experience. Enjoy videos, music, and graphics on the 2.4? QVGA display and orientation sensor. Find directions and locations with the integrated A-GPS and included maps. Take photos with a 3.2-megapixel autofocus camera. Additional features include USB charging with simultaneous data transfer, Bluetooth 2.0 +EDR, and USB 2.0 High-Speed. Supported WCDMA frequencies depend on the region where the device is available."
+ specifications: "<table width=300> \
+ <tr><td width=50%>Resolution <td width=50%>240 x 320 \
+ <tr><td>Color Depth <td>24 bit \
+ <tr><td>Device Size <td>111.8 x 501 x 14.4 mm \
+ <tr><td>Volume <td>69 cc \
+ <tr><td>Weight <td>139 g \
+ </table>"
+ url: "http://www.forum.nokia.com/devices/E75"
+ rating: 5
+ }
+ ListElement {
+ title: "Nokia N810"
+ thumb: "http://www.forum.nokia.com/devices/pics/n810_main.jpg"
+ description: "The Nokia N810 features include Voice-over-IP (VoIP) Internet and video calling, Instant Messaging, an integrated slide-out QWERTY keyboard and touch screen. The N810 lets you stay connected on the go with WLAN or Bluetooth 2.0 +EDR and a Bluetooth enabled mobile phone. The hi-resolution 4.13\", 800 x 480 screen and the integrated web cam add to the internet experience. Use the Nokia N810 to play music and videos with the built-in stereo speakers or use the 3.5mm stereo plug with headphones. The Nokia N810 also has an integrated GPS receiver which allows you to pinpoint your position and find points-of-interests using pre-loaded maps."
+ specifications: "<table width=300> \
+ <tr><td width=50%>Resolution <td width=50%>800 x 480 \
+ <tr><td>Color Depth <td>16 bit \
+ <tr><td>Device Size <td>128 x 72 x 14 mm \
+ <tr><td>Weight <td>225 g \
+ </table>"
+ url: "http://www.forum.nokia.com/devices/N810"
+ rating: 5
+ }
+ ListElement {
+ title: "Nokia 6260 slide"
+ thumb: "http://www.forum.nokia.com/devices/pics/6260slide_main.jpg"
+ description: "The Nokia 6260 slide is a Series 40 6th Edition phone, supporting quad-band GSM 850/900/1800/1900, triple-band WCDMA 900/1900/2100 and WLAN. Other key features include integrated A-GPS with included maps, a 5.0 megapixel camera with LED flash and Carl Zeiss optics, WebKit Open Source Browser, Flash Lite 3.0, Bluetooth 2.1 + EDR and MIDP Java 2.1 with additional Java APIs. Supported WCDMA frequencies depend on the region where the device is available."
+ specifications: "<table width=300>\
+ <tr><td width=50%>Resolution <td width=50%>320 x 480 \
+ <tr><td>Color Depth <td>24 bit \
+ <tr><td>Device Size <td>99.4 x 46.5 x 15.4 mm \
+ <tr><td>Volume <td>64.5 cc \
+ <tr><td>Weight <td>114 g \
+ </table>"
+ url: "http://www.forum.nokia.com/devices/6260_slide"
+ rating: 5
+ }
+ ListElement {
+ title: "Nokia 2330 classic"
+ thumb: "http://www.forum.nokia.com/devices/pics/2330_main.jpg"
+ description: "The Nokia 2330 classic is a Dual-band GPRS phone for EGSM 900/1800 or GSM 850/1900 (for some markets) that includes a VGA camera, Stereo FM radio with recording feature, Bluetooth 2.0, Mail on Ovi and MIDP 2.1 APIs for application creation."
+ specifications: "<table width=300>\
+ <tr><td width=50%>Resolution <td width=50%>128 x 160 \
+ <tr><td>Color Depth <td>16 bit \
+ <tr><td>Device Size <td>107 x 46 x 13.8 mm\
+ <tr><td>Weight <td>80 g\
+ </table>"
+ url: "http://www.forum.nokia.com/devices/2330_classic"
+ rating: 5
+ }
+ ListElement {
+ title: "Nokia 2355"
+ thumb: "http://www.forum.nokia.com/devices/pics/2355_main.jpg"
+ description: "The Nokia 2355 CDMA phone features a 64K color display, FM radio, integrated flashlight, WAP 2.0 browsing, MMS, Java(tm) and Brew. It's stylishly polished fold design will keep you in the spotlight."
+ specifications: "<table width=300> \
+ <tr><td width=50%>Resolution <td width=50%>128 x 128 \
+ <tr><td>Color Depth <td>16 bit \
+ <tr><td>Device Size <td>81 x 43 x 22 mm \
+ <tr><td>Weight <td>78 g \
+ </table>"
+ url: "http://www.forum.nokia.com/devices/2355"
+ rating: 5
+ }
+}
diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri
index 00e3ccb..40b854f 100644
--- a/src/declarative/qml/qml.pri
+++ b/src/declarative/qml/qml.pri
@@ -33,6 +33,7 @@ HEADERS += qml/qmlparser_p.h \
qml/qmlcomponent.h \
qml/qmlcomponent_p.h \
qml/qmlcustomparser.h \
+ qml/qmlcustomparser_p.h \
qml/qmlpropertyvaluesource.h \
qml/qmlboundsignal_p.h \
qml/qmlxmlparser_p.h \
diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp
index 4cfe1e8..4433286 100644
--- a/src/declarative/qml/qmlcompiler.cpp
+++ b/src/declarative/qml/qmlcompiler.cpp
@@ -59,6 +59,7 @@
#include <qmlcontext.h>
#include <qmlmetatype.h>
#include <QtCore/qdebug.h>
+#include "private/qmlcustomparser_p.h"
#include "qmlscriptparser_p.h"
@@ -552,6 +553,7 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt)
obj->properties.remove(SIGNALS_NAME);
}
+ int createInstrIdx = output->bytecode.count();
if (obj->type != -1 && output->types.at(obj->type).parser) {
QByteArray data = obj->custom;
int ref = output->indexForByteArray(data);
@@ -567,6 +569,7 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt)
QmlInstruction create;
create.type = QmlInstruction::CreateObject;
create.line = obj->line;
+ create.create.data = -1;
create.create.type = obj->type;
output->bytecode << create;
}
@@ -591,19 +594,48 @@ bool QmlCompiler::compileObject(Object *obj, int ctxt)
}
}
+ bool isCustomParser = output->types.at(obj->type).type &&
+ output->types.at(obj->type).type->customParser() != 0;
+ QList<QmlCustomParserProperty> customProps;
+
foreach(Property *prop, obj->properties) {
if (!ignoreProperties && prop->name == PROPERTIES_NAME) {
} else if (!ignoreSignals && prop->name == SIGNALS_NAME) {
} else if (prop->name.length() >= 3 && prop->name.startsWith("on") &&
('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) {
- COMPILE_CHECK(compileSignal(prop, obj));
+ if (!isCustomParser) {
+ COMPILE_CHECK(compileSignal(prop, obj));
+ } else {
+ customProps << QmlCustomParserNodePrivate::fromProperty(prop);
+ }
} else {
- COMPILE_CHECK(compileProperty(prop, obj, ctxt));
+ if (!isCustomParser || (isCustomParser && testProperty(prop, obj))) {
+ COMPILE_CHECK(compileProperty(prop, obj, ctxt));
+ } else {
+ customProps << QmlCustomParserNodePrivate::fromProperty(prop);
+ }
}
}
- if (obj->defaultProperty)
- COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt));
+ if (obj->defaultProperty) {
+ if(!isCustomParser || (isCustomParser && testProperty(obj->defaultProperty, obj))) {
+ COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt));
+ } else {
+ customProps << QmlCustomParserNodePrivate::fromProperty(obj->defaultProperty);
+ }
+ }
+
+ if (isCustomParser && !customProps.isEmpty()) {
+ // ### Check for failure
+ bool ok = false;
+ QmlCustomParser *cp = output->types.at(obj->type).type->customParser();
+ QByteArray customData = cp->compile(customProps, &ok);
+ if(!ok)
+ COMPILE_EXCEPTION("Failure compiling custom type");
+ if(!customData.isEmpty())
+ output->bytecode[createInstrIdx].create.data =
+ output->indexForByteArray(customData);
+ }
if (obj->type != -1) {
if (output->types.at(obj->type).component) {
@@ -764,65 +796,61 @@ bool QmlCompiler::compileSignal(Property *prop, Object *obj)
return true;
}
+// Returns true if prop exists on obj, false otherwise
+bool QmlCompiler::testProperty(QmlParser::Property *prop,
+ QmlParser::Object *obj)
+{
+ if(isAttachedProperty(prop->name) || prop->name == "id")
+ return true;
+
+ const QMetaObject *mo = obj->metaObject();
+ if (mo) {
+ if (prop->isDefault) {
+ QMetaProperty p = QmlMetaType::defaultProperty(mo);
+ return p.name() != 0;
+ } else {
+ int idx = mo->indexOfProperty(prop->name.constData());
+ return idx != -1;
+ }
+ }
+
+ return false;
+}
+
bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt)
{
if (prop->values.isEmpty() && !prop->value)
return true;
// First we're going to need a reference to this property
- if (obj->type != -1) {
+ const QMetaObject *mo = obj->metaObject();
+ if (mo && !isAttachedProperty(prop->name)) {
+ if (prop->isDefault) {
+ QMetaProperty p = QmlMetaType::defaultProperty(mo);
+ // XXX
+ // Currently we don't handle enums in the static analysis
+ // so we let them drop through to generateStoreInstruction()
+ if (p.name() && !p.isEnumType()) {
+ prop->index = mo->indexOfProperty(p.name());
+ prop->name = p.name();
- const QMetaObject *mo = obj->metaObject();
- if (mo) {
- if (prop->isDefault) {
- QMetaProperty p = QmlMetaType::defaultProperty(mo);
- // XXX
- // Currently we don't handle enums in the static analysis
- // so we let them drop through to generateStoreInstruction()
- if (p.name() && !p.isEnumType()) {
- prop->index = mo->indexOfProperty(p.name());
- prop->name = p.name();
-
- int t = p.type();
- if (t == QVariant::UserType)
- t = p.userType();
-
- prop->type = t;
- }
- } else {
- prop->index = mo->indexOfProperty(prop->name.constData());
- QMetaProperty p = mo->property(prop->index);
- // XXX
- // Currently we don't handle enums in the static analysis
- // so we let them drop through to generateStoreInstruction()
- if (p.name() && !p.isEnumType()) {
- int t = p.type();
- if (t == QVariant::UserType)
- t = p.userType();
-
- prop->type = t;
- }
- }
- }
- } else {
- const QMetaObject *mo = obj->metaObject();
- if (mo) {
- if (prop->isDefault) {
- QMetaProperty p = QmlMetaType::defaultProperty(mo);
- if (p.name()) {
- prop->index = mo->indexOfProperty(p.name());
- prop->name = p.name();
- }
int t = p.type();
if (t == QVariant::UserType)
t = p.userType();
+
prop->type = t;
- } else {
- prop->index = mo->indexOfProperty(prop->name.constData());
- QMetaProperty p = mo->property(prop->index);
+ }
+ } else {
+ prop->index = mo->indexOfProperty(prop->name.constData());
+ QMetaProperty p = mo->property(prop->index);
+ // XXX
+ // Currently we don't handle enums in the static analysis
+ // so we let them drop through to generateStoreInstruction()
+ if (p.name() && !p.isEnumType()) {
int t = p.type();
if (t == QVariant::UserType)
t = p.userType();
+
prop->type = t;
}
}
@@ -841,7 +869,7 @@ bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt)
COMPILE_CHECK(compileNestedProperty(prop, ctxt));
} else if (QmlMetaType::isQmlList(prop->type) ||
- QmlMetaType::isList(prop->type)) {
+ QmlMetaType::isList(prop->type)) {
COMPILE_CHECK(compileListProperty(prop, obj, ctxt));
diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h
index 2a06f73..9a0ce1c 100644
--- a/src/declarative/qml/qmlcompiler_p.h
+++ b/src/declarative/qml/qmlcompiler_p.h
@@ -139,6 +139,7 @@ private:
bool compileComponentFromRoot(QmlParser::Object *obj, int);
bool compileFetchedObject(QmlParser::Object *obj, int);
bool compileSignal(QmlParser::Property *prop, QmlParser::Object *obj);
+ bool testProperty(QmlParser::Property *prop, QmlParser::Object *obj);
bool compileProperty(QmlParser::Property *prop, QmlParser::Object *obj, int);
bool compileIdProperty(QmlParser::Property *prop,
QmlParser::Object *obj);
diff --git a/src/declarative/qml/qmlcustomparser.cpp b/src/declarative/qml/qmlcustomparser.cpp
index a342ca8..fe0c3a8 100644
--- a/src/declarative/qml/qmlcustomparser.cpp
+++ b/src/declarative/qml/qmlcustomparser.cpp
@@ -40,10 +40,13 @@
****************************************************************************/
#include "qmlcustomparser.h"
-
+#include "qmlcustomparser_p.h"
+#include "qmlparser_p.h"
QT_BEGIN_NAMESPACE
+using namespace QmlParser;
+
/*!
\class QmlCustomParser
\brief The QmlCustomParser class allows you to add new arbitrary types to QML.
@@ -92,5 +95,129 @@ QT_BEGIN_NAMESPACE
the same-named type as this custom parser is defined for).
*/
+QmlCustomParserNode
+QmlCustomParserNodePrivate::fromObject(QmlParser::Object *root)
+{
+ QmlCustomParserNode rootNode;
+ rootNode.d->name = root->typeName;
+
+ for(QHash<QByteArray, Property *>::Iterator iter = root->properties.begin();
+ iter != root->properties.end();
+ ++iter) {
+
+ Property *p = *iter;
+
+ rootNode.d->properties << fromProperty(p);
+ }
+
+ return rootNode;
+}
+
+QmlCustomParserProperty
+QmlCustomParserNodePrivate::fromProperty(QmlParser::Property *p)
+{
+ QmlCustomParserProperty prop;
+ prop.d->name = p->name;
+ prop.d->isList = (p->values.count() > 1);
+
+ for(int ii = 0; ii < p->values.count(); ++ii) {
+ Value *v = p->values.at(ii);
+
+ // We skip fetched properties for now
+ if(v->object && v->object->type == -1)
+ continue;
+
+ if(v->object) {
+ QmlCustomParserNode node = fromObject(v->object);
+ prop.d->values << QVariant::fromValue(node);
+ } else {
+ prop.d->values << QVariant::fromValue(v->primitive);
+ }
+
+ }
+
+ return prop;
+}
+
+QmlCustomParserNode::QmlCustomParserNode()
+: d(new QmlCustomParserNodePrivate)
+{
+}
+
+QmlCustomParserNode::QmlCustomParserNode(const QmlCustomParserNode &other)
+: d(new QmlCustomParserNodePrivate)
+{
+ *this = other;
+}
+
+QmlCustomParserNode &QmlCustomParserNode::operator=(const QmlCustomParserNode &other)
+{
+ d->name = other.d->name;
+ d->properties = other.d->properties;
+ return *this;
+}
+
+QmlCustomParserNode::~QmlCustomParserNode()
+{
+ delete d; d = 0;
+}
+
+QByteArray QmlCustomParserNode::name() const
+{
+ return d->name;
+}
+
+QList<QmlCustomParserProperty> QmlCustomParserNode::properties() const
+{
+ return d->properties;
+}
+
+QmlCustomParserProperty::QmlCustomParserProperty()
+: d(new QmlCustomParserPropertyPrivate)
+{
+}
+
+QmlCustomParserProperty::QmlCustomParserProperty(const QmlCustomParserProperty &other)
+: d(new QmlCustomParserPropertyPrivate)
+{
+ *this = other;
+}
+
+QmlCustomParserProperty &QmlCustomParserProperty::operator=(const QmlCustomParserProperty &other)
+{
+ d->name = other.d->name;
+ d->isList = other.d->isList;
+ d->values = other.d->values;
+ return *this;
+}
+
+QmlCustomParserProperty::~QmlCustomParserProperty()
+{
+ delete d; d = 0;
+}
+
+QByteArray QmlCustomParserProperty::name() const
+{
+ return d->name;
+}
+
+bool QmlCustomParserProperty::isList() const
+{
+ return d->isList;
+}
+
+QList<QVariant> QmlCustomParserProperty::assignedValues() const
+{
+ return d->values;
+}
+
+QByteArray QmlCustomParser::compile(const QList<QmlCustomParserProperty> &, bool *ok)
+{
+ return QByteArray();
+}
+
+void QmlCustomParser::setCustomData(QObject *, const QByteArray &)
+{
+}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlcustomparser.h b/src/declarative/qml/qmlcustomparser.h
index 9de1be4..0e6a619 100644
--- a/src/declarative/qml/qmlcustomparser.h
+++ b/src/declarative/qml/qmlcustomparser.h
@@ -53,13 +53,55 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
+class QmlCustomParserPropertyPrivate;
+class Q_DECLARATIVE_EXPORT QmlCustomParserProperty
+{
+public:
+ QmlCustomParserProperty();
+ QmlCustomParserProperty(const QmlCustomParserProperty &);
+ QmlCustomParserProperty &operator=(const QmlCustomParserProperty &);
+ ~QmlCustomParserProperty();
+
+ QByteArray name() const;
+
+ bool isList() const;
+ QList<QVariant> assignedValues() const;
+
+private:
+ friend class QmlCustomParserNodePrivate;
+ friend class QmlCustomParserPropertyPrivate;
+ QmlCustomParserPropertyPrivate *d;
+};
+Q_DECLARE_METATYPE(QmlCustomParserProperty);
+
+class QmlCustomParserNodePrivate;
+class Q_DECLARATIVE_EXPORT QmlCustomParserNode
+{
+public:
+ QmlCustomParserNode();
+ QmlCustomParserNode(const QmlCustomParserNode &);
+ QmlCustomParserNode &operator=(const QmlCustomParserNode &);
+ ~QmlCustomParserNode();
+
+ QByteArray name() const;
+
+ QList<QmlCustomParserProperty> properties() const;
+
+private:
+ friend class QmlCustomParserNodePrivate;
+ QmlCustomParserNodePrivate *d;
+};
+Q_DECLARE_METATYPE(QmlCustomParserNode);
+
class Q_DECLARATIVE_EXPORT QmlCustomParser
{
public:
virtual ~QmlCustomParser() {}
virtual QByteArray compile(QXmlStreamReader&, bool *ok)=0;
+ virtual QByteArray compile(const QList<QmlCustomParserProperty> &, bool *ok);
virtual QVariant create(const QByteArray &)=0;
+ virtual void setCustomData(QObject *, const QByteArray &);
struct Register {
Register(const char *name, QmlCustomParser *parser) {
@@ -76,7 +118,11 @@ public:
#define QML_DEFINE_CUSTOM_PARSER_NS(namespacestring, name, parserClass) \
template<> QmlCustomParser::Register QmlCustomParser::Define<parserClass>::instance(namespacestring "/" # name, new parserClass);
+#define QML_DEFINE_CUSTOM_TYPE(TYPE, NAME, CUSTOMTYPE) \
+ template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *>::instance(qmlRegisterCustomType<TYPE>(#NAME, #TYPE, new CUSTOMTYPE));
+
QT_END_NAMESPACE
QT_END_HEADER
+
#endif
diff --git a/src/declarative/qml/qmlcustomparser_p.h b/src/declarative/qml/qmlcustomparser_p.h
new file mode 100644
index 0000000..63d148c
--- /dev/null
+++ b/src/declarative/qml/qmlcustomparser_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** 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 QMLCUSTOMPARSER_P_H
+#define QMLCUSTOMPARSER_P_H
+
+#include <QtCore/qglobal.h>
+#include "qmlcustomparser.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QmlParser
+{
+ class Object;
+ class Property;
+};
+
+class QmlCustomParserNodePrivate
+{
+public:
+ QByteArray name;
+ QList<QmlCustomParserProperty> properties;
+
+ static QmlCustomParserNode fromObject(QmlParser::Object *);
+ static QmlCustomParserProperty fromProperty(QmlParser::Property *);
+};
+
+class QmlCustomParserPropertyPrivate
+{
+public:
+ QmlCustomParserPropertyPrivate()
+ : isList(false) {}
+
+ QByteArray name;
+ bool isList;
+ QList<QVariant> values;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLCUSTOMPARSER_P_H
diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h
index 440b54a..922fc61 100644
--- a/src/declarative/qml/qmlinstruction_p.h
+++ b/src/declarative/qml/qmlinstruction_p.h
@@ -174,6 +174,7 @@ public:
} init;
struct {
int type;
+ int data;
} create;
struct {
int data;
diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp
index 9b99917..fbfeca0 100644
--- a/src/declarative/qml/qmlmetatype.cpp
+++ b/src/declarative/qml/qmlmetatype.cpp
@@ -118,6 +118,7 @@ public:
QmlPrivate::CreateFunc m_extFunc;
const QMetaObject *m_extMetaObject;
int m_index;
+ QmlCustomParser *m_customParser;
mutable volatile bool m_isSetup:1;
mutable QList<QmlProxyMetaObject::ProxyData> m_metaObjects;
mutable QByteArray m_hash;
@@ -126,7 +127,8 @@ public:
QmlTypePrivate::QmlTypePrivate()
: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_qmlListId(0),
m_opFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0),
- m_parserStatusCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_isSetup(false)
+ m_parserStatusCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1),
+ m_customParser(0), m_isSetup(false)
{
}
@@ -150,7 +152,8 @@ QmlType::QmlType(int type, int listType, int qmlListType,
const QMetaObject *metaObject,
QmlAttachedPropertiesFunc attachedPropertiesFunc,
int parserStatusCast, QmlPrivate::CreateFunc extFunc,
- const QMetaObject *extMetaObject, int index)
+ const QMetaObject *extMetaObject, int index,
+ QmlCustomParser *customParser)
: d(new QmlTypePrivate)
{
d->m_name = qmlName;
@@ -163,6 +166,7 @@ QmlType::QmlType(int type, int listType, int qmlListType,
d->m_parserStatusCast = parserStatusCast;
d->m_extFunc = extFunc;
d->m_index = index;
+ d->m_customParser = customParser;
if (extMetaObject)
d->m_extMetaObject = extMetaObject;
@@ -272,6 +276,11 @@ QObject *QmlType::create() const
return rv;
}
+QmlCustomParser *QmlType::customParser() const
+{
+ return d->m_customParser;
+}
+
bool QmlType::isInterface() const
{
return d->m_isInterface;
@@ -396,7 +405,7 @@ int QmlMetaType::registerInterface(const QmlPrivate::MetaTypeIds &id,
return index;
}
-int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Func func, const char *cname, const QMetaObject *mo, QmlAttachedPropertiesFunc attach, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo)
+int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Func func, const char *cname, const QMetaObject *mo, QmlAttachedPropertiesFunc attach, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *parser)
{
Q_UNUSED(object);
QWriteLocker lock(metaTypeDataLock());
@@ -414,7 +423,7 @@ int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Fun
QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId,
func, cname, mo, attach, pStatus, extFunc,
- extmo, index);
+ extmo, index, parser);
data->types.append(type);
data->idToType.insert(type->typeId(), type);
diff --git a/src/declarative/qml/qmlmetatype.h b/src/declarative/qml/qmlmetatype.h
index 83fb60b..99f8e93 100644
--- a/src/declarative/qml/qmlmetatype.h
+++ b/src/declarative/qml/qmlmetatype.h
@@ -59,7 +59,7 @@ class QmlCustomParser;
class Q_DECLARATIVE_EXPORT QmlMetaType
{
public:
- static int registerType(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *, const QMetaObject *, QmlAttachedPropertiesFunc, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo);
+ static int registerType(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *, const QMetaObject *, QmlAttachedPropertiesFunc, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo, QmlCustomParser *);
static int registerInterface(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *);
static void registerCustomParser(const char *, QmlCustomParser *);
@@ -121,6 +121,8 @@ public:
QObject *create() const;
+ QmlCustomParser *customParser() const;
+
bool isInterface() const;
int typeId() const;
int qListTypeId() const;
@@ -145,7 +147,7 @@ private:
friend class QmlMetaType;
friend class QmlTypePrivate;
QmlType(int, int, int, QmlPrivate::Func, const char *, int);
- QmlType(int, int, int, QmlPrivate::Func, const char *, const QMetaObject *, QmlAttachedPropertiesFunc, int, QmlPrivate::CreateFunc, const QMetaObject *, int);
+ QmlType(int, int, int, QmlPrivate::Func, const char *, const QMetaObject *, QmlAttachedPropertiesFunc, int, QmlPrivate::CreateFunc, const QMetaObject *, int, QmlCustomParser *);
~QmlType();
QmlTypePrivate *d;
@@ -166,7 +168,7 @@ int qmlRegisterType(const char *typeName)
QmlPrivate::attachedPropertiesFunc<T>(),
QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(),
QmlPrivate::StaticCastSelector<T,QObject>::cast(),
- 0, 0);
+ 0, 0, 0);
}
template<typename T>
@@ -184,7 +186,7 @@ int qmlRegisterType(const char *qmlName, const char *typeName)
QmlPrivate::attachedPropertiesFunc<T>(),
QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(),
QmlPrivate::StaticCastSelector<T,QObject>::cast(),
- 0, 0);
+ 0, 0, 0);
}
template<typename T, typename E>
@@ -206,7 +208,7 @@ int qmlRegisterExtendedType(const char *typeName)
&T::staticMetaObject, attached,
QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(),
QmlPrivate::StaticCastSelector<T,QObject>::cast(),
- &QmlPrivate::CreateParent<E>::create, &E::staticMetaObject);
+ &QmlPrivate::CreateParent<E>::create, &E::staticMetaObject, 0);
}
template<typename T, typename E>
@@ -231,7 +233,7 @@ int qmlRegisterExtendedType(const char *qmlName, const char *typeName)
QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(),
QmlPrivate::StaticCastSelector<T,QObject>::cast(),
&QmlPrivate::CreateParent<E>::create,
- &E::staticMetaObject);
+ &E::staticMetaObject, 0);
}
template<typename T>
@@ -249,6 +251,24 @@ int qmlRegisterInterface(const char *typeName)
qobject_interface_iid<T *>());
}
+template<typename T>
+int qmlRegisterCustomType(const char *qmlName, const char *typeName, QmlCustomParser *parser)
+{
+ QByteArray name(typeName);
+ QmlPrivate::MetaTypeIds ids = {
+ qRegisterMetaType<T *>(QByteArray(name + "*").constData()),
+ qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()),
+ qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData())
+ };
+
+ return QmlMetaType::registerType(ids, QmlPrivate::list_op<T>, qmlName,
+ &T::staticMetaObject,
+ QmlPrivate::attachedPropertiesFunc<T>(),
+ QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(),
+ QmlPrivate::StaticCastSelector<T,QObject>::cast(),
+ 0, 0, parser);
+}
+
void qmlRegisterCustomParser(const char *qmlName, QmlCustomParser *);
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp
index 253e9a7..7b3291e 100644
--- a/src/declarative/qml/qmlvme.cpp
+++ b/src/declarative/qml/qmlvme.cpp
@@ -257,6 +257,11 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in
if (!o)
VME_EXCEPTION("Unable to create object of type" << types.at(instr.create.type).className);
+ if (instr.create.data != -1) {
+ QmlCustomParser *customParser =
+ types.at(instr.create.type).type->customParser();
+ customParser->setCustomData(o, datas.at(instr.create.data));
+ }
if (!stack.isEmpty()) {
QObject *parent = stack.top();
o->setParent(parent);
diff --git a/src/declarative/util/qmllistmodel.cpp b/src/declarative/util/qmllistmodel.cpp
index 54aea2c..968e17b 100644
--- a/src/declarative/util/qmllistmodel.cpp
+++ b/src/declarative/util/qmllistmodel.cpp
@@ -53,55 +53,23 @@ QT_BEGIN_NAMESPACE
#define DATA_ROLE_ID 1
#define DATA_ROLE_NAME "data"
-Q_DECLARE_METATYPE(QListModelInterface *);
-class QmlListModelPrivate
+struct ListInstruction
{
-public:
- QmlListModelPrivate(QmlListModel *m)
- : q(m),
- type(QmlListModel::Invalid),
- listModelInterface(0),
- singleObject(0),
- roleCacheValid(false)
- {
- }
-
- void clear()
- {
- type = QmlListModel::Invalid;
- model = QVariant();
- if (listModelInterface)
- listModelInterface->disconnect(q);
- listModelInterface = 0;
- singleObject = 0;
- roleCacheValid = false;
- roleCache.clear();
- }
-
- void updateRoleCache()
- {
- if (roleCacheValid)
- return;
-
- roleCacheValid = true;
- if (type == QmlListModel::SingleObject)
- roleCache = QmlMetaProperty::properties(singleObject);
- }
-
- QmlListModel *q;
-
- QmlListModel::ModelType type;
-
- QVariant model;
- QListModelInterface *listModelInterface;
- QObject *singleObject;
+ enum { Push, Pop, Value, Set } type;
+ int dataIdx;
+};
- bool roleCacheValid;
- QStringList roleCache;
+struct ListModelData
+{
+ int dataOffset;
+ int instrCount;
+ ListInstruction *instructions() const { return (ListInstruction *)((char *)this + sizeof(ListModelData)); }
};
+Q_DECLARE_METATYPE(QListModelInterface *);
+
/*!
- \qmlclass ListModel QmlListModel
+ \qmlclass ListModel
\brief The ListModel element defines a free-form list data source.
The ListModel is a simple XML heirarchy of items containing data roles.
@@ -140,157 +108,6 @@ public:
<ListView model="{FruitModel}" delegate="{FruitDelegate}" anchors.fill="{parent}"/>
\endcode
*/
-/*!
- \internal
- \class QmlListModel
-*/
-QmlListModel::QmlListModel(QObject *parent)
-: QListModelInterface(parent), d(new QmlListModelPrivate(this))
-{
-}
-
-QmlListModel::~QmlListModel()
-{
- delete d; d = 0;
-}
-
-QmlListModel::ModelType QmlListModel::modelType() const
-{
- return d->type;
-}
-
-bool QmlListModel::setModel(const QVariant &model)
-{
- d->clear();
-
- QListModelInterface *iface = qvariant_cast<QListModelInterface *>(model);
- if (iface) {
- QObject::connect(iface, SIGNAL(itemsInserted(int,int)),
- this, SIGNAL(itemsInserted(int,int)));
- QObject::connect(iface, SIGNAL(itemsRemoved(int,int)),
- this, SIGNAL(itemsRemoved(int,int)));
- QObject::connect(iface, SIGNAL(itemsMoved(int,int,int)),
- this, SIGNAL(itemsMoved(int,int,int)));
- QObject::connect(iface, SIGNAL(itemsChanged(int,int,QList<int>)),
- this, SIGNAL(itemsChanged(int,int,QList<int>)));
- d->listModelInterface = iface;
- d->type = ListInterface;
- d->model = model;
- return true;
- }
-
- QObject *object = qvariant_cast<QObject *>(model);
- if (object) {
- d->singleObject = object;
- d->type = SingleObject;
- d->model = model;
- return true;
- }
-
- if (QmlMetaType::isList(model)) {
- d->type = SimpleList;
- d->model = model;
- return true;
- }
-
- return false;
-}
-
-QVariant QmlListModel::model() const
-{
- return d->model;
-}
-
-QList<int> QmlListModel::roles() const
-{
- d->updateRoleCache();
- switch(modelType()) {
- case Invalid:
- return QList<int>();
- case SimpleList:
- return QList<int>() << DATA_ROLE_ID;
- case ListInterface:
- return d->listModelInterface->roles();
- case SingleObject:
- {
- QList<int> rv;
- for (int ii = 0; ii < d->roleCache.count(); ++ii)
- rv << ii;
- return rv;
- }
- break;
- };
- return QList<int>();
-}
-
-QString QmlListModel::toString(int role) const
-{
- d->updateRoleCache();
- switch(modelType()) {
- case Invalid:
- return QString();
- case SimpleList:
- if (role == DATA_ROLE_ID)
- return QLatin1String(DATA_ROLE_NAME);
- else
- return QString();
- case ListInterface:
- return d->listModelInterface->toString(role);
- case SingleObject:
- if (role >= d->roleCache.count())
- return QString();
- else
- return d->roleCache.at(role);
- };
- return QString();
-}
-
-/*!
- \qmlproperty int ListModel::count
- This property holds the number of items in the list.
-*/
-int QmlListModel::count() const
-{
- switch(modelType()) {
- case Invalid:
- return 0;
- case SimpleList:
- return QmlMetaType::listCount(model());
- case ListInterface:
- return d->listModelInterface->count();
- case SingleObject:
- return 1;
- }
- return 0;
-}
-
-QHash<int,QVariant> QmlListModel::data(int index, const QList<int> &roles) const
-{
- d->updateRoleCache();
- QHash<int, QVariant> rv;
- switch(modelType()) {
- case Invalid:
- break;
- case SimpleList:
- if (roles.contains(DATA_ROLE_ID))
- rv.insert(DATA_ROLE_ID, QmlMetaType::listAt(d->model, index));
- break;
- case ListInterface:
- return d->listModelInterface->data(index, roles);
- case SingleObject:
- {
- for (int ii = 0; ii < roles.count(); ++ii) {
- QmlMetaProperty prop(d->singleObject, toString(roles.at(ii)));
- rv.insert(roles.at(ii), prop.read());
- }
- }
- break;
- };
-
- return rv;
-}
-
-
struct ModelNode;
class ListModel : public QListModelInterface
@@ -484,20 +301,181 @@ int ListModel::count() const
return _root->values.count();
}
-struct ListInstruction
-{
- enum { Push, Pop, Value, Set } type;
- int dataIdx;
-};
-
class ListModelParser : public QmlCustomParser
{
public:
virtual QByteArray compile(QXmlStreamReader& reader, bool *);
+ QByteArray compile(const QList<QmlCustomParserProperty> &, bool *ok);
virtual QVariant create(const QByteArray &);
+
+ bool compileProperty(const QmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data);
+ void setCustomData(QObject *, const QByteArray &);
};
QML_DEFINE_CUSTOM_PARSER(ListModel, ListModelParser);
+bool ListModelParser::compileProperty(const QmlCustomParserProperty &prop, QList<ListInstruction> &instr, QByteArray &data)
+{
+ QList<QVariant> values = prop.assignedValues();
+ for(int ii = 0; ii < values.count(); ++ii) {
+ const QVariant &value = values.at(ii);
+
+ if(value.userType() == qMetaTypeId<QmlCustomParserNode>()) {
+ QmlCustomParserNode node =
+ qvariant_cast<QmlCustomParserNode>(value);
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Push;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ QList<QmlCustomParserProperty> props = node.properties();
+ for(int jj = 0; jj < props.count(); ++jj) {
+ const QmlCustomParserProperty &nodeProp = props.at(jj);
+ if(nodeProp.name() == "")
+ return false;
+
+ ListInstruction li;
+ int ref = data.count();
+ data.append(nodeProp.name());
+ data.append('\0');
+ li.type = ListInstruction::Set;
+ li.dataIdx = ref;
+ instr << li;
+
+ if(!compileProperty(nodeProp, instr, data))
+ return false;
+
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ {
+ ListInstruction li;
+ li.type = ListInstruction::Pop;
+ li.dataIdx = -1;
+ instr << li;
+ }
+
+ } else {
+
+ int ref = data.count();
+ QByteArray d = value.toString().toLatin1();
+ d.append('\0');
+ data.append(d);
+
+ ListInstruction li;
+ li.type = ListInstruction::Value;
+ li.dataIdx = ref;
+ instr << li;
+
+ }
+ }
+
+ return true;
+}
+
+QByteArray ListModelParser::compile(const QList<QmlCustomParserProperty> &customProps, bool *ok)
+{
+ *ok = true;
+ QList<ListInstruction> instr;
+ QByteArray data;
+
+ for(int ii = 0; ii < customProps.count(); ++ii) {
+ const QmlCustomParserProperty &prop = customProps.at(ii);
+ if(prop.name() != "") { // isn't default property
+ *ok = false;
+ return QByteArray();
+ }
+
+ if(!compileProperty(prop, instr, data)) {
+ *ok = false;
+ return QByteArray();
+ }
+ }
+
+ int size = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction) +
+ data.count();
+
+ QByteArray rv;
+ rv.resize(size);
+
+ ListModelData *lmd = (ListModelData *)rv.data();
+ lmd->dataOffset = sizeof(ListModelData) +
+ instr.count() * sizeof(ListInstruction);
+ lmd->instrCount = instr.count();
+ for (int ii = 0; ii < instr.count(); ++ii)
+ lmd->instructions()[ii] = instr.at(ii);
+ ::memcpy(rv.data() + lmd->dataOffset, data.constData(), data.count());
+
+ return rv;
+}
+
+void ListModelParser::setCustomData(QObject *obj, const QByteArray &d)
+{
+ ListModel *rv = static_cast<ListModel *>(obj);
+
+ ModelNode *root = new ModelNode;
+ rv->_root = root;
+ QStack<ModelNode *> nodes;
+ nodes << root;
+
+ const ListModelData *lmd = (const ListModelData *)d.constData();
+ const char *data = ((const char *)lmd) + lmd->dataOffset;
+
+ for (int ii = 0; ii < lmd->instrCount; ++ii) {
+ const ListInstruction &instr = lmd->instructions()[ii];
+
+ switch(instr.type) {
+ case ListInstruction::Push:
+ {
+ ModelNode *n = nodes.top();
+ ModelNode *n2 = new ModelNode;
+ n->values << qVariantFromValue(n2);
+ nodes.push(n2);
+ }
+ break;
+
+ case ListInstruction::Pop:
+ nodes.pop();
+ break;
+
+ case ListInstruction::Value:
+ {
+ ModelNode *n = nodes.top();
+ n->values.append(QByteArray(data + instr.dataIdx));
+ }
+ break;
+
+ case ListInstruction::Set:
+ {
+ ModelNode *n = nodes.top();
+ ModelNode *n2 = new ModelNode;
+ n->properties.insert(QLatin1String(data + instr.dataIdx), n2);
+ nodes.push(n2);
+ }
+ break;
+ }
+ }
+}
+
+class ListModel2 : public ListModel
+{
+Q_OBJECT
+};
+QML_DECLARE_TYPE(ListModel2);
+QML_DEFINE_CUSTOM_TYPE(ListModel2, ListModel2, ListModelParser);
+
+class ListElement : public QObject
+{
+Q_OBJECT
+};
+QML_DECLARE_TYPE(ListElement);
+QML_DEFINE_TYPE(ListElement,ListElement);
+
static void dump(ModelNode *node, int ind)
{
QByteArray indentBa(ind * 4, ' ');
@@ -534,13 +512,6 @@ ModelNode::~ModelNode()
if (modelCache) { delete modelCache; modelCache = 0; }
}
-struct ListModelData
-{
- int dataOffset;
- int instrCount;
- ListInstruction *instructions() const { return (ListInstruction *)((char *)this + sizeof(ListModelData)); }
-};
-
QByteArray ListModelParser::compile(QXmlStreamReader& reader, bool *ok)
{
*ok = true;
diff --git a/src/declarative/util/qmllistmodel.h b/src/declarative/util/qmllistmodel.h
index 3dcac4f..36aa009 100644
--- a/src/declarative/util/qmllistmodel.h
+++ b/src/declarative/util/qmllistmodel.h
@@ -57,40 +57,10 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
-class QmlListModelPrivate;
-class Q_DECLARATIVE_EXPORT QmlListModel : public QListModelInterface
-{
-Q_OBJECT
-public:
- QmlListModel(QObject *parent = 0);
- virtual ~QmlListModel();
-
- enum ModelType {
- Invalid,
- SimpleList,
- ListInterface,
- SingleObject
- };
-
- ModelType modelType() const;
- bool setModel(const QVariant &);
- QVariant model() const;
-
- virtual QList<int> roles() const;
- virtual QString toString(int role) const;
-
- Q_PROPERTY(int count READ count);
- virtual int count() const;
- virtual QHash<int,QVariant>
- data(int index, const QList<int> &roles = (QList<int>())) const;
-private:
- QmlListModelPrivate *d;
-};
-QML_DECLARE_TYPE(QmlListModel);
-
-#endif // QMLLISTMODEL_H
QT_END_NAMESPACE
QT_END_HEADER
+
+#endif // QMLLISTMODEL_H