summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/declarative/flickr/flickr-mobile.qml18
-rw-r--r--demos/declarative/flickr/mobile/Button.qml4
-rw-r--r--demos/declarative/flickr/mobile/GridDelegate.qml9
-rw-r--r--demos/declarative/flickr/mobile/TitleBar.qml5
-rw-r--r--demos/declarative/flickr/mobile/ToolBar.qml12
-rw-r--r--demos/declarative/flickr/mobile/images/titlebar.png (renamed from demos/declarative/flickr/mobile/images/titlebar2.png)bin1436 -> 1436 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/titlebar.sci5
-rw-r--r--demos/declarative/flickr/mobile/images/titlebar2.sci5
-rw-r--r--demos/declarative/flickr/mobile/images/toolbutton.png (renamed from demos/declarative/flickr/mobile/images/toolbutton2.png)bin2619 -> 2619 bytes
-rw-r--r--demos/declarative/flickr/mobile/images/toolbutton.sci (renamed from demos/declarative/flickr/mobile/images/toolbutton2.sci)2
-rw-r--r--doc/src/declarative/extending.qdoc2
-rw-r--r--doc/src/declarative/modules.qdoc160
-rw-r--r--examples/declarative/xmlhttprequest/test.qml26
-rw-r--r--examples/declarative/xmlhttprequest/test.xml5
-rw-r--r--src/declarative/fx/qfxwebview.h1
-rw-r--r--src/declarative/qml/qmlcompositetypemanager.cpp19
-rw-r--r--src/declarative/qml/qmlengine.cpp228
-rw-r--r--src/declarative/qml/qmlengine_p.h7
-rw-r--r--src/declarative/qml/qmlxmlhttprequest.cpp883
-rw-r--r--tests/auto/declarative/qmlparser/failingComponent.errors.txt3
-rw-r--r--tests/auto/declarative/qmlparser/importNamespaceConflict.errors.txt1
-rw-r--r--tests/auto/declarative/qmlparser/importNamespaceConflict.qml4
-rw-r--r--tests/auto/declarative/qmlparser/lib/com/nokia/installedtest/qmldir1
-rw-r--r--tests/auto/declarative/qmlparser/testtypes.h5
-rw-r--r--tests/auto/declarative/qmlparser/tst_qmlparser.cpp130
25 files changed, 1254 insertions, 281 deletions
diff --git a/demos/declarative/flickr/flickr-mobile.qml b/demos/declarative/flickr/flickr-mobile.qml
index 643298d..c497e4e 100644
--- a/demos/declarative/flickr/flickr-mobile.qml
+++ b/demos/declarative/flickr/flickr-mobile.qml
@@ -31,9 +31,18 @@ Item {
id: PhotoListView; model: RssModel; delegate: ListDelegate
width: parent.width; height: parent.height; x: -(parent.width * 1.5); cacheBuffer: 100;
}
+ states: State {
+ name: "ListView"; when: Screen.inListView == true
+ PropertyChanges { target: PhotoListView; x: 0 }
+ PropertyChanges { target: PhotoGridView; x: -(parent.width * 1.5) }
+ }
+
+ transitions: Transition {
+ NumberAnimation { properties: "x"; duration: 500; easing: "easeInOutQuad" }
+ }
}
- Common.ImageDetails { id: ImageDetails; width: parent.width; x: parent.width; height: parent.height }
+ Common.ImageDetails { id: ImageDetails; width: parent.width; anchors.left: Views.right; height: parent.height }
Mobile.TitleBar { id: TitleBar; width: parent.width; height: 40; opacity: 0.9 }
Mobile.ToolBar {
@@ -45,9 +54,10 @@ Item {
}
states: State {
- name: "ListView"; when: Screen.inListView == true
- PropertyChanges { target: PhotoListView; x: 0 }
- PropertyChanges { target: PhotoGridView; x: -(parent.width * 1.5) }
+ name: "DetailedView"
+ PropertyChanges { target: Views; x: -parent.width }
+ PropertyChanges { target: ToolBar; button2Label: "Back" }
+ PropertyChanges { target: ToolBar; onButton2Clicked: { } }
}
transitions: Transition {
diff --git a/demos/declarative/flickr/mobile/Button.qml b/demos/declarative/flickr/mobile/Button.qml
index 275408c..3a0b42e 100644
--- a/demos/declarative/flickr/mobile/Button.qml
+++ b/demos/declarative/flickr/mobile/Button.qml
@@ -9,13 +9,13 @@ Item {
BorderImage {
id: Image
- source: "images/toolbutton2.sci"
+ source: "images/toolbutton.sci"
width: Container.width; height: Container.height
}
BorderImage {
id: Pressed
opacity: 0
- source: "images/toolbutton2.sci"
+ source: "images/toolbutton.sci"
width: Container.width; height: Container.height
}
MouseRegion {
diff --git a/demos/declarative/flickr/mobile/GridDelegate.qml b/demos/declarative/flickr/mobile/GridDelegate.qml
index 5ab4d3a..91e7c8d 100644
--- a/demos/declarative/flickr/mobile/GridDelegate.qml
+++ b/demos/declarative/flickr/mobile/GridDelegate.qml
@@ -48,23 +48,20 @@
name: "Details"; extend: "Show"
ParentChange { target: Wrapper; parent: ImageDetails.frontContainer }
PropertyChanges { target: Wrapper; x: 20; y: 60 }
- PropertyChanges { target: ImageDetails; x: 0 }
- PropertyChanges { target: Views; x: -parent.width }
- PropertyChanges { target: ToolBar.button2; text: "Back" }
- PropertyChanges { target: ToolBar; onButton2Clicked: { } }
+ PropertyChanges { target: Background; state: "DetailedView" }
}
]
transitions: [
Transition {
from: "Show"; to: "Details"
ParentAction { }
- NumberAnimation { properties: "x,y,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ NumberAnimation { properties: "x,y"; duration: 500; easing: "easeInOutQuad" }
},
Transition {
from: "Details"; to: "Show"
SequentialAnimation {
ParentAction { }
- NumberAnimation { properties: "x,y,opacity,angle"; duration: 500; easing: "easeInOutQuad" }
+ NumberAnimation { properties: "x,y"; duration: 500; easing: "easeInOutQuad" }
PropertyAction { target: Wrapper; properties: "z" }
}
}
diff --git a/demos/declarative/flickr/mobile/TitleBar.qml b/demos/declarative/flickr/mobile/TitleBar.qml
index b74e414..79c1326 100644
--- a/demos/declarative/flickr/mobile/TitleBar.qml
+++ b/demos/declarative/flickr/mobile/TitleBar.qml
@@ -5,7 +5,7 @@ Item {
property string untaggedString: "Uploads from everyone"
property string taggedString: "Recent uploads tagged "
- BorderImage { source: "images/titlebar2.sci"; width: parent.width; height: parent.height + 14; y: -7 }
+ BorderImage { source: "images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 }
Item {
id: Container
@@ -13,8 +13,9 @@ Item {
Script {
function accept() {
- RssModel.tags = Editor.text
TitleBar.state = ""
+ Background.state = ""
+ RssModel.tags = Editor.text
}
}
diff --git a/demos/declarative/flickr/mobile/ToolBar.qml b/demos/declarative/flickr/mobile/ToolBar.qml
index 80897cc..cfdc8fe 100644
--- a/demos/declarative/flickr/mobile/ToolBar.qml
+++ b/demos/declarative/flickr/mobile/ToolBar.qml
@@ -3,20 +3,22 @@ import Qt 4.6
Item {
id: Toolbar
- property var button1Label
- property var button2Label
+ property alias button1Label: Button1.text
+ property alias button2Label: Button2.text
signal button1Clicked
signal button2Clicked
- BorderImage { source: "images/titlebar2.sci"; width: parent.width; height: parent.height + 14; y: -7 }
+ BorderImage { source: "images/titlebar.sci"; width: parent.width; height: parent.height + 14; y: -7 }
Button {
- anchors.left: parent.left; anchors.leftMargin: 5; y: 3; width: 140; height: 32; text: button1Label
+ id: Button1
+ anchors.left: parent.left; anchors.leftMargin: 5; y: 3; width: 140; height: 32
onClicked: Toolbar.button1Clicked()
}
Button {
- anchors.right: parent.right; anchors.rightMargin: 5; y: 3; width: 140; height: 32; text: button2Label
+ id: Button2
+ anchors.right: parent.right; anchors.rightMargin: 5; y: 3; width: 140; height: 32
onClicked: Toolbar.button2Clicked()
}
}
diff --git a/demos/declarative/flickr/mobile/images/titlebar2.png b/demos/declarative/flickr/mobile/images/titlebar.png
index 51c9008..51c9008 100644
--- a/demos/declarative/flickr/mobile/images/titlebar2.png
+++ b/demos/declarative/flickr/mobile/images/titlebar.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/titlebar.sci b/demos/declarative/flickr/mobile/images/titlebar.sci
new file mode 100644
index 0000000..50444e1
--- /dev/null
+++ b/demos/declarative/flickr/mobile/images/titlebar.sci
@@ -0,0 +1,5 @@
+gridLeft: 10
+gridTop: 12
+gridBottom: 12
+gridRight: 10
+imageFile: titlebar.png
diff --git a/demos/declarative/flickr/mobile/images/titlebar2.sci b/demos/declarative/flickr/mobile/images/titlebar2.sci
deleted file mode 100644
index e8fc2d1..0000000
--- a/demos/declarative/flickr/mobile/images/titlebar2.sci
+++ /dev/null
@@ -1,5 +0,0 @@
-gridLeft: 22
-gridTop: 10
-gridBottom: 10
-gridRight: 22
-imageFile: titlebar2.png
diff --git a/demos/declarative/flickr/mobile/images/toolbutton2.png b/demos/declarative/flickr/mobile/images/toolbutton.png
index 8862898..8862898 100644
--- a/demos/declarative/flickr/mobile/images/toolbutton2.png
+++ b/demos/declarative/flickr/mobile/images/toolbutton.png
Binary files differ
diff --git a/demos/declarative/flickr/mobile/images/toolbutton2.sci b/demos/declarative/flickr/mobile/images/toolbutton.sci
index e3118b0..a0a885f 100644
--- a/demos/declarative/flickr/mobile/images/toolbutton2.sci
+++ b/demos/declarative/flickr/mobile/images/toolbutton.sci
@@ -2,4 +2,4 @@ gridLeft: 15
gridTop: 4
gridBottom: 4
gridRight: 15
-imageFile: toolbutton2.png
+imageFile: toolbutton.png
diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc
index 833a5db..3235435 100644
--- a/doc/src/declarative/extending.qdoc
+++ b/doc/src/declarative/extending.qdoc
@@ -818,7 +818,7 @@ Rectangle {
\endcode
\endtable
-Components may be collected into \l {Modules of Components} that gives the
+Components may be collected into \l {Modules} that gives the
developer more freedom than just putting files in the same directory.
\section2 Building reusable components
diff --git a/doc/src/declarative/modules.qdoc b/doc/src/declarative/modules.qdoc
index 60cf2a4..7c67f60 100644
--- a/doc/src/declarative/modules.qdoc
+++ b/doc/src/declarative/modules.qdoc
@@ -1,123 +1,105 @@
/*!
-\page qmlmodules.html
\target qmlmodules
-\title Modules of Components
-
-A \bold module is a collection of \l Components.
-
-To use a module, include the following statement at the begining
-of your QML:
-
-\code
-import "path"
-\endcode
-
-This allows all components defined in the directory \c path to be used in
-the component where this statement appears.
-
-Currently, \c path may only be a directory relative to the directory containing
-the component issuing the import.
-
-The import statement cannot be used by remote content.
-*/
-
-/*
-
-Ideas for full module support....
-
-See QT-558.
-
-* Modularity within applications
-
-This is the currently-supported mechanism.
+\page qmlmodules.html
+\title Modules
-By using the "import" statement, a subdirectory of types can be added to the
-empty namespace. Alternatively, a type in a subdirectory can be referenced
-explicitly.
+A \bold module is a collection of QML types.
-So, given these files:
+To use types from a module it must be imported using the \c import statement. Successive
+import statements override earlier import statements.
- ./SubModule1/Type1.qml
- ./SubModule2/Type1.qml
+\section1 Importing Built-in Types
-This is valid QML:
+To use built-in types, you must import the module defining them.
+For example, to use types from Qt, import it:
- import "SubModule1"
- Type1 { ... }
- SubModule2.Type1 { ... }
+\code
+import Qt 4.6
+\endcode
+This makes available all types in Qt that were available in Qt 4.6, regardless of the
+actual version of Qt executing the QML.
-* System-installed modules (dependencies)
+Modules can be compiled-in (such as the Qt module), or they can be
+defined in QML files.
-To use system-installed modules, the dependency must be explicitly stated
-using the "require" statement. Types in required modules must still be
-explicitly qualified. Dependencies cannot be added to the empty namespace.
+\section1 Importing QML Files
- QMLPATH=/opt/Nokia/qml:/usr/share/lib/qml
- /opt/Nokia/qml/Module1/Type1.qml
- /usr/share/lib/qml/Module1/Type1.qml
+To import types defined in QML files in directories relative to the file importing them,
+a quoted import directory is used:
- require "Module1"
- Module1.Type1 { ... }
+\code
+import "path"
+\endcode
+This allows all components defined in the directory \c path to be used in
+the component where this statement appears.
-* Grouping of components within application modules
+To import types defined in QML files that are installed somewhere on the system,
+an unquoted URI is used:
-Sub-sub directories allow further grouping of types.
+\code
+import com.nokia.CoolStuff 1.0
+\endcode
- ./SubModule1/Group1/*.qml
- ./SubModule1/Group2/*.qml
+This will access file in the directory \c com/nokia/CoolStuff/, found in some
+location determined outside QML. See QmlEngine::addImportPath() and the \c -L option
+to the \l {qmlviewer}{viewer} application.
- SubModule1.Group1.Type1 { ... }
- SubModule1.Group1.Type2 { ... }
- SubModule1.Group2.Type1 { ... }
- SubModule1.Group2.Type2 { ... }
+The directory of installed files must include a file \c qmldir which specifies the
+mapping from all type names to versioned QML files. It is a list of lines of the form:
- import "SubModule1/Group1"
- Type1 { ... }
+\code
+# <Comment>
+<TypeName> <VersionRange> <File>
+\endcode
- import "SubModule1"
- Group1.Type1 { ... }
+<TypeName> is the type being made available; <VersionRange> is either a single version
+number like \c 4.0 or a range of minor versions like \c 4.0-2; <File> is the (relative)
+file name of the QML file defining the type.
+The same type can be provided by different files in different versions.
+If a type is in multiple major versions, it should be listed on a separate line.
+Installed files do not need to import the module of which they are a part, as they can refer
+to the other QML files in the module as relative (local) files.
-* Grouping of components within system-installed modules
+Installed files \e must be referred to by version information described above,
+local files \e may have it.
-System-installed types may also be grouped into types. The hierarchy is a
-global namespace, so such grouping is recommended to reduce clashes.
+The versioning system ensures that a given QML file will work regardless of the version
+of installed software, since a versioned import \e only imports types for that version,
+leaving other identifiers available, even if the actual installed version might otherwise
+use those identifiers.
- /opt/Nokia/qml/Module1/Group1/*.qml
- /opt/Nokia/qml/Module1/Group2/*.qml
+\section1 Namespaces - Named Imports
- require "Module1"
- Module1.Group1.Type1 { ... }
- Module1.Group1.Type2 { ... }
- Module1.Group2.Type1 { ... }
- Module1.Group2.Type2 { ... }
+When importing content it by default imports types into the global namespace.
+You may choose to import the module into another namespace, either to allow identically-named
+types to be referenced, or purely for readability.
- require "Module1/Group1"
- Group1.Type1 { ... }
+To import a module into a namespace:
- // Alternative syntax
- /opt/qml/com/nokia/qml/Module1/Group1/*.qml
- require "com.nokia.qml.Module1.Group1"
- Group1.Type1 { ... }
+\code
+import Qt 4.6 as TheQtLibrary
+\endcode
+Types from Qt 4.6 may then be used, but only by qualifying them with the namespace:
-* Private sub-components
+\code
+TheQtLibrary.Rectangle { ... }
+\endcode
-Directories begining with _ cannot be referenced except by types in the
-directory immediately containing it.
+Multiple modules can be imported into the same namespace in the same way that multiple
+modules can be imported into the global namespace:
- /opt/Nokia/qml/Module1/_private/Type1.qml
- ./SubModule1/_private/Type1.qml
+\code
+import Qt 4.6 as Nokia
+import Ovi 1.0 as Nokia
+\endcode
+*/
- SubModule1._private.Type1 { ... } // Not allowed
- import "SubModule1._private" // Not allowed
- require "SubModule1._private" // Not allowed
- require "SubModule1"
- Module1._private.Type1 { ... } // Not allowed
+/*
- import "_private" // allowed
- Type1 { ... }
+See original requirement QT-558.
*/
diff --git a/examples/declarative/xmlhttprequest/test.qml b/examples/declarative/xmlhttprequest/test.qml
new file mode 100644
index 0000000..56366d6
--- /dev/null
+++ b/examples/declarative/xmlhttprequest/test.qml
@@ -0,0 +1,26 @@
+import Qt 4.6
+
+Rectangle {
+ width: 800; height: 600
+
+ MouseRegion {
+ anchors.fill: parent
+ onClicked: {
+
+ var doc = new XMLHttpRequest();
+ doc.onreadystatechange = function() {
+ if (doc.readyState == XMLHttpRequest.DONE) {
+
+ var a = doc.responseXML.documentElement;
+ for (var ii = 0; ii < a.childNodes.length; ++ii) {
+ print (a.childNodes[ii].nodeName);
+ }
+
+ }
+ }
+
+ doc.open("GET", "test.xml");
+ doc.send();
+ }
+ }
+}
diff --git a/examples/declarative/xmlhttprequest/test.xml b/examples/declarative/xmlhttprequest/test.xml
new file mode 100644
index 0000000..8b7f1e1
--- /dev/null
+++ b/examples/declarative/xmlhttprequest/test.xml
@@ -0,0 +1,5 @@
+<data>
+ <element1 />
+ <element2 />
+</data>
+
diff --git a/src/declarative/fx/qfxwebview.h b/src/declarative/fx/qfxwebview.h
index 3dd1b65..f136e2d 100644
--- a/src/declarative/fx/qfxwebview.h
+++ b/src/declarative/fx/qfxwebview.h
@@ -80,7 +80,6 @@ class QFxWebViewAttached;
class QFxWebSettings;
//### TODO: browser plugins
-//### TODO: smart zooming using e.g. DIV
class Q_DECLARATIVE_EXPORT QFxWebView : public QFxPaintedItem
{
diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp
index 1b1f67c..f64547c 100644
--- a/src/declarative/qml/qmlcompositetypemanager.cpp
+++ b/src/declarative/qml/qmlcompositetypemanager.cpp
@@ -329,10 +329,27 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit)
QUrl url;
int majorVersion;
int minorVersion;
- if (!QmlEnginePrivate::get(engine)->resolveType(unit->imports, typeName, &ref.type, &url, &majorVersion, &minorVersion, 0)) {
+ QmlEnginePrivate::ImportedNamespace *typeNamespace = 0;
+ if (!QmlEnginePrivate::get(engine)->resolveType(unit->imports, typeName, &ref.type, &url, &majorVersion, &minorVersion, &typeNamespace)) {
// XXX could produce error message here.
}
+ if (typeNamespace) {
+ QmlError error;
+ error.setUrl(unit->imports.baseUrl());
+ error.setDescription(tr("Namespace %1 cannot be used as a type").arg(QLatin1String(typeName)));
+ if (!parserRef->refObjects.isEmpty()) {
+ QmlParser::Object *obj = parserRef->refObjects.first();
+ error.setLine(obj->location.start.line);
+ error.setColumn(obj->location.start.column);
+ }
+ unit->status = QmlCompositeTypeData::Error;
+ unit->errorType = QmlCompositeTypeData::GeneralError;
+ unit->errors << error;
+ doComplete(unit);
+ return;
+ }
+
if (ref.type) {
foreach (QmlParser::Object *obj, parserRef->refObjects) {
// store namespace for DOM
diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp
index 4b98d1b..d2d0590 100644
--- a/src/declarative/qml/qmlengine.cpp
+++ b/src/declarative/qml/qmlengine.cpp
@@ -109,8 +109,8 @@ QScriptValue desktopOpenUrl(QScriptContext *ctxt, QScriptEngine *e)
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e)
: rootContext(0), currentBindContext(0), currentExpression(0),
isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0),
- scriptEngine(this), rootComponent(0), networkAccessManager(0), typeManager(e),
- uniqueId(1)
+ nodeListClass(0), namedNodeMapClass(0), scriptEngine(this), rootComponent(0),
+ networkAccessManager(0), typeManager(e), uniqueId(1)
{
QScriptValue qtObject =
scriptEngine.newQMetaObject(StaticQtMetaObject::get());
@@ -139,6 +139,10 @@ QmlEnginePrivate::~QmlEnginePrivate()
objectClass = 0;
delete networkAccessManager;
networkAccessManager = 0;
+ delete nodeListClass;
+ nodeListClass = 0;
+ delete namedNodeMapClass;
+ namedNodeMapClass = 0;
for(int ii = 0; ii < bindValues.count(); ++ii)
clear(bindValues[ii]);
@@ -1138,65 +1142,71 @@ struct QmlEnginePrivate::ImportedNamespace {
QList<int> majversions;
QList<int> minversions;
QList<bool> isLibrary;
+ QList<bool> isBuiltin;
- QUrl find(const QString& type) const
+ bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return) const
{
for (int i=0; i<urls.count(); ++i) {
- QUrl url = QUrl(urls.at(i) + QLatin1String("/") + type + QLatin1String(".qml"));
int vmaj = majversions.at(i);
int vmin = minversions.at(i);
- if (vmaj || vmin) {
- // Check version file - XXX cache these in QmlEngine!
- QFile qmldir(QUrl(urls.at(i)+QLatin1String("/qmldir")).toLocalFile());
- if (qmldir.open(QIODevice::ReadOnly)) {
- do {
- QString line = QString::fromUtf8(qmldir.readLine());
- if (line.at(0) == QLatin1Char('#'))
- continue;
- int space1 = line.indexOf(QLatin1Char(' '));
- int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1;
- QStringRef maptype = line.leftRef(space1);
- if (maptype==type) {
- // eg. 1.2-5
- QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-2:space2-space1-1);
- int dot = mapversions.indexOf(QLatin1Char('.'));
- int dash = mapversions.indexOf(QLatin1Char('-'));
- int mapvmaj = mapversions.left(dot).toInt();
- if (mapvmaj==vmaj) {
- int mapvmin_from = (dash <= 0 ? mapversions.mid(dot+1) : mapversions.mid(dot+1,dash-dot-1)).toInt();
- int mapvmin_to = dash <= 0 ? mapvmin_from : mapversions.mid(dash+1).toInt();
- if (vmin >= mapvmin_from && vmin <= mapvmin_to) {
- QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-2);
- return url.resolved(mapfile.toString());
+
+ if (isBuiltin.at(i)) {
+ QByteArray qt = urls.at(i).toLatin1();
+ qt += "/";
+ qt += type;
+ QmlType *t = QmlMetaType::qmlType(qt,vmaj,vmin);
+ if (vmajor) *vmajor = vmaj;
+ if (vminor) *vminor = vmin;
+ if (t) {
+ if (type_return)
+ *type_return = t;
+ return true;
+ }
+ } else {
+ QUrl url = QUrl(urls.at(i) + QLatin1String("/" + type + ".qml"));
+ if (vmaj || vmin) {
+ // Check version file - XXX cache these in QmlEngine!
+ QFile qmldir(QUrl(urls.at(i)+QLatin1String("/qmldir")).toLocalFile());
+ if (qmldir.open(QIODevice::ReadOnly)) {
+ do {
+ QByteArray lineba = qmldir.readLine();
+ if (lineba.at(0) == '#')
+ continue;
+ int space1 = lineba.indexOf(' ');
+ if (qstrncmp(lineba,type,space1)==0) {
+ // eg. 1.2-5
+ QString line = QString::fromUtf8(lineba);
+ space1 = line.indexOf(QLatin1Char(' ')); // refind in Unicode
+ int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1;
+ QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-2:space2-space1-1);
+ int dot = mapversions.indexOf(QLatin1Char('.'));
+ int dash = mapversions.indexOf(QLatin1Char('-'));
+ int mapvmaj = mapversions.left(dot).toInt();
+ if (mapvmaj==vmaj) {
+ int mapvmin_from = (dash <= 0 ? mapversions.mid(dot+1) : mapversions.mid(dot+1,dash-dot-1)).toInt();
+ int mapvmin_to = dash <= 0 ? mapvmin_from : mapversions.mid(dash+1).toInt();
+ if (vmin >= mapvmin_from && vmin <= mapvmin_to) {
+ QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-2);
+ if (url_return)
+ *url_return = url.resolved(mapfile.toString());
+ return true;
+ }
}
}
- }
- } while (!qmldir.atEnd());
+ } while (!qmldir.atEnd());
+ }
+ } else {
+ // XXX search non-files too! (eg. zip files, see QT-524)
+ QFileInfo f(url.toLocalFile());
+ if (f.exists()) {
+ if (url_return)
+ *url_return = url;
+ return true;
+ }
}
- } else {
- // XXX search non-files too! (eg. zip files, see QT-524)
- QFileInfo f(url.toLocalFile());
- if (f.exists())
- return url; // (unversioned) local import
}
}
- return QUrl();
- }
-
- QmlType *findBuiltin(const QByteArray& type, int *vmajor, int *vminor) const
- {
- for (int i=0; i<urls.count(); ++i) {
- int vmaj = majversions.at(i);
- int vmin = minversions.at(i);
- QByteArray qt = urls.at(i).toLatin1();
- qt += "/";
- qt += type;
- QmlType *t = QmlMetaType::qmlType(qt,vmaj,vmin);
- if (vmajor) *vmajor = vmaj;
- if (vminor) *vminor = vmin;
- if (t) return t;
- }
- return 0;
+ return false;
}
};
@@ -1216,22 +1226,14 @@ public:
{
QmlEnginePrivate::ImportedNamespace *s;
if (prefix.isEmpty()) {
- if (importType == QmlScriptParser::Import::Library && !vmaj && !vmin) {
- // unversioned library imports are always qualified - if only by final URI component
- int lastdot = uri.lastIndexOf(QLatin1Char('.'));
- QString defaultprefix = uri.mid(lastdot+1);
- s = set.value(defaultprefix);
- if (!s)
- set.insert(defaultprefix,(s=new QmlEnginePrivate::ImportedNamespace));
- } else {
- s = &unqualifiedset;
- }
+ s = &unqualifiedset;
} else {
s = set.value(prefix);
if (!s)
set.insert(prefix,(s=new QmlEnginePrivate::ImportedNamespace));
}
QString url = uri;
+ bool isbuiltin = false;
if (importType == QmlScriptParser::Import::Library) {
url.replace(QLatin1Char('.'),QLatin1Char('/'));
bool found = false;
@@ -1245,42 +1247,20 @@ public:
}
if (!found) {
// XXX assume it is a built-in type qualifier
+ isbuiltin = true;
}
} else {
url = base.resolved(QUrl(url)).toString();
}
- s->urls.append(url);
- s->majversions.append(vmaj);
- s->minversions.append(vmin);
- s->isLibrary.append(importType == QmlScriptParser::Import::Library);
+ s->urls.prepend(url);
+ s->majversions.prepend(vmaj);
+ s->minversions.prepend(vmin);
+ s->isLibrary.prepend(importType == QmlScriptParser::Import::Library);
+ s->isBuiltin.prepend(isbuiltin);
return true;
}
- QUrl find(const QString& type) const
- {
- const QmlEnginePrivate::ImportedNamespace *s = 0;
- int slash = type.indexOf(QLatin1Char('/'));
- if (slash >= 0) {
- while (!s) {
- s = set.value(type.left(slash));
- int nslash = type.indexOf(QLatin1Char('/'),slash+1);
- if (nslash > 0)
- slash = nslash;
- else
- break;
- }
- } else {
- s = &unqualifiedset;
- }
- QString unqualifiedtype = type.mid(slash+1);
- if (s)
- return s->find(unqualifiedtype);
- else
- return QUrl();
- }
-
-
- QmlType *findBuiltin(const QByteArray& type, int *vmajor, int *vminor)
+ bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return)
{
QmlEnginePrivate::ImportedNamespace *s = 0;
int slash = type.indexOf('/');
@@ -1297,10 +1277,16 @@ public:
s = &unqualifiedset;
}
QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
- if (s)
- return s->findBuiltin(unqualifiedtype,vmajor,vminor);
- else
- return 0;
+ if (s) {
+ if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return))
+ return true;
+ }
+ if (url_return) {
+ *url_return = base.resolved(QUrl(QLatin1String(type + ".qml")));
+ return true;
+ } else {
+ return false;
+ }
}
QmlEnginePrivate::ImportedNamespace *findNamespace(const QString& type)
@@ -1412,40 +1398,27 @@ bool QmlEnginePrivate::addToImport(Imports* imports, const QString& uri, const Q
*/
bool QmlEnginePrivate::resolveType(const Imports& imports, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *vmaj, int *vmin, ImportedNamespace** ns_return) const
{
- if (ns_return) {
- *ns_return = imports.d->findNamespace(QLatin1String(type));
- if (*ns_return)
- return true;
- }
- if (type_return) {
- QmlType* t = imports.d->findBuiltin(type,vmaj,vmin);
- if (!t) {
- // XXX do we really still need this?
- t = QmlMetaType::qmlType(type,0,0); // Try global namespace
- if (vmin) *vmin = 0;
- if (vmaj) *vmaj = 0;
- }
- if (t) {
- if (type_return) *type_return = t;
- if (qmlImportTrace())
- qDebug() << "QmlEngine::resolveType" << type << "= (builtin)";
- return true;
- }
+ ImportedNamespace* ns = imports.d->findNamespace(QLatin1String(type));
+ if (ns) {
+ if (qmlImportTrace())
+ qDebug() << "QmlEngine::resolveType" << type << "is namespace for" << ns->urls;
+ if (ns_return)
+ *ns_return = ns;
+ return true;
}
- if (url_return) {
- QUrl url = imports.d->find(QLatin1String(type));
- if (!url.isValid())
- url = imports.d->base.resolved(QUrl(QLatin1String(type + ".qml")));
-
- if (url.isValid()) {
- if (url_return) *url_return = url;
- if (qmlImportTrace())
- qDebug() << "QmlEngine::resolveType" << type << "=" << url;
+ if (type_return || url_return) {
+ if (imports.d->find(type,vmaj,vmin,type_return,url_return)) {
+ if (qmlImportTrace()) {
+ if (type_return && *type_return)
+ qDebug() << "QmlEngine::resolveType" << type << "=" << (*type_return)->typeName();
+ if (url_return)
+ qDebug() << "QmlEngine::resolveType" << type << "=" << *url_return;
+ }
return true;
}
+ if (qmlImportTrace())
+ qDebug() << "QmlEngine::resolveType" << type << "not found";
}
- if (qmlImportTrace())
- qDebug() << "QmlEngine::resolveType" << type << " not found";
return false;
}
@@ -1461,12 +1434,7 @@ bool QmlEnginePrivate::resolveType(const Imports& imports, const QByteArray& typ
*/
void QmlEnginePrivate::resolveTypeInNamespace(ImportedNamespace* ns, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *vmaj, int *vmin ) const
{
- if (type_return) {
- *type_return = ns->findBuiltin(type,vmaj,vmin);
- }
- if (url_return) {
- *url_return = ns->find(QLatin1String(type));
- }
+ ns->find(type,vmaj,vmin,type_return,url_return);
}
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h
index aeee355..b3c6279 100644
--- a/src/declarative/qml/qmlengine_p.h
+++ b/src/declarative/qml/qmlengine_p.h
@@ -114,7 +114,7 @@ public:
QPODVector<CapturedProperty> capturedProperties;
QmlContext *rootContext;
- QmlContext *currentBindContext;
+ QmlContext *currentBindContext; // ### Remove me
QmlExpression *currentExpression;
bool isDebugging;
#ifdef QT_SCRIPTTOOLS_LIB
@@ -124,9 +124,12 @@ public:
QmlContextScriptClass *contextClass;
QmlObjectScriptClass *objectClass;
QmlValueTypeScriptClass *valueTypeClass;
+ // Used by DOM Core 3 API
+ QScriptClass *nodeListClass;
+ QScriptClass *namedNodeMapClass;
QmlContext *setCurrentBindContext(QmlContext *);
- QStack<QmlContext *> activeContexts;
+ QStack<QmlContext *> activeContexts; // ### Remove me
struct QmlScriptEngine : public QScriptEngine
{
diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp
index fb92c54..0cfd794 100644
--- a/src/declarative/qml/qmlxmlhttprequest.cpp
+++ b/src/declarative/qml/qmlxmlhttprequest.cpp
@@ -46,6 +46,10 @@
#include <QtScript/qscriptcontext.h>
#include <QtScript/qscriptengine.h>
#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qxmlstream.h>
+#include <private/qmlrefcount_p.h>
+#include <private/qmlengine_p.h>
+#include <QtCore/qstack.h>
#include "qmlxmlhttprequest_p.h"
#include <QtCore/qdebug.h>
@@ -53,6 +57,840 @@
// ### Find real values
#define INVALID_STATE_ERR ((QScriptContext::Error)15)
+#define D(arg) (arg)->release()
+#define A(arg) (arg)->addref()
+
+namespace {
+
+class NodeImpl : public QmlRefCount
+{
+public:
+ NodeImpl() : type(Element), parent(0) {}
+ virtual ~NodeImpl() {
+ if (parent) D(parent);
+ for (int ii = 0; ii < children.count(); ++ii)
+ D(children.at(ii));
+ for (int ii = 0; ii < attributes.count(); ++ii)
+ D(attributes.at(ii));
+ }
+
+ // These numbers are copied from the Node IDL definition
+ enum Type {
+ Attr = 2,
+ CDATA = 4,
+ Comment = 8,
+ Document = 9,
+ DocumentFragment = 11,
+ DocumentType = 10,
+ Element = 1,
+ Entity = 6,
+ EntityReference = 5,
+ Notation = 12,
+ ProcessingInstruction = 7,
+ Text = 3
+ };
+ Type type;
+
+ QString namespaceUri;
+ QString name;
+
+ QString data;
+
+ NodeImpl *parent;
+
+ QList<NodeImpl *> children;
+ QList<NodeImpl *> attributes;
+};
+
+class DocumentImpl : public QmlRefCount
+{
+public:
+ DocumentImpl() : root(0) {}
+ virtual ~DocumentImpl() {
+ if (root) D(root);
+ }
+
+ QString version;
+ QString encoding;
+ bool isStandalone;
+
+ NodeImpl *root;
+};
+
+class NamedNodeMap
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *, QList<NodeImpl *> *);
+
+ NamedNodeMap();
+ NamedNodeMap(const NamedNodeMap &);
+ NamedNodeMap &operator=(const NamedNodeMap &);
+ ~NamedNodeMap();
+ bool isNull();
+
+ NodeImpl *d;
+ QList<NodeImpl *> *list;
+};
+
+class NamedNodeMapClass : public QScriptClass
+{
+public:
+ NamedNodeMapClass(QScriptEngine *engine) : QScriptClass(engine) {}
+
+ virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class NodeList
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue item(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+ NodeList();
+ NodeList(const NodeList &);
+ NodeList &operator=(const NodeList &);
+ ~NodeList();
+ bool isNull();
+
+ NodeImpl *d;
+};
+
+class NodeListClass : public QScriptClass
+{
+public:
+ NodeListClass(QScriptEngine *engine) : QScriptClass(engine) {}
+ virtual QueryFlags queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id);
+ virtual QScriptValue property(const QScriptValue &object, const QScriptString &name, uint id);
+};
+
+class Node
+{
+public:
+ // JS API
+ static QScriptValue nodeName(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nodeValue(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nodeType(QScriptContext *context, QScriptEngine *engine);
+
+ static QScriptValue parentNode(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue childNodes(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue firstChild(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue lastChild(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue previousSibling(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue nextSibling(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue attributes(QScriptContext *context, QScriptEngine *engine);
+
+ //static QScriptValue ownerDocument(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue namespaceURI(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue prefix(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue localName(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue baseURI(QScriptContext *context, QScriptEngine *engine);
+ //static QScriptValue textContent(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue create(QScriptEngine *, NodeImpl *);
+
+ Node();
+ Node(const Node &o);
+ Node &operator=(const Node &);
+ ~Node();
+ bool isNull() const;
+
+ NodeImpl *d;
+};
+
+class Element : public Node
+{
+public:
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class CharacterData : public Node
+{
+public:
+ // JS API
+ static QScriptValue length(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Text : public CharacterData
+{
+public:
+ // JS API
+ static QScriptValue isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue wholeText(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class CDATA : public Text
+{
+public:
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+};
+
+class Document : public Node
+{
+public:
+ // JS API
+ static QScriptValue xmlVersion(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue xmlEncoding(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue xmlStandalone(QScriptContext *context, QScriptEngine *engine);
+ static QScriptValue documentElement(QScriptContext *context, QScriptEngine *engine);
+
+ // C++ API
+ static QScriptValue prototype(QScriptEngine *);
+ static QScriptValue load(QScriptEngine *engine, const QString &data);
+
+ Document();
+ Document(const Document &);
+ Document &operator=(const Document &);
+ ~Document();
+ bool isNull() const;
+
+ DocumentImpl *d;
+private:
+ Document(DocumentImpl *);
+};
+
+};
+
+Q_DECLARE_METATYPE(Node);
+Q_DECLARE_METATYPE(NodeList);
+Q_DECLARE_METATYPE(NamedNodeMap);
+Q_DECLARE_METATYPE(Document);
+
+QScriptValue Node::nodeName(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+ return QScriptValue(node.d->name);
+}
+
+QScriptValue Node::nodeValue(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->data);
+}
+
+QScriptValue Node::nodeType(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+ return QScriptValue(node.d->type);
+}
+
+QScriptValue Node::parentNode(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->parent) return Node::create(engine, node.d->parent);
+ else return engine->nullValue();
+}
+
+QScriptValue Node::childNodes(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return NodeList::create(engine, node.d);
+}
+
+QScriptValue Node::firstChild(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->children.isEmpty()) return engine->nullValue();
+ else return Node::create(engine, node.d->children.first());
+}
+
+QScriptValue Node::lastChild(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->children.isEmpty()) return engine->nullValue();
+ else return Node::create(engine, node.d->children.last());
+}
+
+QScriptValue Node::previousSibling(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (!node.d->parent) return engine->nullValue();
+
+ for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+ if (node.d->parent->children.at(ii) == node.d) {
+ if (ii == 0) return engine->nullValue();
+ else return Node::create(engine, node.d->parent->children.at(ii - 1));
+ }
+ }
+
+ return engine->nullValue();
+}
+
+QScriptValue Node::nextSibling(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (!node.d->parent) return engine->nullValue();
+
+ for (int ii = 0; ii < node.d->parent->children.count(); ++ii) {
+ if (node.d->parent->children.at(ii) == node.d) {
+ if ((ii + 1) == node.d->parent->children.count()) return engine->nullValue();
+ else return Node::create(engine, node.d->parent->children.at(ii + 1));
+ }
+ }
+
+ return engine->nullValue();
+}
+
+QScriptValue Node::attributes(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ if (node.d->type != NodeImpl::Element)
+ return engine->nullValue();
+ else
+ return NamedNodeMap::create(engine, node.d, &node.d->attributes);
+}
+
+QScriptValue Node::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("nodeName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("nodeValue"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("nodeType"), engine->newFunction(nodeType), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("parentNode"), engine->newFunction(parentNode), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("childNodes"), engine->newFunction(childNodes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("firstChild"), engine->newFunction(firstChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("lastChild"), engine->newFunction(lastChild), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("previousSibling"), engine->newFunction(previousSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("nextSibling"), engine->newFunction(nextSibling), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("attributes"), engine->newFunction(attributes), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Node::create(QScriptEngine *engine, NodeImpl *data)
+{
+ QScriptValue instance = engine->newObject();
+
+ switch (data->type) {
+ case NodeImpl::Attr:
+ case NodeImpl::Comment:
+ case NodeImpl::Document:
+ case NodeImpl::DocumentFragment:
+ case NodeImpl::DocumentType:
+ case NodeImpl::Entity:
+ case NodeImpl::EntityReference:
+ case NodeImpl::Notation:
+ case NodeImpl::CDATA:
+ instance.setPrototype(CDATA::prototype(engine));
+ break;
+ case NodeImpl::ProcessingInstruction:
+ instance.setPrototype(Node::prototype(engine));
+ break;
+ case NodeImpl::Text:
+ instance.setPrototype(Text::prototype(engine));
+ break;
+ case NodeImpl::Element:
+ instance.setPrototype(Element::prototype(engine));
+ break;
+ }
+
+ Node node;
+ node.d = data;
+ if (data) A(data);
+
+ return engine->newVariant(instance, qVariantFromValue(node));
+}
+
+QScriptValue Element::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("tagName"), engine->newFunction(nodeName), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue CharacterData::length(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(node.d->data.length());
+}
+
+QScriptValue CharacterData::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("data"), engine->newFunction(nodeValue), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Text::isElementContentWhitespace(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ // ### implement
+ return QScriptValue(false);
+}
+
+QScriptValue Text::wholeText(QScriptContext *context, QScriptEngine *engine)
+{
+ Node node = qscriptvalue_cast<Node>(context->thisObject());
+ if (node.isNull()) return engine->undefinedValue();
+
+ // ### implement
+ return QScriptValue(QString());
+}
+
+QScriptValue Text::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(CharacterData::prototype(engine));
+
+ proto.setProperty(QLatin1String("isElementContentWhitespace"), engine->newFunction(isElementContentWhitespace), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("wholeText"), engine->newFunction(wholeText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue CDATA::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Text::prototype(engine));
+ return proto;
+}
+
+QScriptValue Document::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+ proto.setPrototype(Node::prototype(engine));
+
+ proto.setProperty(QLatin1String("xmlVersion"), engine->newFunction(xmlVersion), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("xmlEncoding"), engine->newFunction(xmlEncoding), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("xmlStandalone"), engine->newFunction(xmlStandalone), QScriptValue::ReadOnly | QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
+ proto.setProperty(QLatin1String("documentElement"), engine->newFunction(documentElement), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue Document::load(QScriptEngine *engine, const QString &data)
+{
+ Q_ASSERT(engine);
+
+ DocumentImpl *document = 0;
+ QStack<NodeImpl *> nodeStack;
+
+ QXmlStreamReader reader(data);
+
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ break;
+ case QXmlStreamReader::Invalid:
+ break;
+ case QXmlStreamReader::StartDocument:
+ Q_ASSERT(!document);
+ document = new DocumentImpl;
+ document->version = reader.documentVersion().toString();
+ document->encoding = reader.documentEncoding().toString();
+ document->isStandalone = reader.isStandaloneDocument();
+ break;
+ case QXmlStreamReader::EndDocument:
+ break;
+ case QXmlStreamReader::StartElement:
+ {
+ Q_ASSERT(document);
+ NodeImpl *node = new NodeImpl;
+ node->namespaceUri = reader.namespaceUri().toString();
+ node->name = reader.name().toString();
+ if (nodeStack.isEmpty()) {
+ document->root = node;
+ } else {
+ node->parent = nodeStack.top();
+ A(node->parent);
+ node->parent->children.append(node);
+ }
+ nodeStack.append(node);
+
+ foreach (const QXmlStreamAttribute &a, reader.attributes()) {
+ NodeImpl *attr = new NodeImpl;
+ attr->type = NodeImpl::Attr;
+ attr->namespaceUri = a.namespaceUri().toString();
+ attr->name = a.name().toString();
+ attr->data = a.value().toString();
+ node->attributes.append(attr);
+ }
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ nodeStack.pop();
+ break;
+ case QXmlStreamReader::Characters:
+ {
+ NodeImpl *node = new NodeImpl;
+ node->type = reader.isCDATA()?NodeImpl::CDATA:NodeImpl::Text;
+ node->parent = nodeStack.top();
+ A(node->parent);
+ node->parent->children.append(node);
+ node->data = reader.text().toString();
+ }
+ break;
+ case QXmlStreamReader::Comment:
+ break;
+ case QXmlStreamReader::DTD:
+ break;
+ case QXmlStreamReader::EntityReference:
+ break;
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+
+ if (!document || reader.hasError()) {
+ if (document) D(document);
+ return engine->nullValue();
+ }
+
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(Document::prototype(engine));
+ return engine->newVariant(instance, qVariantFromValue(Document(document)));
+}
+
+Node::Node()
+: d(0)
+{
+}
+
+Node::Node(const Node &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+Node &Node::operator=(const Node &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ return *this;
+}
+
+Node::~Node()
+{
+ if (d) D(d);
+}
+
+bool Node::isNull() const
+{
+ return d == 0;
+}
+
+QScriptValue NamedNodeMap::length(QScriptContext *context, QScriptEngine *engine)
+{
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(context->thisObject().data());
+ if (map.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(map.list->count());
+}
+
+QScriptValue NamedNodeMap::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+
+ return proto;
+}
+
+QScriptValue NamedNodeMap::create(QScriptEngine *engine, NodeImpl *data, QList<NodeImpl *> *list)
+{
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(NamedNodeMap::prototype(engine));
+
+ NamedNodeMap map;
+ map.d = data;
+ map.list = list;
+ if (data) A(data);
+
+ instance.setData(engine->newVariant(qVariantFromValue(map)));
+
+ if (!QmlEnginePrivate::get(engine)->namedNodeMapClass)
+ QmlEnginePrivate::get(engine)->namedNodeMapClass= new NamedNodeMapClass(engine);
+
+ instance.setScriptClass(QmlEnginePrivate::get(engine)->namedNodeMapClass);
+
+ return instance;
+}
+
+NamedNodeMap::NamedNodeMap()
+: d(0), list(0)
+{
+}
+
+NamedNodeMap::NamedNodeMap(const NamedNodeMap &o)
+: d(o.d), list(o.list)
+{
+ if (d) A(d);
+}
+
+NamedNodeMap &NamedNodeMap::operator=(const NamedNodeMap &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ list = o.list;
+ return *this;
+}
+
+NamedNodeMap::~NamedNodeMap()
+{
+ if (d) D(d);
+}
+
+bool NamedNodeMap::isNull()
+{
+ return d == 0;
+}
+
+QScriptValue NodeList::item(QScriptContext *context, QScriptEngine *engine)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
+ if (list.isNull() || context->argumentCount() != 1)
+ return engine->undefinedValue();
+
+ qint32 index = context->argument(0).toInt32();
+
+ if (index >= list.d->children.count())
+ return engine->undefinedValue(); // ### Exception
+ else
+ return Node::create(engine, list.d->children.at(index));
+}
+
+QScriptValue NodeList::length(QScriptContext *context, QScriptEngine *engine)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(context->thisObject().data());
+ if (list.isNull()) return engine->undefinedValue();
+
+ return QScriptValue(list.d->children.count());
+}
+
+QScriptValue NodeList::prototype(QScriptEngine *engine)
+{
+ QScriptValue proto = engine->newObject();
+
+ proto.setProperty(QLatin1String("length"), engine->newFunction(length), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ proto.setProperty(QLatin1String("item"), engine->newFunction(item, 1), QScriptValue::ReadOnly);
+
+ return proto;
+}
+
+QScriptValue NodeList::create(QScriptEngine *engine, NodeImpl *data)
+{
+ QScriptValue instance = engine->newObject();
+ instance.setPrototype(NodeList::prototype(engine));
+
+ NodeList list;
+ list.d = data;
+ if (data) A(data);
+
+ instance.setData(engine->newVariant(qVariantFromValue(list)));
+
+ if (!QmlEnginePrivate::get(engine)->nodeListClass)
+ QmlEnginePrivate::get(engine)->nodeListClass= new NodeListClass(engine);
+
+ instance.setScriptClass(QmlEnginePrivate::get(engine)->nodeListClass);
+
+ return instance;
+}
+
+NodeList::NodeList()
+: d(0)
+{
+}
+
+NodeList::NodeList(const NodeList &o)
+: d(o.d)
+{
+ if (d) A(d);
+}
+
+NodeList &NodeList::operator=(const NodeList &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ return *this;
+}
+
+NodeList::~NodeList()
+{
+ if (d) D(d);
+}
+
+bool NodeList::isNull()
+{
+ return d == 0;
+}
+
+NamedNodeMapClass::QueryFlags NamedNodeMapClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+ if (!(flags & HandlesReadAccess))
+ return 0;
+
+ bool ok = false;
+ uint index = name.toString().toUInt(&ok);
+ if (!ok)
+ return 0;
+
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+ if (map.isNull() || (uint)map.list->count() <= index)
+ return 0; // ### I think we're meant to raise an exception
+
+ *id = index;
+ return HandlesReadAccess;
+}
+
+QScriptValue NamedNodeMapClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+ NamedNodeMap map = qscriptvalue_cast<NamedNodeMap>(object.data());
+ return Node::create(engine(), map.list->at(id));
+}
+
+NodeListClass::QueryFlags NodeListClass::queryProperty(const QScriptValue &object, const QScriptString &name, QueryFlags flags, uint *id)
+{
+ if (!(flags & HandlesReadAccess))
+ return 0;
+
+ bool ok = false;
+ uint index = name.toString().toUInt(&ok);
+ if (!ok)
+ return 0;
+
+ NodeList list = qscriptvalue_cast<NodeList>(object.data());
+ if (list.isNull() || (uint)list.d->children.count() <= index)
+ return 0; // ### I think we're meant to raise an exception
+
+ *id = index;
+ return HandlesReadAccess;
+}
+
+QScriptValue NodeListClass::property(const QScriptValue &object, const QScriptString &, uint id)
+{
+ NodeList list = qscriptvalue_cast<NodeList>(object.data());
+ return Node::create(engine(), list.d->children.at(id));
+}
+
+Document::Document()
+: d(0)
+{
+}
+
+Document::Document(DocumentImpl *data)
+: d(data)
+{
+}
+
+Document::Document(const Document &o)
+: Node(o), d(o.d)
+{
+ if (d) A(d);
+}
+
+Document &Document::operator=(const Document &o)
+{
+ if (o.d) A(o.d);
+ if (d) D(d);
+ d = o.d;
+ return *this;
+}
+
+Document::~Document()
+{
+ if (d) D(d);
+}
+
+bool Document::isNull() const
+{
+ return d == 0;
+}
+
+QScriptValue Document::documentElement(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (!document.d->root) return engine->nullValue();
+
+ return Node::create(engine, document.d->root);
+}
+
+QScriptValue Document::xmlStandalone(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (context->argumentCount())
+ document.d->isStandalone = context->argument(0).toBool();
+
+ return QScriptValue(document.d->isStandalone);
+}
+
+QScriptValue Document::xmlVersion(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (context->argumentCount())
+ document.d->version = context->argument(0).toString();
+
+ return QScriptValue(document.d->version);
+}
+
+QScriptValue Document::xmlEncoding(QScriptContext *context, QScriptEngine *engine)
+{
+ Document document = qscriptvalue_cast<Document>(context->thisObject());
+ if (document.isNull()) return engine->undefinedValue();
+
+ if (context->argumentCount())
+ document.d->encoding = context->argument(0).toString();
+
+ return QScriptValue(document.d->encoding);
+}
+
class QmlXMLHttpRequest : public QObject
{
Q_OBJECT
@@ -311,8 +1149,13 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin
// Argument 1 - URL
QUrl url(context->argument(1).toString()); // ### Need to resolve correctly
- if (url.isRelative()) // ### Fix me
- return context->throwError(QScriptContext::SyntaxError, "Relative URLs not supported");
+ if (url.isRelative()) {
+ QmlContext *ctxt = QmlEnginePrivate::get(engine)->currentExpression?QmlEnginePrivate::get(engine)->currentExpression->context():0;
+ if (ctxt)
+ url = ctxt->resolvedUrl(url);
+ else
+ return context->throwError(QScriptContext::SyntaxError, "Relative URLs not supported");
+ }
// Argument 2 - async (optional)
if (context->argumentCount() > 2 && !context->argument(2).toBoolean())
@@ -480,6 +1323,18 @@ static QScriptValue qmlxmlhttprequest_responseText(QScriptContext *context, QScr
return QScriptValue(request->responseBody());
}
+static QScriptValue qmlxmlhttprequest_responseXML(QScriptContext *context, QScriptEngine *engine)
+{
+ QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject());
+ if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object"));
+
+ if (request->readyState() != QmlXMLHttpRequest::Loading &&
+ request->readyState() != QmlXMLHttpRequest::Done)
+ return engine->nullValue();
+ else
+ return Document::load(engine, request->responseBody());
+}
+
static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context, QScriptEngine *engine)
{
QmlXMLHttpRequest *request = qobject_cast<QmlXMLHttpRequest *>(context->thisObject().data().toQObject());
@@ -494,23 +1349,16 @@ static QScriptValue qmlxmlhttprequest_onreadystatechange(QScriptContext *context
// Constructor
static QScriptValue qmlxmlhttprequest_new(QScriptContext *context, QScriptEngine *engine)
{
- QScriptValue rv = engine->newObject();
- rv.setPrototype(context->callee().data());
- rv.setData(engine->newQObject(new QmlXMLHttpRequest(QmlEnginePrivate::getEngine(engine)), QScriptEngine::ScriptOwnership));
- return rv;
+ if (context->isCalledAsConstructor()) {
+ context->thisObject().setData(engine->newQObject(new QmlXMLHttpRequest(QmlEnginePrivate::getEngine(engine)), QScriptEngine::ScriptOwnership));
+ }
+ return engine->undefinedValue();
}
void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
{
QScriptValue prototype = engine->newObject();
- // Constants
- prototype.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
- prototype.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
-
// Methods
prototype.setProperty(QLatin1String("open"), engine->newFunction(qmlxmlhttprequest_open, 2));
prototype.setProperty(QLatin1String("setRequestHeader"), engine->newFunction(qmlxmlhttprequest_setRequestHeader, 2));
@@ -524,11 +1372,16 @@ void qt_add_qmlxmlhttprequest(QScriptEngine *engine)
prototype.setProperty(QLatin1String("status"), engine->newFunction(qmlxmlhttprequest_status), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
prototype.setProperty(QLatin1String("statusText"), engine->newFunction(qmlxmlhttprequest_statusText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
prototype.setProperty(QLatin1String("responseText"), engine->newFunction(qmlxmlhttprequest_responseText), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
+ prototype.setProperty(QLatin1String("responseXML"), engine->newFunction(qmlxmlhttprequest_responseXML), QScriptValue::ReadOnly | QScriptValue::PropertyGetter);
prototype.setProperty(QLatin1String("onreadystatechange"), engine->newFunction(qmlxmlhttprequest_onreadystatechange), QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
// Constructor
- QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new);
- constructor.setData(prototype);
+ QScriptValue constructor = engine->newFunction(qmlxmlhttprequest_new, prototype);
+ constructor.setProperty(QLatin1String("UNSENT"), 0, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("OPENED"), 1, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("HEADERS_RECEIVED"), 2, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("LOADING"), 3, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
+ constructor.setProperty(QLatin1String("DONE"), 4, QScriptValue::ReadOnly | QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
engine->globalObject().setProperty(QLatin1String("XMLHttpRequest"), constructor);
}
diff --git a/tests/auto/declarative/qmlparser/failingComponent.errors.txt b/tests/auto/declarative/qmlparser/failingComponent.errors.txt
index 190a649..0cf0ef3 100644
--- a/tests/auto/declarative/qmlparser/failingComponent.errors.txt
+++ b/tests/auto/declarative/qmlparser/failingComponent.errors.txt
@@ -1,2 +1 @@
-3:5:Unable to create type FailingComponent
-4:5:Cannot assign to non-existant property "a"
+3:5:Type FailingComponent unavailable
diff --git a/tests/auto/declarative/qmlparser/importNamespaceConflict.errors.txt b/tests/auto/declarative/qmlparser/importNamespaceConflict.errors.txt
new file mode 100644
index 0000000..231998d
--- /dev/null
+++ b/tests/auto/declarative/qmlparser/importNamespaceConflict.errors.txt
@@ -0,0 +1 @@
+4:1:Namespace Rectangle cannot be used as a type
diff --git a/tests/auto/declarative/qmlparser/importNamespaceConflict.qml b/tests/auto/declarative/qmlparser/importNamespaceConflict.qml
new file mode 100644
index 0000000..cd112af
--- /dev/null
+++ b/tests/auto/declarative/qmlparser/importNamespaceConflict.qml
@@ -0,0 +1,4 @@
+import Test 1.0 as Rectangle
+import Qt 4.6
+
+Rectangle { }
diff --git a/tests/auto/declarative/qmlparser/lib/com/nokia/installedtest/qmldir b/tests/auto/declarative/qmlparser/lib/com/nokia/installedtest/qmldir
index f22e179..ba0b42a 100644
--- a/tests/auto/declarative/qmlparser/lib/com/nokia/installedtest/qmldir
+++ b/tests/auto/declarative/qmlparser/lib/com/nokia/installedtest/qmldir
@@ -1,2 +1,3 @@
InstalledTest 1.0-3 InstalledTest.qml
InstalledTest 1.4 InstalledTest2.qml
+Rectangle 1.5 InstalledTest2.qml
diff --git a/tests/auto/declarative/qmlparser/testtypes.h b/tests/auto/declarative/qmlparser/testtypes.h
index ace7ef9..f700484 100644
--- a/tests/auto/declarative/qmlparser/testtypes.h
+++ b/tests/auto/declarative/qmlparser/testtypes.h
@@ -357,12 +357,13 @@ private:
QML_DECLARE_TYPE(MyContainer);
-class MyPropertyValueSource : public QmlPropertyValueSource
+class MyPropertyValueSource : public QObject, public QmlPropertyValueSource
{
Q_OBJECT
+ Q_INTERFACES(QmlPropertyValueSource)
public:
MyPropertyValueSource()
- : QmlPropertyValueSource(0) {}
+ : QmlPropertyValueSource() {}
QmlMetaProperty prop;
virtual void setTarget(const QmlMetaProperty &p)
diff --git a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp
index 3047bb0..36471a4 100644
--- a/tests/auto/declarative/qmlparser/tst_qmlparser.cpp
+++ b/tests/auto/declarative/qmlparser/tst_qmlparser.cpp
@@ -48,14 +48,21 @@ private slots:
void customVariantTypes();
void valueTypes();
- void imports_data();
- void imports();
+ void importsBuiltin_data();
+ void importsBuiltin();
+ void importsLocal_data();
+ void importsLocal();
+ void importsInstalled_data();
+ void importsInstalled();
+ void importsOrder_data();
+ void importsOrder();
// regression tests for crashes
void crash1();
private:
QmlEngine engine;
+ void testType(const QString& qml, const QString& type);
};
#define VERIFY_ERRORS(errorfile) \
@@ -148,6 +155,8 @@ void tst_qmlparser::errors_data()
QTest::newRow("failingComponent") << "failingComponentTest.qml" << "failingComponent.errors.txt" << false;
QTest::newRow("missingSignal") << "missingSignal.qml" << "missingSignal.errors.txt" << false;
QTest::newRow("finalOverride") << "finalOverride.qml" << "finalOverride.errors.txt" << false;
+
+ QTest::newRow("importNamespaceConflict") << "importNamespaceConflict.qml" << "importNamespaceConflict.errors.txt" << false;
}
void tst_qmlparser::errors()
@@ -420,6 +429,10 @@ void tst_qmlparser::autoComponentCreation()
void tst_qmlparser::propertyValueSource()
{
+ QVERIFY(false);
+
+/* Does not compile...
+
QmlComponent component(&engine, TEST_FILE("propertyValueSource.qml"));
VERIFY_ERRORS(0);
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
@@ -432,6 +445,7 @@ void tst_qmlparser::propertyValueSource()
QVERIFY(valueSource != 0);
QCOMPARE(valueSource->prop.object(), object);
QCOMPARE(valueSource->prop.name(), QString(QLatin1String("intProperty")));
+*/
}
void tst_qmlparser::attachedProperties()
@@ -502,6 +516,21 @@ public:
TestType2(QObject *p=0) : QObject(p) {}
};
+// Check that first child of qml is of given type. Empty type insists on error.
+void tst_qmlparser::testType(const QString& qml, const QString& type)
+{
+ QmlComponent component(&engine, qml.toUtf8(), TEST_FILE("empty.qml")); // just a file for relative local imports
+
+ if (type.isEmpty()) {
+ QVERIFY(component.isError());
+ } else {
+ VERIFY_ERRORS(0);
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(QString(object->metaObject()->className()), type);
+ }
+}
+
QML_DECLARE_TYPE(TestType)
QML_DECLARE_TYPE(TestType2)
@@ -511,7 +540,7 @@ QML_DEFINE_TYPE(com.nokia.Test, 1, 8, 9, Test, TestType2)
QML_DEFINE_TYPE(com.nokia.Test, 1, 12, 13, Test, TestType2)
QML_DEFINE_TYPE(com.nokia.Test, 1, 9, 11, OldTest, TestType)
-void tst_qmlparser::imports_data()
+void tst_qmlparser::importsBuiltin_data()
{
QTest::addColumn<QString>("qml");
QTest::addColumn<QString>("type");
@@ -605,6 +634,19 @@ void tst_qmlparser::imports_data()
"import com.nokia.Test 1.10 as T10\n"
"T10.Test {}"
<< "";
+}
+
+void tst_qmlparser::importsBuiltin()
+{
+ QFETCH(QString, qml);
+ QFETCH(QString, type);
+ testType(qml,type);
+}
+
+void tst_qmlparser::importsLocal_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<QString>("type");
// import locals
QTest::newRow("local import")
@@ -624,6 +666,19 @@ void tst_qmlparser::imports_data()
"import com.nokia.Test 1.0\n"
"Test {}"
<< "TestType";
+}
+
+void tst_qmlparser::importsLocal()
+{
+ QFETCH(QString, qml);
+ QFETCH(QString, type);
+ testType(qml,type);
+}
+
+void tst_qmlparser::importsInstalled_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<QString>("type");
// import installed
QTest::newRow("installed import")
@@ -636,21 +691,70 @@ void tst_qmlparser::imports_data()
<< "QFxText";
}
-void tst_qmlparser::imports()
+void tst_qmlparser::importsInstalled()
{
QFETCH(QString, qml);
QFETCH(QString, type);
+ testType(qml,type);
+}
- QmlComponent component(&engine, qml.toUtf8(), TEST_FILE("empty.qml")); // just a file for relative local imports
- if (type.isEmpty()) {
- QVERIFY(component.isError());
- } else {
- VERIFY_ERRORS(0);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(QString(object->metaObject()->className()), type);
- }
+void tst_qmlparser::importsOrder_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<QString>("type");
+
+ QTest::newRow("installed import overrides 1") <<
+ "import com.nokia.installedtest 1.0\n"
+ "import com.nokia.installedtest 1.4\n"
+ "InstalledTest {}"
+ << "QFxText";
+ QTest::newRow("installed import overrides 2") <<
+ "import com.nokia.installedtest 1.4\n"
+ "import com.nokia.installedtest 1.0\n"
+ "InstalledTest {}"
+ << "QFxRect";
+ QTest::newRow("installed import re-overrides 1") <<
+ "import com.nokia.installedtest 1.4\n"
+ "import com.nokia.installedtest 1.0\n"
+ "import com.nokia.installedtest 1.4\n"
+ "InstalledTest {}"
+ << "QFxText";
+ QTest::newRow("installed import re-overrides 2") <<
+ "import com.nokia.installedtest 1.4\n"
+ "import com.nokia.installedtest 1.0\n"
+ "import com.nokia.installedtest 1.4\n"
+ "import com.nokia.installedtest 1.0\n"
+ "InstalledTest {}"
+ << "QFxRect";
+
+ QTest::newRow("installed import versus builtin 1") <<
+ "import com.nokia.installedtest 1.5\n"
+ "import Qt 4.6\n"
+ "Rectangle {}"
+ << "QFxRect";
+ QTest::newRow("installed import versus builtin 2") <<
+ "import Qt 4.6\n"
+ "import com.nokia.installedtest 1.5\n"
+ "Rectangle {}"
+ << "QFxText";
+ QTest::newRow("namespaces cannot be overridden by types 1") <<
+ "import Qt 4.6 as Rectangle\n"
+ "import com.nokia.installedtest 1.5\n"
+ "Rectangle {}"
+ << "";
+ QTest::newRow("namespaces cannot be overridden by types 2") <<
+ "import Qt 4.6 as Rectangle\n"
+ "import com.nokia.installedtest 1.5\n"
+ "Rectangle.Image {}"
+ << "QFxImage";
+}
+
+void tst_qmlparser::importsOrder()
+{
+ QFETCH(QString, qml);
+ QFETCH(QString, type);
+ testType(qml,type);
}
void tst_qmlparser::crash1()