diff -r 5dc02b23752f -r 3e2da88830cd src/declarative/util/qdeclarativexmllistmodel.cpp --- a/src/declarative/util/qdeclarativexmllistmodel.cpp Tue Jul 06 15:10:48 2010 +0300 +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp Wed Aug 18 10:37:55 2010 +0300 @@ -80,7 +80,11 @@ /*! \qmlproperty string XmlRole::name - The name for the role. This name is used to access the model data for this role from Qml. + + The name for the role. This name is used to access the model data for this role. + + For example, the following model has a role named "title", which can be accessed + from the view's delegate: \qml XmlListModel { @@ -91,19 +95,27 @@ ListView { model: xmlModel - Text { text: title } + 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). + The relative XPath expression query for this role. The query must be relative; it cannot start + with a '/'. + + For example, if there is an XML document like this: - \qml - XmlRole { name: "title"; query: "title/string()" } - \endqml + \quotefile doc/src/snippets/declarative/xmlrole.xml + + Here are some valid XPath expressions for XmlRole queries on this document: + + \snippet doc/src/snippets/declarative/xmlrole.qml 0 + \dots 4 + \snippet doc/src/snippets/declarative/xmlrole.qml 1 + + See the \l{http://www.w3.org/TR/xpath20/}{W3C XPath 2.0 specification} for more information. */ /*! @@ -136,6 +148,7 @@ QDeclarativeXmlQuery(QObject *parent=0) : QThread(parent), m_quit(false), m_abortQueryId(-1), m_queryIds(XMLLISTMODEL_CLEAR_ID + 1) { qRegisterMetaType("QDeclarativeXmlQueryResult"); + m_currentJob.queryId = -1; } ~QDeclarativeXmlQuery() { @@ -149,6 +162,13 @@ void abort(int id) { QMutexLocker locker(&m_mutex); + QQueue::iterator it; + for (it = m_jobs.begin(); it != m_jobs.end(); ++it) { + if ((*it).queryId == id) { + m_jobs.erase(it); + return; + } + } m_abortQueryId = id; } @@ -176,7 +196,7 @@ m_queryIds++; if (!isRunning()) - start(); + start(QThread::IdlePriority); else m_condition.wakeOne(); return job.queryId; @@ -190,24 +210,28 @@ void run() { while (!m_quit) { m_mutex.lock(); - doQueryJob(); - doSubQueryJob(); + if (!m_jobs.isEmpty()) + m_currentJob = m_jobs.dequeue(); m_mutex.unlock(); - m_mutex.lock(); - const XmlQueryJob &job = m_jobs.dequeue(); - if (m_abortQueryId != job.queryId) { - QDeclarativeXmlQueryResult r; - r.queryId = job.queryId; + QDeclarativeXmlQueryResult r; + if (m_currentJob.queryId != -1) { + doQueryJob(); + doSubQueryJob(); + r.queryId = m_currentJob.queryId; r.size = m_size; r.data = m_modelData; r.inserted = m_insertedItemRanges; r.removed = m_removedItemRanges; - r.keyRoleResultsCache = job.keyRoleResultsCache; + r.keyRoleResultsCache = m_currentJob.keyRoleResultsCache; + } + + m_mutex.lock(); + if (m_currentJob.queryId != -1 && m_abortQueryId != m_currentJob.queryId) emit queryCompleted(r); - } if (m_jobs.isEmpty()) m_condition.wait(&m_mutex); + m_currentJob.queryId = -1; m_abortQueryId = -1; m_mutex.unlock(); } @@ -223,6 +247,7 @@ QMutex m_mutex; QWaitCondition m_condition; QQueue m_jobs; + XmlQueryJob m_currentJob; bool m_quit; int m_abortQueryId; QString m_prefix; @@ -237,15 +262,14 @@ void QDeclarativeXmlQuery::doQueryJob() { - Q_ASSERT(!m_jobs.isEmpty()); - XmlQueryJob &job = m_jobs.head(); + Q_ASSERT(m_currentJob.queryId != -1); QString r; QXmlQuery query; - QBuffer buffer(&job.data); + QBuffer buffer(&m_currentJob.data); buffer.open(QIODevice::ReadOnly); query.bindVariable(QLatin1String("src"), &buffer); - query.setQuery(job.namespaces + job.query); + query.setQuery(m_currentJob.namespaces + m_currentJob.query); query.evaluateTo(&r); //always need a single root element @@ -253,9 +277,9 @@ QBuffer b(&xml); b.open(QIODevice::ReadOnly); - QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + job.namespaces; + QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + m_currentJob.namespaces; QString prefix = QLatin1String("doc($inputDocument)/dummy:items") + - job.query.mid(job.query.lastIndexOf(QLatin1Char('/'))); + m_currentJob.query.mid(m_currentJob.query.lastIndexOf(QLatin1Char('/'))); //figure out how many items we are dealing with int count = -1; @@ -270,7 +294,7 @@ count = item.toAtomicValue().toInt(); } - job.data = xml; + m_currentJob.data = xml; m_prefix = namespaces + prefix + QLatin1Char('/'); m_size = 0; if (count > 0) @@ -279,9 +303,9 @@ void QDeclarativeXmlQuery::getValuesOfKeyRoles(QStringList *values, QXmlQuery *query) const { - Q_ASSERT(!m_jobs.isEmpty()); + Q_ASSERT(m_currentJob.queryId != -1); - const QStringList &keysQueries = m_jobs.head().keyRoleQueries; + const QStringList &keysQueries = m_currentJob.keyRoleQueries; QString keysQuery; if (keysQueries.count() == 1) keysQuery = m_prefix + keysQueries[0]; @@ -311,11 +335,10 @@ void QDeclarativeXmlQuery::doSubQueryJob() { - Q_ASSERT(!m_jobs.isEmpty()); - XmlQueryJob &job = m_jobs.head(); + Q_ASSERT(m_currentJob.queryId != -1); m_modelData.clear(); - QBuffer b(&job.data); + QBuffer b(&m_currentJob.data); b.open(QIODevice::ReadOnly); QXmlQuery subquery; @@ -328,16 +351,16 @@ m_insertedItemRanges.clear(); m_removedItemRanges.clear(); - if (job.keyRoleResultsCache.isEmpty()) { + if (m_currentJob.keyRoleResultsCache.isEmpty()) { m_insertedItemRanges << qMakePair(0, m_size); } else { - if (keyRoleResults != job.keyRoleResultsCache) { + if (keyRoleResults != m_currentJob.keyRoleResultsCache) { QStringList temp; - for (int i=0; i resultList; if (!queries[i].isEmpty()) { @@ -366,7 +389,7 @@ item = resultItems.next(); } } else { - emit error(job.roleQueryErrorId.at(i), queries[i]); + emit error(m_currentJob.roleQueryErrorId.at(i), queries[i]); } } //### should warn here if things have gone wrong. @@ -485,8 +508,8 @@ \since 4.7 \brief The XmlListModel element is used to specify a model using XPath expressions. - XmlListModel is used to create a model from XML data. XmlListModel can be used as a data source - for the view classes (such as ListView, PathView, GridView) and other classes that interact with model + XmlListModel is used to create a model from XML data. It can be used as a data source + for view elements (such as ListView, PathView, GridView) and other elements that interact with model data (such as \l Repeater). For example, if there is a XML document at http://www.mysite.com/feed.xml like this: @@ -497,11 +520,11 @@ ... - Item A + A blog post Sat, 07 Sep 2010 10:00:01 GMT - Item B + Another blog post Sat, 07 Sep 2010 15:35:01 GMT @@ -511,19 +534,25 @@ A XmlListModel could create a model from this data, like this: \qml + import Qt 4.7 + XmlListModel { id: xmlModel source: "http://www.mysite.com/feed.xml" query: "/rss/channel/item" + XmlRole { name: "title"; query: "title/string()" } XmlRole { name: "pubDate"; query: "pubDate/string()" } } \endqml The \l {XmlListModel::query}{query} value of "/rss/channel/item" specifies that the XmlListModel should generate - a model item for each \c in the XML document. The XmlRole objects define the - model item attributes; here, each model item will have \c title and \c pubDate + a model item for each \c in the XML document. + + The XmlRole objects define the + model item attributes. Here, each model item will have \c title and \c pubDate attributes that match the \c title and \c pubDate values of its corresponding \c . + (See \l XmlRole::query for more examples of valid XPath expressions for XmlRole.) The model could be used in a ListView, like this: @@ -531,10 +560,17 @@ ListView { width: 180; height: 300 model: xmlModel - delegate: Text { title + " (" + pubDate + ")" } + delegate: Text { text: title + " (" + pubDate + ")" } } \endqml + \image qml-xmllistmodel-example.png + + The XmlListModel data is loaded asynchronously, and \l status + is set to \c XmlListModel.Ready when loading is complete. + Note this means when XmlListModel is used for a view, the view is not + populated until the model is loaded. + \section2 Using key XML roles @@ -560,7 +596,7 @@ with a combined value of all key roles that is not already present in the model. - \sa {declarative/xml/xmldata}{XML data example} + \sa {RSS News} */ QDeclarativeXmlListModel::QDeclarativeXmlListModel(QObject *parent) @@ -638,7 +674,7 @@ \qmlproperty url XmlListModel::source The location of the XML data source. - If both source and xml are set, xml will be used. + If both \c source and \l xml are set, \l xml is used. */ QUrl QDeclarativeXmlListModel::source() const { @@ -659,11 +695,11 @@ /*! \qmlproperty string XmlListModel::xml - This property holds XML text set directly. + This property holds the XML data for this model, if set. The text is assumed to be UTF-8 encoded. - If both source and xml are set, xml will be used. + If both \l source and \c xml are set, \c xml is used. */ QString QDeclarativeXmlListModel::xml() const { @@ -720,6 +756,7 @@ source: "http://mysite.com/feed.xml" query: "/feed/entry" namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';" + XmlRole { name: "title"; query: "title/string()" } } \endqml