summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/declarative/flickr/flickr.qml22
-rw-r--r--demos/declarative/flickr/flickr2.qml22
-rw-r--r--doc/src/declarative/elements.qdoc2
-rw-r--r--examples/declarative/flowview/flickr.qml22
-rw-r--r--examples/declarative/xmldata/daringfireball.qml8
-rw-r--r--examples/declarative/xmldata/yahoonews.qml8
-rw-r--r--src/declarative/extra/qmlxmllistmodel.cpp115
-rw-r--r--src/declarative/extra/qmlxmllistmodel.h15
8 files changed, 162 insertions, 52 deletions
diff --git a/demos/declarative/flickr/flickr.qml b/demos/declarative/flickr/flickr.qml
index 3ce442e..edf1095 100644
--- a/demos/declarative/flickr/flickr.qml
+++ b/demos/declarative/flickr/flickr.qml
@@ -10,19 +10,19 @@ Item {
id: FeedModel
property string tags : TagsEdit.text
source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2"
- query: "doc($src)/rss/channel/item"
+ query: "/rss/channel/item"
namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";"
- Role { name: "title"; query: "title/string()" }
- Role { name: "imagePath"; query: "media:thumbnail/@url/string()" }
- Role { name: "url"; query: "media:content/@url/string()" }
- Role { name: "description"; query: "description/string()" }
- Role { name: "tags"; query: "media:category/string()" }
- Role { name: "photoWidth"; query: "media:content/@width/string()" }
- Role { name: "photoHeight"; query: "media:content/@height/string()" }
- Role { name: "photoType"; query: "media:content/@type/string()" }
- Role { name: "photoAuthor"; query: "author/string()" }
- Role { name: "photoDate"; query: "pubDate/string()" }
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "imagePath"; query: "media:thumbnail/@url/string()" }
+ XmlRole { name: "url"; query: "media:content/@url/string()" }
+ XmlRole { name: "description"; query: "description/string()" }
+ XmlRole { name: "tags"; query: "media:category/string()" }
+ XmlRole { name: "photoWidth"; query: "media:content/@width/string()" }
+ XmlRole { name: "photoHeight"; query: "media:content/@height/string()" }
+ XmlRole { name: "photoType"; query: "media:content/@type/string()" }
+ XmlRole { name: "photoAuthor"; query: "author/string()" }
+ XmlRole { name: "photoDate"; query: "pubDate/string()" }
},
Component {
diff --git a/demos/declarative/flickr/flickr2.qml b/demos/declarative/flickr/flickr2.qml
index 947bf9e..d6d5c95 100644
--- a/demos/declarative/flickr/flickr2.qml
+++ b/demos/declarative/flickr/flickr2.qml
@@ -12,19 +12,19 @@ Item {
id: FeedModel
property string tags : TagsEdit.text
source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+tags+"&" : "")+"format=rss2"
- query: "doc($src)/rss/channel/item"
+ query: "/rss/channel/item"
namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";"
- Role { name: "title"; query: "title/string()" }
- Role { name: "imagePath"; query: "media:thumbnail/@url/string()" }
- Role { name: "url"; query: "media:content/@url/string()" }
- Role { name: "description"; query: "description/string()" }
- Role { name: "tags"; query: "media:category/string()" }
- Role { name: "photoWidth"; query: "media:content/@width/string()" }
- Role { name: "photoHeight"; query: "media:content/@height/string()" }
- Role { name: "photoType"; query: "media:content/@type/string()" }
- Role { name: "photoAuthor"; query: "author/string()" }
- Role { name: "photoDate"; query: "pubDate/string()" }
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "imagePath"; query: "media:thumbnail/@url/string()" }
+ XmlRole { name: "url"; query: "media:content/@url/string()" }
+ XmlRole { name: "description"; query: "description/string()" }
+ XmlRole { name: "tags"; query: "media:category/string()" }
+ XmlRole { name: "photoWidth"; query: "media:content/@width/string()" }
+ XmlRole { name: "photoHeight"; query: "media:content/@height/string()" }
+ XmlRole { name: "photoType"; query: "media:content/@type/string()" }
+ XmlRole { name: "photoAuthor"; query: "author/string()" }
+ XmlRole { name: "photoDate"; query: "pubDate/string()" }
}
delegate: Package {
diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc
index 9edb087..63566f6 100644
--- a/doc/src/declarative/elements.qdoc
+++ b/doc/src/declarative/elements.qdoc
@@ -42,7 +42,7 @@ The following table lists the Qml elements provided by the Qt Declarative module
\list
\o \l Bind
\o \l ListModel
-\o \l XmlListModel
+\o \l XmlListModel and XmlRole
\o \l SqlQuery, \l SqlConnection, and \l SqlBind
\o \l DateTimeFormatter
\o \l NumberFormatter
diff --git a/examples/declarative/flowview/flickr.qml b/examples/declarative/flowview/flickr.qml
index fa8233b..2742839 100644
--- a/examples/declarative/flowview/flickr.qml
+++ b/examples/declarative/flowview/flickr.qml
@@ -8,19 +8,19 @@ Rect {
XmlListModel {
id: FeedModel
source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2"
- query: "doc($src)/rss/channel/item"
+ query: "/rss/channel/item"
namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";"
- Role { name: "title"; query: "title/string()" }
- Role { name: "imagePath"; query: "media:thumbnail/@url/string()" }
- Role { name: "url"; query: "media:content/@url/string()" }
- Role { name: "description"; query: "description/string()" }
- Role { name: "tags"; query: "media:category/string()" }
- Role { name: "photoWidth"; query: "media:content/@width/string()" }
- Role { name: "photoHeight"; query: "media:content/@height/string()" }
- Role { name: "photoType"; query: "media:content/@type/string()" }
- Role { name: "photoAuthor"; query: "author/string()" }
- Role { name: "photoDate"; query: "pubDate/string()" }
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "imagePath"; query: "media:thumbnail/@url/string()" }
+ XmlRole { name: "url"; query: "media:content/@url/string()" }
+ XmlRole { name: "description"; query: "description/string()" }
+ XmlRole { name: "tags"; query: "media:category/string()" }
+ XmlRole { name: "photoWidth"; query: "media:content/@width/string()" }
+ XmlRole { name: "photoHeight"; query: "media:content/@height/string()" }
+ XmlRole { name: "photoType"; query: "media:content/@type/string()" }
+ XmlRole { name: "photoAuthor"; query: "author/string()" }
+ XmlRole { name: "photoDate"; query: "pubDate/string()" }
}
ListView {
diff --git a/examples/declarative/xmldata/daringfireball.qml b/examples/declarative/xmldata/daringfireball.qml
index b14dfbf..6f3461e 100644
--- a/examples/declarative/xmldata/daringfireball.qml
+++ b/examples/declarative/xmldata/daringfireball.qml
@@ -6,17 +6,17 @@ Rect {
XmlListModel {
id: feedModel
source: "http://daringfireball.net/index.xml"
- query: "doc($src)/feed/entry"
+ query: "/feed/entry"
namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';"
- Role {
+ XmlRole {
name: "title"
query: "title/string()"
}
- Role {
+ XmlRole {
name: "tagline"
query: "author/name/string()"
}
- Role {
+ XmlRole {
name: "content"
query: "content/string()"
}
diff --git a/examples/declarative/xmldata/yahoonews.qml b/examples/declarative/xmldata/yahoonews.qml
index d20da99..9d0c956 100644
--- a/examples/declarative/xmldata/yahoonews.qml
+++ b/examples/declarative/xmldata/yahoonews.qml
@@ -9,16 +9,16 @@ Rect {
XmlListModel {
id: feedModel
source: "http://rss.news.yahoo.com/rss/oceania"
- query: "doc($src)/rss/channel/item"
- Role {
+ query: "/rss/channel/item"
+ XmlRole {
name: "title"
query: "title/string()"
}
- Role {
+ XmlRole {
name: "link"
query: "link/string()"
}
- Role {
+ XmlRole {
name: "description"
query: "description/string()"
}
diff --git a/src/declarative/extra/qmlxmllistmodel.cpp b/src/declarative/extra/qmlxmllistmodel.cpp
index 51905fa..082c9c2 100644
--- a/src/declarative/extra/qmlxmllistmodel.cpp
+++ b/src/declarative/extra/qmlxmllistmodel.cpp
@@ -58,7 +58,7 @@
QT_BEGIN_NAMESPACE
-QML_DEFINE_TYPE(XmlListModelRole, Role)
+QML_DEFINE_TYPE(XmlListModelRole, XmlRole)
QML_DEFINE_TYPE(QmlXmlListModel, XmlListModel)
@@ -105,7 +105,7 @@ public:
m_modelData.clear();
m_size = 0;
m_data = data;
- m_query = query;
+ m_query = QLatin1String("doc($src)") + query;
m_namespaces = namespaces;
m_roleObjects = roleObjects;
if (!isRunning()) {
@@ -224,6 +224,13 @@ void QmlXmlQuery::doSubQueryJob()
//### we might be able to condense even further (query for everything in one go)
for (int i = 0; i < m_roleObjects->size(); ++i) {
XmlListModelRole *role = m_roleObjects->at(i);
+ if (!role->isValid()) {
+ QList<QVariant> resultList;
+ for (int j = 0; j < m_size; ++j)
+ resultList << QVariant();
+ m_modelData << resultList;
+ continue;
+ }
subquery.setQuery(m_prefix + QLatin1String("(let $v := ") + role->query() + QLatin1String(" return if ($v) then ") + role->query() + QLatin1String(" else \"\")"));
QXmlResultItems output3;
subquery.evaluateTo(&output3);
@@ -233,6 +240,9 @@ void QmlXmlQuery::doSubQueryJob()
resultList << item.toAtomicValue(); //### we used to trim strings
item = output3.next();
}
+ //### should warn here if things have gone wrong.
+ while (resultList.count() < m_size)
+ resultList << QVariant();
m_modelData << resultList;
b.seek(0);
}
@@ -308,6 +318,38 @@ void QmlXmlRoleList::append(XmlListModelRole *role) {
model->roleNames << role->name();
++model->highestRole;
}
+
+/*!
+ \qmlclass XmlRole
+ \brief The XmlRole element allows you to specify a role for an XmlListModel.
+*/
+
+/*!
+ \qmlproperty string XmlRole::name
+ The name for the role. This name is used to access the model data for this role from Qml.
+
+ \qml
+ XmlRole { name: "title"; query: "title/string()" }
+
+ ...
+
+ Component {
+ id: Delegate
+ Text { text: title }
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty string XmlRole::query
+ The relative XPath query for this role. The query should not start with a '/' (i.e. it must be
+ relative).
+
+ \qml
+ XmlRole { name: "title"; query: "title/string()" }
+ \endqml
+*/
+
//XXX clear, removeAt, and insert need to invalidate any cached data (in data table) as well
// (and the model should emit the appropriate signals)
void QmlXmlRoleList::clear()
@@ -316,12 +358,15 @@ void QmlXmlRoleList::clear()
model->roleNames.clear();
QmlConcreteList<XmlListModelRole *>::clear();
}
+
void QmlXmlRoleList::removeAt(int i)
{
model->roles.removeAt(i);
model->roleNames.removeAt(i);
QmlConcreteList<XmlListModelRole *>::removeAt(i);
}
+
+//### we should enforce unique role names
void QmlXmlRoleList::insert(int i, XmlListModelRole *role)
{
QmlConcreteList<XmlListModelRole *>::insert(i, role);
@@ -332,7 +377,7 @@ void QmlXmlRoleList::insert(int i, XmlListModelRole *role)
/*!
\qmlclass XmlListModel
- \brief The XmlListModel class allows you to specify a model using XQuery.
+ \brief The XmlListModel element allows you to specify a model using XPath expressions.
XmlListModel allows you to construct a model from XML data that can then be used as a data source
for the view classes (ListView, PathView, GridView) and any other classes that interact with model
@@ -343,13 +388,14 @@ void QmlXmlRoleList::insert(int i, XmlListModelRole *role)
XmlListModel {
id: FeedModel
source: "http://rss.news.yahoo.com/rss/oceania"
- query: "doc($src)/rss/channel/item"
- Role { name: "title"; query: "title/string()" }
- Role { name: "link"; query: "link/string()" }
- Role { name: "description"; query: "description/string()" }
+ query: "/rss/channel/item"
+ XmlRole { name: "title"; query: "title/string()" }
+ XmlRole { name: "link"; query: "link/string()" }
+ XmlRole { name: "description"; query: "description/string()" }
}
\endqml
- \note The model is currently static, so the above is really just a snapshot of an RSS feed.
+ \note The model is currently static, so the above is really just a snapshot of an RSS feed. To force a
+ reload of the entire model, you can call the reload function.
*/
QmlXmlListModel::QmlXmlListModel(QObject *parent)
@@ -364,6 +410,11 @@ QmlXmlListModel::~QmlXmlListModel()
{
}
+/*!
+ \qmlproperty list<XmlRole> QmlListModel::roles
+
+ The roles to make available for this model.
+*/
QmlList<XmlListModelRole *> *QmlXmlListModel::roleObjects()
{
Q_D(QmlXmlListModel);
@@ -403,6 +454,10 @@ QString QmlXmlListModel::toString(int role) const
return d->roleNames.at(index);
}
+/*!
+ \qmlproperty url XmlListModel::source
+ The location of the XML data source.
+*/
QUrl QmlXmlListModel::source() const
{
Q_D(const QmlXmlListModel);
@@ -418,6 +473,11 @@ void QmlXmlListModel::setSource(const QUrl &src)
}
}
+/*!
+ \qmlproperty url XmlListModel::query
+ An absolute XPath query representing the base query for the model items. The query should start with
+ a '/' or '//'.
+*/
QString QmlXmlListModel::query() const
{
Q_D(const QmlXmlListModel);
@@ -427,12 +487,21 @@ QString QmlXmlListModel::query() const
void QmlXmlListModel::setQuery(const QString &query)
{
Q_D(QmlXmlListModel);
+ if (!query.startsWith(QLatin1Char('/'))) {
+ qmlInfo(this) << "An XmlListModel query must start with '/' or \"//\"";
+ return;
+ }
+
if (d->query != query) {
d->query = query;
reload();
}
}
+/*!
+ \qmlproperty string XmlListModel::namespaceDeclarations
+ A set of declarations for the namespaces used in the query.
+*/
QString QmlXmlListModel::namespaceDeclarations() const
{
Q_D(const QmlXmlListModel);
@@ -447,12 +516,34 @@ void QmlXmlListModel::setNamespaceDeclarations(const QString &declarations)
reload();
}
}
+
+/*!
+ \qmlproperty enum XmlListModel::status
+
+ This property holds the status of data source loading. It can be one of:
+ \list
+ \o Idle - no data source has been set, or the data source has been loaded
+ \o Loading - the data source is currently being loaded
+ \o Error - an error occurred while loading the data source
+ \endlist
+
+ \sa progress
+
+*/
QmlXmlListModel::Status QmlXmlListModel::status() const
{
Q_D(const QmlXmlListModel);
return d->status;
}
+/*!
+ \qmlproperty real XmlListModel::progress
+
+ This property holds the progress of data source loading, from 0.0 (nothing loaded)
+ to 1.0 (finished).
+
+ \sa status
+*/
qreal QmlXmlListModel::progress() const
{
Q_D(const QmlXmlListModel);
@@ -466,6 +557,12 @@ void QmlXmlListModel::classComplete()
reload();
}
+/*!
+ \qmlmethod XmlListModel::reload()
+
+ Reloads the model. All the existing model data will be removed, and the model
+ will be rebuilt from scratch.
+*/
void QmlXmlListModel::reload()
{
Q_D(QmlXmlListModel);
@@ -484,7 +581,7 @@ void QmlXmlListModel::reload()
emit itemsRemoved(0, count);
if (d->src.isEmpty()) {
- qWarning() << "Can't load empty src string";
+ qmlInfo(this) << "Can't load empty src string";
return;
}
diff --git a/src/declarative/extra/qmlxmllistmodel.h b/src/declarative/extra/qmlxmllistmodel.h
index c6aae4a..0d41456 100644
--- a/src/declarative/extra/qmlxmllistmodel.h
+++ b/src/declarative/extra/qmlxmllistmodel.h
@@ -44,6 +44,7 @@
#include <QtDeclarative/qml.h>
#include <QtDeclarative/QListModelInterface>
+#include <QtDeclarative/qmlinfo.h>
QT_BEGIN_HEADER
@@ -66,7 +67,18 @@ public:
void setName(const QString &name) { m_name = name; }
QString query() const { return m_query; }
- void setQuery(const QString &query) { m_query = query; }
+ void setQuery(const QString &query)
+ {
+ if (query.startsWith(QLatin1Char('/'))) {
+ qmlInfo(this) << "An XmlRole query must not start with '/'";
+ return;
+ }
+ m_query = query;
+ }
+
+ bool isValid() {
+ return !m_name.isEmpty() && !m_query.isEmpty();
+ }
private:
QString m_name;
@@ -88,6 +100,7 @@ class Q_DECLARATIVE_EXPORT QmlXmlListModel : public QListModelInterface, public
Q_PROPERTY(QString namespaceDeclarations READ namespaceDeclarations WRITE setNamespaceDeclarations)
Q_PROPERTY(QmlList<XmlListModelRole *> *roles READ roleObjects)
Q_CLASSINFO("DefaultProperty", "roles")
+
public:
QmlXmlListModel(QObject *parent = 0);
~QmlXmlListModel();