diff options
author | Frederik Gladhorn <frederik.gladhorn@qt.io> | 2018-06-16 11:40:05 +0200 |
---|---|---|
committer | Jani Heikkinen <jani.heikkinen@qt.io> | 2018-11-05 12:48:48 +0000 |
commit | 0477a057fd02050fd330760bf046f5e0e91a9331 (patch) | |
tree | 159df846e849db8ef6a91f53f29c399dd6fde63f | |
parent | 627226520a2bbb977ce32a21bdffd2004cb28796 (diff) |
32 files changed, 4 insertions, 3079 deletions
diff --git a/src/imports/imports.pro b/src/imports/imports.pro index cf49deb03c..24e93fec1c 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -28,4 +28,3 @@ qtHaveModule(quick) { qtConfig(quick-path):qtConfig(thread): SUBDIRS += shapes } -qtHaveModule(xmlpatterns) : SUBDIRS += xmllistmodel diff --git a/src/imports/xmllistmodel/plugin.cpp b/src/imports/xmllistmodel/plugin.cpp deleted file mode 100644 index c5356b8534..0000000000 --- a/src/imports/xmllistmodel/plugin.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtQml/qqmlextensionplugin.h> -#include <QtQml/qqml.h> - -#include "qqmlxmllistmodel_p.h" - -QT_BEGIN_NAMESPACE - -class QmlXmlListModelPlugin : public QQmlExtensionPlugin -{ - Q_OBJECT - Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) - -public: - QmlXmlListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { } - void registerTypes(const char *uri) override - { - Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.XmlListModel")); - qmlRegisterType<QQuickXmlListModel>(uri,2,0,"XmlListModel"); - qmlRegisterType<QQuickXmlListModelRole>(uri,2,0,"XmlRole"); - - // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward - qmlRegisterModule(uri, 2, QT_VERSION_MINOR); - } -}; - -QT_END_NAMESPACE - -#include "plugin.moc" diff --git a/src/imports/xmllistmodel/plugins.qmltypes b/src/imports/xmllistmodel/plugins.qmltypes deleted file mode 100644 index 951d0b6eeb..0000000000 --- a/src/imports/xmllistmodel/plugins.qmltypes +++ /dev/null @@ -1,59 +0,0 @@ -import QtQuick.tooling 1.2 - -// This file describes the plugin-supplied types contained in the library. -// It is used for QML tooling purposes only. -// -// This file was auto-generated by: -// 'qmlplugindump -nonrelocatable QtQuick.XmlListModel 2.12' - -Module { - dependencies: ["QtQuick 2.12"] - Component { - name: "QQuickXmlListModel" - defaultProperty: "roles" - prototype: "QAbstractListModel" - exports: ["QtQuick.XmlListModel/XmlListModel 2.0"] - exportMetaObjectRevisions: [0] - Enum { - name: "Status" - values: { - "Null": 0, - "Ready": 1, - "Loading": 2, - "Error": 3 - } - } - Property { name: "status"; type: "Status"; isReadonly: true } - Property { name: "progress"; type: "double"; isReadonly: true } - Property { name: "source"; type: "QUrl" } - Property { name: "xml"; type: "string" } - Property { name: "query"; type: "string" } - Property { name: "namespaceDeclarations"; type: "string" } - Property { name: "roles"; type: "QQuickXmlListModelRole"; isList: true; isReadonly: true } - Property { name: "count"; type: "int"; isReadonly: true } - Signal { - name: "statusChanged" - Parameter { type: "QQuickXmlListModel::Status" } - } - Signal { - name: "progressChanged" - Parameter { name: "progress"; type: "double" } - } - Method { name: "reload" } - Method { - name: "get" - type: "QQmlV4Handle" - Parameter { name: "index"; type: "int" } - } - Method { name: "errorString"; type: "string" } - } - Component { - name: "QQuickXmlListModelRole" - prototype: "QObject" - exports: ["QtQuick.XmlListModel/XmlRole 2.0"] - exportMetaObjectRevisions: [0] - Property { name: "name"; type: "string" } - Property { name: "query"; type: "string" } - Property { name: "isKey"; type: "bool" } - } -} diff --git a/src/imports/xmllistmodel/qmldir b/src/imports/xmllistmodel/qmldir deleted file mode 100644 index 1f17dbb112..0000000000 --- a/src/imports/xmllistmodel/qmldir +++ /dev/null @@ -1,5 +0,0 @@ -module QtQuick.XmlListModel -plugin qmlxmllistmodelplugin -classname QmlXmlListModelPlugin -typeinfo plugins.qmltypes -designersupported diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp deleted file mode 100644 index 470b419c1f..0000000000 --- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp +++ /dev/null @@ -1,1238 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qqmlxmllistmodel_p.h" - -#include <qqmlcontext.h> -#include <private/qqmlengine_p.h> -#include <private/qv8engine_p.h> -#include <private/qv4value_p.h> -#include <private/qv4engine_p.h> -#include <private/qv4object_p.h> - -#include <QDebug> -#include <QStringList> -#include <QMap> -#include <QThread> -#include <QXmlQuery> -#include <QXmlResultItems> -#include <QXmlNodeModelIndex> -#include <QBuffer> -#if QT_CONFIG(qml_network) -#include <QNetworkRequest> -#include <QNetworkReply> -#endif -#include <QTimer> -#include <QMutex> - -#include <private/qabstractitemmodel_p.h> - -Q_DECLARE_METATYPE(QQuickXmlQueryResult) - -QT_BEGIN_NAMESPACE - -using namespace QV4; - -typedef QPair<int, int> QQuickXmlListRange; - -#define XMLLISTMODEL_CLEAR_ID 0 - -/*! - \qmlmodule QtQuick.XmlListModel 2.\QtMinorVersion - \title Qt Quick XmlListModel QML Types - \ingroup qmlmodules - \brief Provides QML types for creating models from XML data - - This QML module contains types for creating models from XML data. - - To use the types in this module, import the module with the following line: - - \qml \QtMinorVersion - import QtQuick.XmlListModel 2.\1 - \endqml -*/ - -/*! - \qmltype XmlRole - \instantiates QQuickXmlListModelRole - \inqmlmodule QtQuick.XmlListModel - \brief For specifying a role to an XmlListModel. - \ingroup qtquick-models - - \sa {Qt QML} -*/ - -/*! - \qmlproperty string QtQuick.XmlListModel::XmlRole::name - - 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 { - id: xmlModel - // ... - XmlRole { - name: "title" - query: "title/string()" - } - } - \endqml - - \qml - ListView { - model: xmlModel - delegate: Text { text: title } - } - \endqml -*/ - -/*! - \qmlproperty string QtQuick.XmlListModel::XmlRole::query - 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: - - \quotefile qml/xmlrole.xml - Here are some valid XPath expressions for XmlRole queries on this document: - - \snippet qml/xmlrole.qml 0 - \dots 4 - \snippet qml/xmlrole.qml 1 - - Accessing the model data for the above roles from a delegate: - - \snippet qml/xmlrole.qml 2 - - See the \l{http://www.w3.org/TR/xpath20/}{W3C XPath 2.0 specification} for more information. -*/ - -/*! - \qmlproperty bool QtQuick.XmlListModel::XmlRole::isKey - Defines whether this is a key role. - Key roles are used to determine whether a set of values should - be updated or added to the XML list model when XmlListModel::reload() - is called. - - \sa XmlListModel -*/ - -struct XmlQueryJob -{ - int queryId; - QByteArray data; - QString query; - QString namespaces; - QStringList roleQueries; - QList<void*> roleQueryErrorId; // the ptr to send back if there is an error - QStringList keyRoleQueries; - QStringList keyRoleResultsCache; - QString prefix; -}; - - -class QQuickXmlQueryEngine; -class QQuickXmlQueryThreadObject : public QObject -{ - Q_OBJECT -public: - QQuickXmlQueryThreadObject(QQuickXmlQueryEngine *); - - void processJobs(); - bool event(QEvent *e) override; - -private: - QQuickXmlQueryEngine *m_queryEngine; -}; - - -class QQuickXmlQueryEngine : public QThread -{ - Q_OBJECT -public: - QQuickXmlQueryEngine(QQmlEngine *eng); - ~QQuickXmlQueryEngine(); - - int doQuery(QString query, QString namespaces, QByteArray data, QList<QQuickXmlListModelRole *>* roleObjects, QStringList keyRoleResultsCache); - void abort(int id); - - void processJobs(); - - static QQuickXmlQueryEngine *instance(QQmlEngine *engine); - -signals: - void queryCompleted(const QQuickXmlQueryResult &); - void error(void*, const QString&); - -protected: - void run() override; - -private: - void processQuery(XmlQueryJob *job); - void doQueryJob(XmlQueryJob *job, QQuickXmlQueryResult *currentResult); - void doSubQueryJob(XmlQueryJob *job, QQuickXmlQueryResult *currentResult); - void getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const; - void addIndexToRangeList(QList<QQuickXmlListRange> *ranges, int index) const; - - QMutex m_mutex; - QQuickXmlQueryThreadObject *m_threadObject; - QList<XmlQueryJob> m_jobs; - QSet<int> m_cancelledJobs; - QAtomicInt m_queryIds; - - QQmlEngine *m_engine; - QObject *m_eventLoopQuitHack; - - static QHash<QQmlEngine *,QQuickXmlQueryEngine*> queryEngines; - static QMutex queryEnginesMutex; -}; -QHash<QQmlEngine *,QQuickXmlQueryEngine*> QQuickXmlQueryEngine::queryEngines; -QMutex QQuickXmlQueryEngine::queryEnginesMutex; - - -QQuickXmlQueryThreadObject::QQuickXmlQueryThreadObject(QQuickXmlQueryEngine *e) - : m_queryEngine(e) -{ -} - -void QQuickXmlQueryThreadObject::processJobs() -{ - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); -} - -bool QQuickXmlQueryThreadObject::event(QEvent *e) -{ - if (e->type() == QEvent::User) { - m_queryEngine->processJobs(); - return true; - } else { - return QObject::event(e); - } -} - - - -QQuickXmlQueryEngine::QQuickXmlQueryEngine(QQmlEngine *eng) -: QThread(eng), m_threadObject(0), m_queryIds(XMLLISTMODEL_CLEAR_ID + 1), m_engine(eng), m_eventLoopQuitHack(0) -{ - qRegisterMetaType<QQuickXmlQueryResult>("QQuickXmlQueryResult"); - - m_eventLoopQuitHack = new QObject; - m_eventLoopQuitHack->moveToThread(this); - connect(m_eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection); - start(QThread::IdlePriority); -} - -QQuickXmlQueryEngine::~QQuickXmlQueryEngine() -{ - queryEnginesMutex.lock(); - queryEngines.remove(m_engine); - queryEnginesMutex.unlock(); - - m_eventLoopQuitHack->deleteLater(); - wait(); -} - -int QQuickXmlQueryEngine::doQuery(QString query, QString namespaces, QByteArray data, QList<QQuickXmlListModelRole *>* roleObjects, QStringList keyRoleResultsCache) { - { - QMutexLocker m1(&m_mutex); - m_queryIds.ref(); - if (m_queryIds.load() <= 0) - m_queryIds.store(1); - } - - XmlQueryJob job; - job.queryId = m_queryIds.load(); - job.data = data; - job.query = QLatin1String("doc($src)") + query; - job.namespaces = namespaces; - job.keyRoleResultsCache = keyRoleResultsCache; - - for (int i=0; i<roleObjects->count(); i++) { - if (!roleObjects->at(i)->isValid()) { - job.roleQueries << QString(); - continue; - } - job.roleQueries << roleObjects->at(i)->query(); - job.roleQueryErrorId << static_cast<void*>(roleObjects->at(i)); - if (roleObjects->at(i)->isKey()) - job.keyRoleQueries << job.roleQueries.last(); - } - - { - QMutexLocker ml(&m_mutex); - m_jobs.append(job); - if (m_threadObject) - m_threadObject->processJobs(); - } - - return job.queryId; -} - -void QQuickXmlQueryEngine::abort(int id) -{ - QMutexLocker ml(&m_mutex); - if (id != -1) - m_cancelledJobs.insert(id); -} - -void QQuickXmlQueryEngine::run() -{ - m_mutex.lock(); - m_threadObject = new QQuickXmlQueryThreadObject(this); - m_mutex.unlock(); - - processJobs(); - exec(); - - delete m_threadObject; - m_threadObject = 0; -} - -void QQuickXmlQueryEngine::processJobs() -{ - QMutexLocker locker(&m_mutex); - - while (true) { - if (m_jobs.isEmpty()) - return; - - XmlQueryJob currentJob = m_jobs.takeLast(); - while (m_cancelledJobs.remove(currentJob.queryId)) { - if (m_jobs.isEmpty()) - return; - currentJob = m_jobs.takeLast(); - } - - locker.unlock(); - processQuery(¤tJob); - locker.relock(); - } -} - -QQuickXmlQueryEngine *QQuickXmlQueryEngine::instance(QQmlEngine *engine) -{ - queryEnginesMutex.lock(); - QQuickXmlQueryEngine *queryEng = queryEngines.value(engine); - if (!queryEng) { - queryEng = new QQuickXmlQueryEngine(engine); - queryEngines.insert(engine, queryEng); - } - queryEnginesMutex.unlock(); - - return queryEng; -} - -void QQuickXmlQueryEngine::processQuery(XmlQueryJob *job) -{ - QQuickXmlQueryResult result; - result.queryId = job->queryId; - doQueryJob(job, &result); - doSubQueryJob(job, &result); - - { - QMutexLocker ml(&m_mutex); - if (m_cancelledJobs.contains(job->queryId)) { - m_cancelledJobs.remove(job->queryId); - } else { - emit queryCompleted(result); - } - } -} - -void QQuickXmlQueryEngine::doQueryJob(XmlQueryJob *currentJob, QQuickXmlQueryResult *currentResult) -{ - Q_ASSERT(currentJob->queryId != -1); - - QString r; - QXmlQuery query; - QBuffer buffer(¤tJob->data); - buffer.open(QIODevice::ReadOnly); - query.bindVariable(QLatin1String("src"), &buffer); - query.setQuery(currentJob->namespaces + currentJob->query); - query.evaluateTo(&r); - - //always need a single root element - QByteArray xml = "<dummy:items xmlns:dummy=\"http://qtsotware.com/dummy\">\n" + r.toUtf8() + "</dummy:items>"; - QBuffer b(&xml); - b.open(QIODevice::ReadOnly); - - QString namespaces = QLatin1String("declare namespace dummy=\"http://qtsotware.com/dummy\";\n") + currentJob->namespaces; - QString prefix = QLatin1String("doc($inputDocument)/dummy:items/*"); - - //figure out how many items we are dealing with - int count = -1; - { - QXmlResultItems result; - QXmlQuery countquery; - countquery.bindVariable(QLatin1String("inputDocument"), &b); - countquery.setQuery(namespaces + QLatin1String("count(") + prefix + QLatin1Char(')')); - countquery.evaluateTo(&result); - QXmlItem item(result.next()); - if (item.isAtomicValue()) - count = item.toAtomicValue().toInt(); - } - - currentJob->data = xml; - currentJob->prefix = namespaces + prefix + QLatin1Char('/'); - currentResult->size = (count > 0 ? count : 0); -} - -void QQuickXmlQueryEngine::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const -{ - const QStringList &keysQueries = currentJob.keyRoleQueries; - QString keysQuery; - if (keysQueries.count() == 1) - keysQuery = currentJob.prefix + keysQueries[0]; - else if (keysQueries.count() > 1) - keysQuery = currentJob.prefix + QLatin1String("concat(") + keysQueries.join(QLatin1Char(',')) + QLatin1Char(')'); - - if (!keysQuery.isEmpty()) { - query->setQuery(keysQuery); - QXmlResultItems resultItems; - query->evaluateTo(&resultItems); - QXmlItem item(resultItems.next()); - while (!item.isNull()) { - values->append(item.toAtomicValue().toString()); - item = resultItems.next(); - } - } -} - -void QQuickXmlQueryEngine::addIndexToRangeList(QList<QQuickXmlListRange> *ranges, int index) const { - if (ranges->isEmpty()) - ranges->append(qMakePair(index, 1)); - else if (ranges->last().first + ranges->last().second == index) - ranges->last().second += 1; - else - ranges->append(qMakePair(index, 1)); -} - -void QQuickXmlQueryEngine::doSubQueryJob(XmlQueryJob *currentJob, QQuickXmlQueryResult *currentResult) -{ - Q_ASSERT(currentJob->queryId != -1); - - QBuffer b(¤tJob->data); - b.open(QIODevice::ReadOnly); - - QXmlQuery subquery; - subquery.bindVariable(QLatin1String("inputDocument"), &b); - - QStringList keyRoleResults; - getValuesOfKeyRoles(*currentJob, &keyRoleResults, &subquery); - - // See if any values of key roles have been inserted or removed. - - if (currentJob->keyRoleResultsCache.isEmpty()) { - currentResult->inserted << qMakePair(0, currentResult->size); - } else { - if (keyRoleResults != currentJob->keyRoleResultsCache) { - QStringList temp; - for (int i=0; i<currentJob->keyRoleResultsCache.count(); i++) { - if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i])) - addIndexToRangeList(¤tResult->removed, i); - else - temp << currentJob->keyRoleResultsCache[i]; - } - for (int i=0; i<keyRoleResults.count(); i++) { - if (temp.count() == i || keyRoleResults[i] != temp[i]) { - temp.insert(i, keyRoleResults[i]); - addIndexToRangeList(¤tResult->inserted, i); - } - } - } - } - currentResult->keyRoleResultsCache = keyRoleResults; - - // Get the new values for each role. - //### we might be able to condense even further (query for everything in one go) - const QStringList &queries = currentJob->roleQueries; - for (int i = 0; i < queries.size(); ++i) { - QList<QVariant> resultList; - if (!queries[i].isEmpty()) { - subquery.setQuery(currentJob->prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); - if (subquery.isValid()) { - QXmlResultItems resultItems; - subquery.evaluateTo(&resultItems); - QXmlItem item(resultItems.next()); - while (!item.isNull()) { - resultList << item.toAtomicValue(); //### we used to trim strings - item = resultItems.next(); - } - } else { - emit error(currentJob->roleQueryErrorId.at(i), queries[i]); - } - } - //### should warn here if things have gone wrong. - while (resultList.count() < currentResult->size) - resultList << QVariant(); - currentResult->data << resultList; - b.seek(0); - } - - //this method is much slower, but works better for incremental loading - /*for (int j = 0; j < m_size; ++j) { - QList<QVariant> resultList; - for (int i = 0; i < m_roleObjects->size(); ++i) { - QQuickXmlListModelRole *role = m_roleObjects->at(i); - subquery.setQuery(m_prefix.arg(j+1) + role->query()); - if (role->isStringList()) { - QStringList data; - subquery.evaluateTo(&data); - resultList << QVariant(data); - //qDebug() << data; - } else { - QString s; - subquery.evaluateTo(&s); - if (role->isCData()) { - //un-escape - s.replace(QLatin1String("<"), QLatin1String("<")); - s.replace(QLatin1String(">"), QLatin1String(">")); - s.replace(QLatin1String("&"), QLatin1String("&")); - } - resultList << s.trimmed(); - //qDebug() << s; - } - b.seek(0); - } - m_modelData << resultList; - }*/ -} - -class QQuickXmlListModelPrivate : public QAbstractItemModelPrivate -{ - Q_DECLARE_PUBLIC(QQuickXmlListModel) -public: - QQuickXmlListModelPrivate() - : isComponentComplete(true), size(0), highestRole(Qt::UserRole) -#if QT_CONFIG(qml_network) - , reply(0) -#endif - , status(QQuickXmlListModel::Null), progress(0.0) - , queryId(-1), roleObjects(), redirectCount(0) {} - - - void notifyQueryStarted(bool remoteSource) { - Q_Q(QQuickXmlListModel); - progress = remoteSource ? 0.0 : 1.0; - status = QQuickXmlListModel::Loading; - errorString.clear(); - emit q->progressChanged(progress); - emit q->statusChanged(status); - } - -#if QT_CONFIG(qml_network) - void deleteReply() { - Q_Q(QQuickXmlListModel); - if (reply) { - QObject::disconnect(reply, 0, q, 0); - reply->deleteLater(); - reply = 0; - } - } -#endif - - bool isComponentComplete; - QUrl src; - QString xml; - QString query; - QString namespaces; - int size; - QList<int> roles; - QStringList roleNames; - int highestRole; - -#if QT_CONFIG(qml_network) - QNetworkReply *reply; -#endif - QQuickXmlListModel::Status status; - QString errorString; - qreal progress; - int queryId; - QStringList keyRoleResultsCache; - QList<QQuickXmlListModelRole *> roleObjects; - - static void append_role(QQmlListProperty<QQuickXmlListModelRole> *list, QQuickXmlListModelRole *role); - static void clear_role(QQmlListProperty<QQuickXmlListModelRole> *list); - QList<QList<QVariant> > data; - int redirectCount; -}; - - -void QQuickXmlListModelPrivate::append_role(QQmlListProperty<QQuickXmlListModelRole> *list, QQuickXmlListModelRole *role) -{ - QQuickXmlListModel *_this = qobject_cast<QQuickXmlListModel *>(list->object); - if (_this && role) { - int i = _this->d_func()->roleObjects.count(); - _this->d_func()->roleObjects.append(role); - if (_this->d_func()->roleNames.contains(role->name())) { - qmlWarning(role) << QQuickXmlListModel::tr("\"%1\" duplicates a previous role name and will be disabled.").arg(role->name()); - return; - } - _this->d_func()->roles.insert(i, _this->d_func()->highestRole); - _this->d_func()->roleNames.insert(i, role->name()); - ++_this->d_func()->highestRole; - } -} - -//### clear needs to invalidate any cached data (in data table) as well -// (and the model should emit the appropriate signals) -void QQuickXmlListModelPrivate::clear_role(QQmlListProperty<QQuickXmlListModelRole> *list) -{ - QQuickXmlListModel *_this = static_cast<QQuickXmlListModel *>(list->object); - _this->d_func()->roles.clear(); - _this->d_func()->roleNames.clear(); - _this->d_func()->roleObjects.clear(); -} - -/*! - \qmltype XmlListModel - \instantiates QQuickXmlListModel - \inqmlmodule QtQuick.XmlListModel - \brief For specifying a read-only model using XPath expressions. - \ingroup qtquick-models - - - To use this element, you will need to import the module with the following line: - \code - import QtQuick.XmlListModel 2.0 - \endcode - - XmlListModel is used to create a read-only 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: - - \code - <?xml version="1.0" encoding="utf-8"?> - <rss version="2.0"> - ... - <channel> - <item> - <title>A blog post</title> - <pubDate>Sat, 07 Sep 2010 10:00:01 GMT</pubDate> - </item> - <item> - <title>Another blog post</title> - <pubDate>Sat, 07 Sep 2010 15:35:01 GMT</pubDate> - </item> - </channel> - </rss> - \endcode - - A XmlListModel could create a model from this data, like this: - - \qml - import QtQuick 2.0 - import QtQuick.XmlListModel 2.0 - - 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 <item> 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 <item>. - (See \l XmlRole::query for more examples of valid XPath expressions for XmlRole.) - - The model could be used in a ListView, like this: - - \qml - ListView { - width: 180; height: 300 - model: xmlModel - 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 - - You can define certain roles as "keys" so that when reload() is called, - the model will only add and refresh data that contains new values for - these keys. - - For example, if above role for "pubDate" was defined like this instead: - - \qml - XmlRole { name: "pubDate"; query: "pubDate/string()"; isKey: true } - \endqml - - Then when reload() is called, the model will only add and reload - items with a "pubDate" value that is not already - present in the model. - - This is useful when displaying the contents of XML documents that - are incrementally updated (such as RSS feeds) to avoid repainting the - entire contents of a model in a view. - - If multiple key roles are specified, the model only adds and reload items - with a combined value of all key roles that is not already present in - the model. - - \sa {Qt Quick Demo - RSS News} -*/ - -QQuickXmlListModel::QQuickXmlListModel(QObject *parent) - : QAbstractListModel(*(new QQuickXmlListModelPrivate), parent) -{ -} - -QQuickXmlListModel::~QQuickXmlListModel() -{ -} - -/*! - \qmlproperty list<XmlRole> QtQuick.XmlListModel::XmlListModel::roles - - The roles to make available for this model. -*/ -QQmlListProperty<QQuickXmlListModelRole> QQuickXmlListModel::roleObjects() -{ - Q_D(QQuickXmlListModel); - QQmlListProperty<QQuickXmlListModelRole> list(this, d->roleObjects); - list.append = &QQuickXmlListModelPrivate::append_role; - list.clear = &QQuickXmlListModelPrivate::clear_role; - return list; -} - -QModelIndex QQuickXmlListModel::index(int row, int column, const QModelIndex &parent) const -{ - Q_D(const QQuickXmlListModel); - return !parent.isValid() && column == 0 && row >= 0 && row < d->size - ? createIndex(row, column) - : QModelIndex(); -} - -int QQuickXmlListModel::rowCount(const QModelIndex &parent) const -{ - Q_D(const QQuickXmlListModel); - return !parent.isValid() ? d->size : 0; -} - -QVariant QQuickXmlListModel::data(const QModelIndex &index, int role) const -{ - Q_D(const QQuickXmlListModel); - const int roleIndex = d->roles.indexOf(role); - return (roleIndex == -1 || !index.isValid()) - ? QVariant() - : d->data.value(roleIndex).value(index.row()); -} - -QHash<int, QByteArray> QQuickXmlListModel::roleNames() const -{ - Q_D(const QQuickXmlListModel); - QHash<int,QByteArray> roleNames; - for (int i = 0; i < d->roles.count(); ++i) - roleNames.insert(d->roles.at(i), d->roleNames.at(i).toUtf8()); - return roleNames; -} - -/*! - \qmlproperty int QtQuick.XmlListModel::XmlListModel::count - The number of data entries in the model. -*/ -int QQuickXmlListModel::count() const -{ - Q_D(const QQuickXmlListModel); - return d->size; -} - -/*! - \qmlproperty url QtQuick.XmlListModel::XmlListModel::source - The location of the XML data source. - - If both \c source and \l xml are set, \l xml is used. -*/ -QUrl QQuickXmlListModel::source() const -{ - Q_D(const QQuickXmlListModel); - return d->src; -} - -void QQuickXmlListModel::setSource(const QUrl &src) -{ - Q_D(QQuickXmlListModel); - if (d->src != src) { - d->src = src; - if (d->xml.isEmpty()) // src is only used if d->xml is not set - reload(); - emit sourceChanged(); - } -} - -/*! - \qmlproperty string QtQuick.XmlListModel::XmlListModel::xml - This property holds the XML data for this model, if set. - - The text is assumed to be UTF-8 encoded. - - If both \l source and \c xml are set, \c xml is used. -*/ -QString QQuickXmlListModel::xml() const -{ - Q_D(const QQuickXmlListModel); - return d->xml; -} - -void QQuickXmlListModel::setXml(const QString &xml) -{ - Q_D(QQuickXmlListModel); - if (d->xml != xml) { - d->xml = xml; - reload(); - emit xmlChanged(); - } -} - -/*! - \qmlproperty string QtQuick.XmlListModel::XmlListModel::query - An absolute XPath query representing the base query for creating model items - from this model's XmlRole objects. The query should start with '/' or '//'. -*/ -QString QQuickXmlListModel::query() const -{ - Q_D(const QQuickXmlListModel); - return d->query; -} - -void QQuickXmlListModel::setQuery(const QString &query) -{ - Q_D(QQuickXmlListModel); - if (!query.startsWith(QLatin1Char('/'))) { - qmlWarning(this) << QCoreApplication::translate("QQuickXmlRoleList", "An XmlListModel query must start with '/' or \"//\""); - return; - } - - if (d->query != query) { - d->query = query; - reload(); - emit queryChanged(); - } -} - -/*! - \qmlproperty string QtQuick.XmlListModel::XmlListModel::namespaceDeclarations - The namespace declarations to be used in the XPath queries. - - The namespaces should be declared as in XQuery. For example, if a requested document - at http://mysite.com/feed.xml uses the namespace "http://www.w3.org/2005/Atom", - this can be declared as the default namespace: - - \qml - XmlListModel { - 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 -*/ -QString QQuickXmlListModel::namespaceDeclarations() const -{ - Q_D(const QQuickXmlListModel); - return d->namespaces; -} - -void QQuickXmlListModel::setNamespaceDeclarations(const QString &declarations) -{ - Q_D(QQuickXmlListModel); - if (d->namespaces != declarations) { - d->namespaces = declarations; - reload(); - emit namespaceDeclarationsChanged(); - } -} - -/*! - \qmlmethod object QtQuick.XmlListModel::XmlListModel::get(int index) - - Returns the item at \a index in the model. - - For example, for a model like this: - - \qml - XmlListModel { - id: model - source: "http://mysite.com/feed.xml" - query: "/feed/entry" - XmlRole { name: "title"; query: "title/string()" } - } - \endqml - - This will access the \c title value for the first item in the model: - - \js - var title = model.get(0).title; - \endjs -*/ -QQmlV4Handle QQuickXmlListModel::get(int index) const -{ - // Must be called with a context and handle scope - Q_D(const QQuickXmlListModel); - - if (index < 0 || index >= count()) - return QQmlV4Handle(Encode::undefined()); - - QQmlEngine *engine = qmlContext(this)->engine(); - ExecutionEngine *v4engine = engine->handle(); - Scope scope(v4engine); - Scoped<Object> o(scope, v4engine->newObject()); - ScopedString name(scope); - ScopedValue value(scope); - for (int ii = 0; ii < d->roleObjects.count(); ++ii) { - name = v4engine->newIdentifier(d->roleObjects[ii]->name()); - value = v4engine->fromVariant(d->data.value(ii).value(index)); - o->insertMember(name.getPointer(), value); - } - - return QQmlV4Handle(o); -} - -/*! - \qmlproperty enumeration QtQuick.XmlListModel::XmlListModel::status - Specifies the model loading status, which can be one of the following: - - \list - \li XmlListModel.Null - No XML data has been set for this model. - \li XmlListModel.Ready - The XML data has been loaded into the model. - \li XmlListModel.Loading - The model is in the process of reading and loading XML data. - \li XmlListModel.Error - An error occurred while the model was loading. See errorString() for details - about the error. - \endlist - - \sa progress - -*/ -QQuickXmlListModel::Status QQuickXmlListModel::status() const -{ - Q_D(const QQuickXmlListModel); - return d->status; -} - -/*! - \qmlproperty real QtQuick.XmlListModel::XmlListModel::progress - - This indicates the current progress of the downloading of the XML data - source. This value ranges from 0.0 (no data downloaded) to - 1.0 (all data downloaded). If the XML data is not from a remote source, - the progress becomes 1.0 as soon as the data is read. - - Note that when the progress is 1.0, the XML data has been downloaded, but - it is yet to be loaded into the model at this point. Use the status - property to find out when the XML data has been read and loaded into - the model. - - \sa status, source -*/ -qreal QQuickXmlListModel::progress() const -{ - Q_D(const QQuickXmlListModel); - return d->progress; -} - -/*! - \qmlmethod QtQuick.XmlListModel::XmlListModel::errorString() - - Returns a string description of the last error that occurred - if \l status is XmlListModel::Error. -*/ -QString QQuickXmlListModel::errorString() const -{ - Q_D(const QQuickXmlListModel); - return d->errorString; -} - -void QQuickXmlListModel::classBegin() -{ - Q_D(QQuickXmlListModel); - d->isComponentComplete = false; - - QQuickXmlQueryEngine *queryEngine = QQuickXmlQueryEngine::instance(qmlEngine(this)); - connect(queryEngine, SIGNAL(queryCompleted(QQuickXmlQueryResult)), - SLOT(queryCompleted(QQuickXmlQueryResult))); - connect(queryEngine, SIGNAL(error(void*,QString)), - SLOT(queryError(void*,QString))); -} - -void QQuickXmlListModel::componentComplete() -{ - Q_D(QQuickXmlListModel); - d->isComponentComplete = true; - reload(); -} - -/*! - \qmlmethod QtQuick.XmlListModel::XmlListModel::reload() - - Reloads the model. - - If no key roles have been specified, all existing model - data is removed, and the model is rebuilt from scratch. - - Otherwise, items are only added if the model does not already - contain items with matching key role values. - - \sa {Using key XML roles}, XmlRole::isKey -*/ -void QQuickXmlListModel::reload() -{ - Q_D(QQuickXmlListModel); - - if (!d->isComponentComplete) - return; - - QQuickXmlQueryEngine::instance(qmlEngine(this))->abort(d->queryId); - d->queryId = -1; - - if (d->size < 0) - d->size = 0; - -#if QT_CONFIG(qml_network) - if (d->reply) { - d->reply->abort(); - d->deleteReply(); - } -#endif - - if (!d->xml.isEmpty()) { - d->queryId = QQuickXmlQueryEngine::instance(qmlEngine(this))->doQuery(d->query, d->namespaces, d->xml.toUtf8(), &d->roleObjects, d->keyRoleResultsCache); - d->notifyQueryStarted(false); - - } else if (d->src.isEmpty()) { - d->queryId = XMLLISTMODEL_CLEAR_ID; - d->notifyQueryStarted(false); - QTimer::singleShot(0, this, SLOT(dataCleared())); - - } else if (QQmlFile::isLocalFile(d->src)) { - QFile file(QQmlFile::urlToLocalFileOrQrc(d->src)); - QByteArray data = file.open(QIODevice::ReadOnly) ? file.readAll() : QByteArray(); - d->notifyQueryStarted(false); - if (data.isEmpty()) { - d->queryId = XMLLISTMODEL_CLEAR_ID; - QTimer::singleShot(0, this, SLOT(dataCleared())); - } else { - d->queryId = QQuickXmlQueryEngine::instance(qmlEngine(this))->doQuery( - d->query, d->namespaces, data, &d->roleObjects, d->keyRoleResultsCache); - } - } else { -#if QT_CONFIG(qml_network) - d->notifyQueryStarted(true); - QNetworkRequest req(d->src); - req.setRawHeader("Accept", "application/xml,*/*"); - d->reply = qmlContext(this)->engine()->networkAccessManager()->get(req); - QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished())); - QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); -#else - d->queryId = XMLLISTMODEL_CLEAR_ID; - d->notifyQueryStarted(false); - QTimer::singleShot(0, this, SLOT(dataCleared())); -#endif - } -} - -#define XMLLISTMODEL_MAX_REDIRECT 16 - -#if QT_CONFIG(qml_network) -void QQuickXmlListModel::requestFinished() -{ - Q_D(QQuickXmlListModel); - - d->redirectCount++; - if (d->redirectCount < XMLLISTMODEL_MAX_REDIRECT) { - QVariant redirect = d->reply->attribute(QNetworkRequest::RedirectionTargetAttribute); - if (redirect.isValid()) { - QUrl url = d->reply->url().resolved(redirect.toUrl()); - d->deleteReply(); - setSource(url); - return; - } - } - d->redirectCount = 0; - - if (d->reply->error() != QNetworkReply::NoError) { - d->errorString = d->reply->errorString(); - d->deleteReply(); - - if (d->size > 0) { - beginRemoveRows(QModelIndex(), 0, d->size - 1); - d->data.clear(); - d->size = 0; - endRemoveRows(); - emit countChanged(); - } - - d->status = Error; - d->queryId = -1; - emit statusChanged(d->status); - } else { - QByteArray data = d->reply->readAll(); - if (data.isEmpty()) { - d->queryId = XMLLISTMODEL_CLEAR_ID; - QTimer::singleShot(0, this, SLOT(dataCleared())); - } else { - d->queryId = QQuickXmlQueryEngine::instance(qmlEngine(this))->doQuery(d->query, d->namespaces, data, &d->roleObjects, d->keyRoleResultsCache); - } - d->deleteReply(); - - d->progress = 1.0; - emit progressChanged(d->progress); - } -} -#endif - -void QQuickXmlListModel::requestProgress(qint64 received, qint64 total) -{ - Q_D(QQuickXmlListModel); - if (d->status == Loading && total > 0) { - d->progress = qreal(received)/total; - emit progressChanged(d->progress); - } -} - -void QQuickXmlListModel::dataCleared() -{ - Q_D(QQuickXmlListModel); - QQuickXmlQueryResult r; - r.queryId = XMLLISTMODEL_CLEAR_ID; - r.size = 0; - r.removed << qMakePair(0, count()); - r.keyRoleResultsCache = d->keyRoleResultsCache; - queryCompleted(r); -} - -void QQuickXmlListModel::queryError(void* object, const QString& error) -{ - // Be extra careful, object may no longer exist, it's just an ID. - Q_D(QQuickXmlListModel); - for (int i=0; i<d->roleObjects.count(); i++) { - if (d->roleObjects.at(i) == static_cast<QQuickXmlListModelRole*>(object)) { - qmlWarning(d->roleObjects.at(i)) << QQuickXmlListModel::tr("invalid query: \"%1\"").arg(error); - return; - } - } - qmlWarning(this) << QQuickXmlListModel::tr("invalid query: \"%1\"").arg(error); -} - -void QQuickXmlListModel::queryCompleted(const QQuickXmlQueryResult &result) -{ - Q_D(QQuickXmlListModel); - if (result.queryId != d->queryId) - return; - - int origCount = d->size; - bool sizeChanged = result.size != d->size; - - d->keyRoleResultsCache = result.keyRoleResultsCache; - if (d->src.isEmpty() && d->xml.isEmpty()) - d->status = Null; - else - d->status = Ready; - d->errorString.clear(); - d->queryId = -1; - - bool hasKeys = false; - for (int i=0; i<d->roleObjects.count(); i++) { - if (d->roleObjects[i]->isKey()) { - hasKeys = true; - break; - } - } - if (!hasKeys) { - if (origCount > 0) { - beginRemoveRows(QModelIndex(), 0, origCount - 1); - endRemoveRows(); - } - d->size = result.size; - d->data = result.data; - if (d->size > 0) { - beginInsertRows(QModelIndex(), 0, d->size - 1); - endInsertRows(); - } - } else { - for (int i=0; i<result.removed.count(); i++) { - const int index = result.removed[i].first; - const int count = result.removed[i].second; - if (count > 0) { - beginRemoveRows(QModelIndex(), index, index + count - 1); - endRemoveRows(); - } - } - d->size = result.size; - d->data = result.data; - for (int i=0; i<result.inserted.count(); i++) { - const int index = result.inserted[i].first; - const int count = result.inserted[i].second; - if (count > 0) { - beginInsertRows(QModelIndex(), index, index + count - 1); - endInsertRows(); - } - } - } - if (sizeChanged) - emit countChanged(); - - emit statusChanged(d->status); -} - -QT_END_NAMESPACE - -#include <qqmlxmllistmodel.moc> diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h deleted file mode 100644 index 65f1299324..0000000000 --- a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h +++ /dev/null @@ -1,219 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKXMLLISTMODEL_H -#define QQUICKXMLLISTMODEL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <qqml.h> -#include <qqmlinfo.h> - -#include <QtCore/qurl.h> -#include <QtCore/qstringlist.h> -#include <QtCore/qabstractitemmodel.h> -#include <private/qv8engine_p.h> - -QT_BEGIN_NAMESPACE - - -class QQmlContext; -class QQuickXmlListModelRole; -class QQuickXmlListModelPrivate; - -struct QQuickXmlQueryResult { - int queryId; - int size; - QList<QList<QVariant> > data; - QList<QPair<int, int> > inserted; - QList<QPair<int, int> > removed; - QStringList keyRoleResultsCache; -}; - -class QQuickXmlListModel : public QAbstractListModel, public QQmlParserStatus -{ - Q_OBJECT - Q_INTERFACES(QQmlParserStatus) - - Q_PROPERTY(Status status READ status NOTIFY statusChanged) - Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - Q_PROPERTY(QString xml READ xml WRITE setXml NOTIFY xmlChanged) - Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged) - Q_PROPERTY(QString namespaceDeclarations READ namespaceDeclarations WRITE setNamespaceDeclarations NOTIFY namespaceDeclarationsChanged) - Q_PROPERTY(QQmlListProperty<QQuickXmlListModelRole> roles READ roleObjects) - Q_PROPERTY(int count READ count NOTIFY countChanged) - Q_CLASSINFO("DefaultProperty", "roles") - -public: - QQuickXmlListModel(QObject *parent = 0); - ~QQuickXmlListModel(); - - QModelIndex index(int row, int column, const QModelIndex &parent) const override; - int rowCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - QHash<int, QByteArray> roleNames() const override; - - int count() const; - - QQmlListProperty<QQuickXmlListModelRole> roleObjects(); - - QUrl source() const; - void setSource(const QUrl&); - - QString xml() const; - void setXml(const QString&); - - QString query() const; - void setQuery(const QString&); - - QString namespaceDeclarations() const; - void setNamespaceDeclarations(const QString&); - - Q_INVOKABLE QQmlV4Handle get(int index) const; - - enum Status { Null, Ready, Loading, Error }; - Q_ENUM(Status) - Status status() const; - qreal progress() const; - - Q_INVOKABLE QString errorString() const; - - void classBegin() override; - void componentComplete() override; - -Q_SIGNALS: - void statusChanged(QQuickXmlListModel::Status); - void progressChanged(qreal progress); - void countChanged(); - void sourceChanged(); - void xmlChanged(); - void queryChanged(); - void namespaceDeclarationsChanged(); - -public Q_SLOTS: - // ### need to use/expose Expiry to guess when to call this? - // ### property to auto-call this on reasonable Expiry? - // ### LastModified/Age also useful to guess. - // ### Probably also applies to other network-requesting types. - void reload(); - -private Q_SLOTS: -#if QT_CONFIG(qml_network) - void requestFinished(); -#endif - void requestProgress(qint64,qint64); - void dataCleared(); - void queryCompleted(const QQuickXmlQueryResult &); - void queryError(void* object, const QString& error); - -private: - Q_DECLARE_PRIVATE(QQuickXmlListModel) - Q_DISABLE_COPY(QQuickXmlListModel) -}; - -class QQuickXmlListModelRole : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - Q_PROPERTY(QString query READ query WRITE setQuery NOTIFY queryChanged) - Q_PROPERTY(bool isKey READ isKey WRITE setIsKey NOTIFY isKeyChanged) -public: - QQuickXmlListModelRole() : m_isKey(false) {} - ~QQuickXmlListModelRole() {} - - QString name() const { return m_name; } - void setName(const QString &name) { - if (name == m_name) - return; - m_name = name; - Q_EMIT nameChanged(); - } - - QString query() const { return m_query; } - void setQuery(const QString &query) - { - if (query.startsWith(QLatin1Char('/'))) { - qmlWarning(this) << tr("An XmlRole query must not start with '/'"); - return; - } - if (m_query == query) - return; - m_query = query; - Q_EMIT queryChanged(); - } - - bool isKey() const { return m_isKey; } - void setIsKey(bool b) { - if (m_isKey == b) - return; - m_isKey = b; - Q_EMIT isKeyChanged(); - } - - bool isValid() const { - return !m_name.isEmpty() && !m_query.isEmpty(); - } - -Q_SIGNALS: - void nameChanged(); - void queryChanged(); - void isKeyChanged(); - -private: - QString m_name; - QString m_query; - bool m_isKey; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickXmlListModel) -QML_DECLARE_TYPE(QQuickXmlListModelRole) - -#endif // QQUICKXMLLISTMODEL_H diff --git a/src/imports/xmllistmodel/xmllistmodel.pro b/src/imports/xmllistmodel/xmllistmodel.pro deleted file mode 100644 index 1e61f4d3d9..0000000000 --- a/src/imports/xmllistmodel/xmllistmodel.pro +++ /dev/null @@ -1,14 +0,0 @@ -CXX_MODULE = qml -TARGET = qmlxmllistmodelplugin -TARGETPATH = QtQuick/XmlListModel -IMPORT_VERSION = 2.$$QT_MINOR_VERSION - -QT = xmlpatterns qml-private core-private -qtConfig(qml-network): QT += network - -SOURCES += qqmlxmllistmodel.cpp plugin.cpp -HEADERS += qqmlxmllistmodel_p.h - -load(qml_plugin) - -requires(qtConfig(qml-network)) diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf index 6161760471..40acc7c13f 100644 --- a/src/qml/doc/qtqml.qdocconf +++ b/src/qml/doc/qtqml.qdocconf @@ -33,7 +33,7 @@ qhp.QtQml.subprojects.qmltypes.sortPages = true tagfile = ../../../doc/qtqml/qtqml.tags -depends += qtcore qtxmlpatterns qtgui qtquick qtdoc qtlinguist qmake qtscript qtwidgets +depends += qtcore qtgui qtquick qtdoc qtlinguist qmake qtscript qtwidgets headerdirs += .. \ ../../imports/models diff --git a/src/qmltest/doc/qtqmltest.qdocconf b/src/qmltest/doc/qtqmltest.qdocconf index 33e8ae334c..a819546fba 100644 --- a/src/qmltest/doc/qtqmltest.qdocconf +++ b/src/qmltest/doc/qtqmltest.qdocconf @@ -31,7 +31,7 @@ qhp.QtQmlTest.subprojects.qmltypes.sortPages = true tagfile = ../../../doc/qtqmltest/qtqmltest.tags -depends += qtcore qtxmlpatterns qtgui qttestlib qtqml qtquick qtdoc +depends += qtcore qtgui qttestlib qtqml qtquick qtdoc headerdirs += .. diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf index 1dbf199bc8..8c69eba6a6 100644 --- a/src/quick/doc/qtquick.qdocconf +++ b/src/quick/doc/qtquick.qdocconf @@ -37,7 +37,7 @@ qhp.QtQuick.subprojects.examples.selectors = fake:example tagfile = ../../../doc/qtquick/qtquick.tags -depends += qtcore qtxmlpatterns qtqml qtqmltest qtgui qtlinguist qtquickcontrols qtdoc qtquickdialogs qtsensors qtwidgets qmake qtmultimedia qtgraphicaleffects qtsql +depends += qtcore qtqml qtqmltest qtgui qtlinguist qtquickcontrols qtquickcontrols2 qtdoc qtquickdialogs qtsensors qtwidgets qmake qtmultimedia qtgraphicaleffects qtsql headerdirs += ..\ ../../quickwidgets diff --git a/src/quick/doc/snippets/qml/xmlrole.qml b/src/quick/doc/snippets/qml/xmlrole.qml deleted file mode 100644 index 9c5172ba45..0000000000 --- a/src/quick/doc/snippets/qml/xmlrole.qml +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -Rectangle { - width: 300; height: 200 - -//![0] -XmlListModel { - id: model -//![0] - source: "xmlrole.xml" - -//![1] - // XmlRole queries will be made on <book> elements - query: "/catalog/book" - - // query the book title - XmlRole { name: "title"; query: "title/string()" } - - // query the book's year - XmlRole { name: "year"; query: "year/number()" } - - // query the book's type (the '@' indicates 'type' is an attribute, not an element) - XmlRole { name: "type"; query: "@type/string()" } - - // query the book's first listed author (note in XPath the first index is 1, not 0) - XmlRole { name: "first_author"; query: "author[1]/string()" } - - // query the wanted attribute as a boolean - XmlRole { name: "wanted"; query: "boolean(@wanted)" } -} -//![1] - -//![2] -ListView { - width: 300; height: 200 - model: model - delegate: Column { - Text { text: title + " (" + type + ")"; font.bold: wanted } - Text { text: first_author } - Text { text: year } - } -//![2] -} - -} diff --git a/tests/auto/quick/examples/examples.pro b/tests/auto/quick/examples/examples.pro index fd8cfd83c8..c047f993ea 100644 --- a/tests/auto/quick/examples/examples.pro +++ b/tests/auto/quick/examples/examples.pro @@ -8,5 +8,4 @@ DEFINES += SRCDIR=\\\"$$PWD\\\" #temporary QT += core-private gui-private qml-private quick-private testlib -!qtHaveModule(xmlpatterns): DEFINES += QT_NO_XMLPATTERNS diff --git a/tests/auto/quick/examples/tst_examples.cpp b/tests/auto/quick/examples/tst_examples.cpp index b3fc87a8de..9b3fa8fd2c 100644 --- a/tests/auto/quick/examples/tst_examples.cpp +++ b/tests/auto/quick/examples/tst_examples.cpp @@ -88,12 +88,6 @@ tst_examples::tst_examples() excludedFiles << "examples/quick/shapes/content/main.qml"; // relies on resources excludedFiles << "examples/quick/shapes/content/interactive.qml"; // relies on resources -#ifdef QT_NO_XMLPATTERNS - excludedFiles << "snippets/qml/xmlrole.qml"; - excludedFiles << "particles/itemparticle/particleview.qml"; - excludedFiles << "views/visualdatamodel/slideshow.qml"; -#endif - #if !QT_CONFIG(opengl) //No support for Particles excludedFiles << "examples/qml/dynamicscene/dynamicscene.qml"; diff --git a/tests/auto/quick/qquickxmllistmodel/data/empty.xml b/tests/auto/quick/qquickxmllistmodel/data/empty.xml deleted file mode 100644 index e69de29bb2..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/empty.xml +++ /dev/null diff --git a/tests/auto/quick/qquickxmllistmodel/data/get.qml b/tests/auto/quick/qquickxmllistmodel/data/get.qml deleted file mode 100644 index 509da7174b..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/get.qml +++ /dev/null @@ -1,61 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } - - id: root - - property bool preTest: false - property bool postTest: false - - function runPreTest() { - if (root.get(0) != undefined) - return; - - preTest = true; - } - - function runPostTest() { - if (root.get(-1) != undefined) - return; - - var row = root.get(0); - if (row.name != "Polly" || - row.type != "Parrot" || - row.age != 12 || - row.size != "Small") - return; - - row = root.get(1); - if (row.name != "Penny" || - row.type != "Turtle" || - row.age != 4 || - row.size != "Small") - return; - - row = root.get(7); - if (row.name != "Rover" || - row.type != "Dog" || - row.age != 0 || - row.size != "Large") - return; - - row = root.get(8); - if (row.name != "Tiny" || - row.type != "Elephant" || - row.age != 15 || - row.size != "Large") - return; - - if (root.get(9) != undefined) - return; - - postTest = true; - } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/groups.qml b/tests/auto/quick/qquickxmllistmodel/data/groups.qml deleted file mode 100644 index c1b574a822..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/groups.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "groups.xml" - query: "//animal[@name='Garfield']/parent::group" - - XmlRole { name: "id"; query: "@id/string()" } - XmlRole { name: "name"; query: "@name/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/groups.xml b/tests/auto/quick/qquickxmllistmodel/data/groups.xml deleted file mode 100644 index 5de4d2ec71..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/groups.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<groups version="2.0"> - <group id="1" name="Animals" type="root"> - <group id="11" name="dogs"> - <animal id="111" name="Lassie"/> - <animal id="112" name="Laika"/> - <animal id="113" name="Wile E. Coyote" type="fictional"/> - </group> - <group id="12" name="cats"> - <animal id="121" name="Garfield" type="fictional"/> - <animal id="122" name="Sylvester" type="fictional"/> - </group> - <group id="13" name="birds"> - <animal id="131" name="Donald Duck" type="fictional"/> - <animal id="132" name="Phoenix" type="fictional"/> - </group> - </group> -</groups> diff --git a/tests/auto/quick/qquickxmllistmodel/data/model.qml b/tests/auto/quick/qquickxmllistmodel/data/model.qml deleted file mode 100644 index 2df3927479..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/model.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/model.xml b/tests/auto/quick/qquickxmllistmodel/data/model.xml deleted file mode 100644 index 40cd6d0432..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/model.xml +++ /dev/null @@ -1,54 +0,0 @@ -<Pets> - <Pet> - <name>Polly</name> - <type>Parrot</type> - <age>12</age> - <size>Small</size> - </Pet> - <Pet> - <name>Penny</name> - <type>Turtle</type> - <age>4</age> - <size>Small</size> - </Pet> - <Pet> - <name>Warren</name> - <type>Rabbit</type> - <age>2</age> - <size>Small</size> - </Pet> - <Pet> - <name>Spot</name> - <type>Dog</type> - <age>9</age> - <size>Medium</size> - </Pet> - <Pet> - <name>Whiskers</name> - <type>Cat</type> - <age>2</age> - <size>Medium</size> - </Pet> - <Pet> - <name>Joey</name> - <type>Kangaroo</type> - <age>1</age> - </Pet> - <Pet> - <name>Kimba</name> - <type>Bunny</type> - <age>65</age> - <size>Large</size> - </Pet> - <Pet> - <name>Rover</name> - <type>Dog</type> - <size>Large</size> - </Pet> - <Pet> - <name>Tiny</name> - <type>Elephant</type> - <age>15</age> - <size>Large</size> - </Pet> -</Pets> diff --git a/tests/auto/quick/qquickxmllistmodel/data/model2.xml b/tests/auto/quick/qquickxmllistmodel/data/model2.xml deleted file mode 100644 index dab2ec6dc0..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/model2.xml +++ /dev/null @@ -1,14 +0,0 @@ -<Pets> - <Pet> - <name>Polly</name> - <type>Parrot</type> - <age>12</age> - <size>Small</size> - </Pet> - <Pet> - <name>Penny</name> - <type>Turtle</type> - <age>4</age> - <size>Small</size> - </Pet> -</Pets> diff --git a/tests/auto/quick/qquickxmllistmodel/data/propertychanges.qml b/tests/auto/quick/qquickxmllistmodel/data/propertychanges.qml deleted file mode 100644 index f8a97bffc3..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/propertychanges.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { objectName: "role"; name: "name"; query: "name/string()" } - XmlRole { name: "type"; query: "type/string()" } - XmlRole { name: "age"; query: "age/number()" } - XmlRole { name: "size"; query: "size/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml b/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml deleted file mode 100644 index c0c5a25e3c..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/proxyCrash.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 -import SortFilterProxyModel 1.0 - -SortFilterProxyModel { - source: XmlListModel { - XmlRole { } - } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/recipes.qml b/tests/auto/quick/qquickxmllistmodel/data/recipes.qml deleted file mode 100644 index dc609e95e3..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/recipes.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "recipes.xml" - query: "/recipes/recipe" - XmlRole { name: "title"; query: "@title/string()" } - XmlRole { name: "picture"; query: "picture/string()" } - XmlRole { name: "ingredients"; query: "ingredients/string()" } - XmlRole { name: "preparation"; query: "method/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/recipes.xml b/tests/auto/quick/qquickxmllistmodel/data/recipes.xml deleted file mode 100644 index d71de60710..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/recipes.xml +++ /dev/null @@ -1,90 +0,0 @@ -<recipes> - <recipe title="Pancakes"> - <picture>content/pics/pancakes.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 1 cup (150g) self-raising flour - <li> 1 tbs caster sugar - <li> 3/4 cup (185ml) milk - <li> 1 egg - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Sift flour and sugar together into a bowl. Add a pinch of salt. - <li> Beat milk and egg together, then add to dry ingredients. Beat until smooth. - <li> Pour mixture into a pan on medium heat and cook until bubbles appear on the surface. - <li> Turn over and cook other side until golden. - </ol> - </html> - ]]></method> - </recipe> - <recipe title="Fruit Salad"> - <picture>content/pics/fruit-salad.jpg</picture> - <ingredients><![CDATA[* Seasonal Fruit]]></ingredients> - <method><![CDATA[* Chop fruit and place in a bowl.]]></method> - </recipe> - <recipe title="Vegetable Soup"> - <picture>content/pics/vegetable-soup.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 1 onion - <li> 1 turnip - <li> 1 potato - <li> 1 carrot - <li> 1 head of celery - <li> 1 1/2 litres of water - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Chop vegetables. - <li> Boil in water until vegetables soften. - <li> Season with salt and pepper to taste. - </ol> - </html> - ]]></method> - </recipe> - <recipe title="Hamburger"> - <picture>content/pics/hamburger.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 500g minced beef - <li> Seasoning - <li> lettuce, tomato, onion, cheese - <li> 1 hamburger bun for each burger - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Mix the beef, together with seasoning, in a food processor. - <li> Shape the beef into burgers. - <li> Grill the burgers for about 5 mins on each side (until cooked through) - <li> Serve each burger on a bun with ketchup, cheese, lettuce, tomato and onion. - </ol> - </html> - ]]></method> - </recipe> - <recipe title="Lemonade"> - <picture>content/pics/lemonade.jpg</picture> - <ingredients><![CDATA[<html> - <ul> - <li> 1 cup Lemon Juice - <li> 1 cup Sugar - <li> 6 Cups of Water (2 cups warm water, 4 cups cold water) - </ul> - </html> - ]]></ingredients> - <method><![CDATA[<html> - <ol> - <li> Pour 2 cups of warm water into a pitcher and stir in sugar until it dissolves. - <li> Pour in lemon juice, stir again, and add 4 cups of cold water. - <li> Chill or serve over ice cubes. - </ol> - </html> - ]]></method> - </recipe> -</recipes> diff --git a/tests/auto/quick/qquickxmllistmodel/data/roleCrash.qml b/tests/auto/quick/qquickxmllistmodel/data/roleCrash.qml deleted file mode 100644 index 6a7059bb45..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/roleCrash.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - id: model - XmlRole {} - Component.onCompleted: model.roles = 0 -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/roleErrors.qml b/tests/auto/quick/qquickxmllistmodel/data/roleErrors.qml deleted file mode 100644 index 91664b6d4a..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/roleErrors.qml +++ /dev/null @@ -1,11 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "/name/string()" } //starts with '/' - XmlRole { name: "type"; query: "type" } //no type - XmlRole { name: "age"; query: "age/" } //ends with '/' - XmlRole { name: "size"; query: "size/number()" } //wrong type -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/roleKeys.qml b/tests/auto/quick/qquickxmllistmodel/data/roleKeys.qml deleted file mode 100644 index 9f667d86e5..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/roleKeys.qml +++ /dev/null @@ -1,13 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - query: "/data/item" - XmlRole { id: nameRole; name: "name"; query: "name/string()"; isKey: true } - XmlRole { name: "age"; query: "age/number()"; isKey: true } - XmlRole { name: "sport"; query: "sport/string()" } - - function disableNameKey() { - nameRole.isKey = false; - } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/testtypes.qml b/tests/auto/quick/qquickxmllistmodel/data/testtypes.qml deleted file mode 100644 index 5ec1ffa35f..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/testtypes.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - query: "/data" - XmlRole { name: "stringValue"; query: "a-string/string()" } - XmlRole { name: "numberValue"; query: "a-number/number()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/data/unique.qml b/tests/auto/quick/qquickxmllistmodel/data/unique.qml deleted file mode 100644 index 322a2e4e5c..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/data/unique.qml +++ /dev/null @@ -1,9 +0,0 @@ -import QtQuick 2.0 -import QtQuick.XmlListModel 2.0 - -XmlListModel { - source: "model.xml" - query: "/Pets/Pet" - XmlRole { name: "name"; query: "name/string()" } - XmlRole { name: "name"; query: "type/string()" } -} diff --git a/tests/auto/quick/qquickxmllistmodel/qquickxmllistmodel.pro b/tests/auto/quick/qquickxmllistmodel/qquickxmllistmodel.pro deleted file mode 100644 index 902325802c..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/qquickxmllistmodel.pro +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG += testcase -TARGET = tst_qquickxmllistmodel -macx:CONFIG -= app_bundle - -SOURCES += tst_qquickxmllistmodel.cpp \ - ../../../../src/imports/xmllistmodel/qqmlxmllistmodel.cpp -HEADERS += ../../../../src/imports/xmllistmodel/qqmlxmllistmodel_p.h - -include (../../shared/util.pri) - -TESTDATA = data/* - -QT += core-private gui-private qml-private network testlib xmlpatterns - -OTHER_FILES += \ - data/groups.qml diff --git a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp b/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp deleted file mode 100644 index bcff0c46fb..0000000000 --- a/tests/auto/quick/qquickxmllistmodel/tst_qquickxmllistmodel.cpp +++ /dev/null @@ -1,1011 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtTest/QtTest> -#include <QtGlobal> -#include <math.h> -#include <QMetaObject> -#include <qtest.h> -#include <QtTest/qsignalspy.h> -#include <QtQml/qqmlnetworkaccessmanagerfactory.h> -#include <QtNetwork/qnetworkaccessmanager.h> -#include <QtNetwork/qnetworkrequest.h> -#include <QtCore/qtimer.h> -#include <QtCore/qfile.h> -#include <QtCore/qtemporaryfile.h> -#include <QtCore/qsortfilterproxymodel.h> -#include "../../shared/util.h" -#include <private/qqmlengine_p.h> - -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlcomponent.h> -#include "../../../../src/imports/xmllistmodel/qqmlxmllistmodel_p.h" - -#include <algorithm> - -typedef QPair<int, int> QQuickXmlListRange; -typedef QList<QVariantList> QQmlXmlModelData; - -Q_DECLARE_METATYPE(QList<QQuickXmlListRange>) -Q_DECLARE_METATYPE(QQmlXmlModelData) -Q_DECLARE_METATYPE(QQuickXmlListModel::Status) - -class tst_qquickxmllistmodel : public QQmlDataTest - -{ - Q_OBJECT -public: - tst_qquickxmllistmodel() {} - -private slots: - void initTestCase() { - QQmlDataTest::initTestCase(); - qRegisterMetaType<QQuickXmlListModel::Status>(); - } - - void buildModel(); - void testTypes(); - void testTypes_data(); - void cdata(); - void attributes(); - void roles(); - void roleErrors(); - void uniqueRoleNames(); - void headers(); - void xml(); - void xml_data(); - void source(); - void source_data(); - void data(); - void get(); - void reload(); - void useKeys(); - void useKeys_data(); - void noKeysValueChanges(); - void keysChanged(); - void threading(); - void threading_data(); - void propertyChanges(); - void selectAncestor(); - - void roleCrash(); - void proxyCrash(); - -private: - QString errorString(QAbstractItemModel *model) { - QString ret; - QMetaObject::invokeMethod(model, "errorString", Q_RETURN_ARG(QString, ret)); - return ret; - } - - QString makeItemXmlAndData(const QString &data, QQmlXmlModelData *modelData = 0) const - { - if (modelData) - modelData->clear(); - QString xml; - - if (!data.isEmpty()) { - QStringList items = data.split(QLatin1Char(';')); - foreach(const QString &item, items) { - if (item.isEmpty()) - continue; - QVariantList variants; - xml += QLatin1String("<item>"); - QStringList fields = item.split(QLatin1Char(',')); - foreach(const QString &field, fields) { - QStringList values = field.split(QLatin1Char('=')); - if (values.count() != 2) { - qWarning() << "makeItemXmlAndData: invalid field:" << field; - continue; - } - xml += QString("<%1>%2</%1>").arg(values[0], values[1]); - if (!modelData) - continue; - bool isNum = false; - int number = values[1].toInt(&isNum); - if (isNum) - variants << number; - else - variants << values[1]; - } - xml += QLatin1String("</item>"); - if (modelData) - modelData->append(variants); - } - } - - QString decl = "<?xml version=\"1.0\" encoding=\"iso-8859-1\" ?>"; - return decl + QLatin1String("<data>") + xml + QLatin1String("</data>"); - } - - QQmlEngine engine; -}; - -class CustomNetworkAccessManagerFactory : public QObject, public QQmlNetworkAccessManagerFactory -{ - Q_OBJECT -public: - QVariantMap lastSentHeaders; - -protected: - QNetworkAccessManager *create(QObject *parent); -}; - -class CustomNetworkAccessManager : public QNetworkAccessManager -{ - Q_OBJECT -public: - CustomNetworkAccessManager(CustomNetworkAccessManagerFactory *factory, QObject *parent) - : QNetworkAccessManager(parent), m_factory(factory) {} - -protected: - QNetworkReply *createRequest(Operation op, const QNetworkRequest &req, QIODevice * outgoingData = 0) - { - if (m_factory) { - QVariantMap map; - foreach (const QString &header, req.rawHeaderList()) - map[header] = req.rawHeader(header.toUtf8()); - m_factory->lastSentHeaders = map; - } - return QNetworkAccessManager::createRequest(op, req, outgoingData); - } - - QPointer<CustomNetworkAccessManagerFactory> m_factory; -}; - -QNetworkAccessManager *CustomNetworkAccessManagerFactory::create(QObject *parent) -{ - return new CustomNetworkAccessManager(this, parent); -} - - -void tst_qquickxmllistmodel::buildModel() -{ - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QModelIndex index = model->index(3, 0); - QCOMPARE(model->data(index, Qt::UserRole).toString(), QLatin1String("Spot")); - QCOMPARE(model->data(index, Qt::UserRole+1).toString(), QLatin1String("Dog")); - QCOMPARE(model->data(index, Qt::UserRole+2).toInt(), 9); - QCOMPARE(model->data(index, Qt::UserRole+3).toString(), QLatin1String("Medium")); - - delete model; -} - -void tst_qquickxmllistmodel::testTypes() -{ - QFETCH(QString, xml); - QFETCH(QString, roleName); - QFETCH(QVariant, expectedValue); - - QQmlComponent component(&engine, testFileUrl("testtypes.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - model->setProperty("xml",xml.toUtf8()); - QMetaObject::invokeMethod(model, "reload"); - QTRY_COMPARE(model->rowCount(), 1); - - int role = model->roleNames().key(roleName.toUtf8(), -1); - QVERIFY(role >= 0); - - QModelIndex index = model->index(0, 0); - if (expectedValue.toString() == "nan") - QVERIFY(qIsNaN(model->data(index, role).toDouble())); - else - QCOMPARE(model->data(index, role), expectedValue); - - delete model; -} - -void tst_qquickxmllistmodel::testTypes_data() -{ - QTest::addColumn<QString>("xml"); - QTest::addColumn<QString>("roleName"); - QTest::addColumn<QVariant>("expectedValue"); - - QTest::newRow("missing string field") << "<data></data>" - << "stringValue" << QVariant(""); - QTest::newRow("empty string") << "<data><a-string></a-string></data>" - << "stringValue" << QVariant(""); - QTest::newRow("1-char string") << "<data><a-string>5</a-string></data>" - << "stringValue" << QVariant("5"); - QTest::newRow("string ok") << "<data><a-string>abc def g</a-string></data>" - << "stringValue" << QVariant("abc def g"); - - QTest::newRow("missing number field") << "<data></data>" - << "numberValue" << QVariant(""); - double nan = qQNaN(); - QTest::newRow("empty number field") << "<data><a-number></a-number></data>" - << "numberValue" << QVariant(nan); - QTest::newRow("number field with string") << "<data><a-number>a string</a-number></data>" - << "numberValue" << QVariant(nan); - QTest::newRow("-1") << "<data><a-number>-1</a-number></data>" - << "numberValue" << QVariant("-1"); - QTest::newRow("-1.5") << "<data><a-number>-1.5</a-number></data>" - << "numberValue" << QVariant("-1.5"); - QTest::newRow("0") << "<data><a-number>0</a-number></data>" - << "numberValue" << QVariant("0"); - QTest::newRow("+1") << "<data><a-number>1</a-number></data>" - << "numberValue" << QVariant("1"); - QTest::newRow("+1.5") << "<data><a-number>1.5</a-number></data>" - << "numberValue" << QVariant("1.5"); -} - -void tst_qquickxmllistmodel::cdata() -{ - QQmlComponent component(&engine, testFileUrl("recipes.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 5); - - QVERIFY(model->data(model->index(2, 0), Qt::UserRole+2).toString().startsWith(QLatin1String("<html>"))); - - delete model; -} - -void tst_qquickxmllistmodel::attributes() -{ - QQmlComponent component(&engine, testFileUrl("recipes.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 5); - QCOMPARE(model->data(model->index(2, 0), Qt::UserRole).toString(), QLatin1String("Vegetable Soup")); - - delete model; -} - -void tst_qquickxmllistmodel::roles() -{ - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.count(), 4); - QVERIFY(roleNames.key("name", -1) >= 0); - QVERIFY(roleNames.key("type", -1) >= 0); - QVERIFY(roleNames.key("age", -1) >= 0); - QVERIFY(roleNames.key("size", -1) >= 0); - - QSet<int> roles; - roles.insert(roleNames.key("name")); - roles.insert(roleNames.key("type")); - roles.insert(roleNames.key("age")); - roles.insert(roleNames.key("size")); - QCOMPARE(roles.count(), 4); - - delete model; -} - -void tst_qquickxmllistmodel::roleErrors() -{ - QQmlComponent component(&engine, testFileUrl("roleErrors.qml")); - QTest::ignoreMessage(QtWarningMsg, (testFileUrl("roleErrors.qml").toString() + ":7:5: QML XmlRole: An XmlRole query must not start with '/'").toUtf8().constData()); - QTest::ignoreMessage(QtWarningMsg, (testFileUrl("roleErrors.qml").toString() + ":10:5: QML XmlRole: invalid query: \"age/\"").toUtf8().constData()); - - //### make sure we receive all expected warning messages. - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QModelIndex index = model->index(3, 0); - //### should any of these return valid values? - QCOMPARE(model->data(index, Qt::UserRole), QVariant()); - QCOMPARE(model->data(index, Qt::UserRole+1), QVariant()); - QCOMPARE(model->data(index, Qt::UserRole+2), QVariant()); - - QEXPECT_FAIL("", "QTBUG-10797", Continue); - QCOMPARE(model->data(index, Qt::UserRole+3), QVariant()); - - delete model; -} - -void tst_qquickxmllistmodel::uniqueRoleNames() -{ - QQmlComponent component(&engine, testFileUrl("unique.qml")); - QTest::ignoreMessage(QtWarningMsg, (testFileUrl("unique.qml").toString() + ":8:5: QML XmlRole: \"name\" duplicates a previous role name and will be disabled.").toUtf8().constData()); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QHash<int, QByteArray> roleNames = model->roleNames(); - QCOMPARE(roleNames.count(), 1); - - delete model; -} - - -void tst_qquickxmllistmodel::xml() -{ - QFETCH(QString, xml); - QFETCH(int, count); - - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - - QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status))); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QTest::qWait(50); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - QCOMPARE(model->rowCount(), 9); - - // if xml is empty (i.e. clearing) it won't have any effect if a source is set - if (xml.isEmpty()) - model->setProperty("source",QUrl()); - model->setProperty("xml",xml); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); // immediately goes to 1.0 if using setXml() - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - if (xml.isEmpty()) - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Null); - else - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->rowCount(), count); - - delete model; -} - -void tst_qquickxmllistmodel::xml_data() -{ - QTest::addColumn<QString>("xml"); - QTest::addColumn<int>("count"); - - QTest::newRow("xml with no items") << "<Pets></Pets>" << 0; - QTest::newRow("empty xml") << "" << 0; - QTest::newRow("one item") << "<Pets><Pet><name>Hobbes</name><type>Tiger</type><age>7</age><size>Large</size></Pet></Pets>" << 1; -} - -void tst_qquickxmllistmodel::headers() -{ - // ensure the QNetworkAccessManagers created for this test are immediately deleted - QQmlEngine qmlEng; - - CustomNetworkAccessManagerFactory factory; - qmlEng.setNetworkAccessManagerFactory(&factory); - - QQmlComponent component(&qmlEng, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - - // It doesn't do a network request for a local file - QCOMPARE(factory.lastSentHeaders.count(), 0); - - model->setProperty("source", QUrl("http://localhost/filethatdoesnotexist.xml")); - QTRY_COMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Error); - - QVariantMap expectedHeaders; - expectedHeaders["Accept"] = "application/xml,*/*"; - - QCOMPARE(factory.lastSentHeaders.count(), expectedHeaders.count()); - foreach (const QString &header, expectedHeaders.keys()) { - QVERIFY(factory.lastSentHeaders.contains(header)); - QCOMPARE(factory.lastSentHeaders[header].toString(), expectedHeaders[header].toString()); - } - - delete model; -} - -void tst_qquickxmllistmodel::source() -{ - QFETCH(QUrl, source); - QFETCH(int, count); - QFETCH(QQuickXmlListModel::Status, status); - - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QSignalSpy spy(model, SIGNAL(statusChanged(QQuickXmlListModel::Status))); - - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Ready); - QVERIFY(errorString(model).isEmpty()); - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - QCOMPARE(model->rowCount(), 9); - - model->setProperty("source",source); - if (model->property("source").toString().isEmpty()) - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Null); - QCOMPARE(model->property("progress").toDouble(), qreal(source.isLocalFile() ? 1.0 : 0.0)); - QTRY_COMPARE(spy.count(), 1); spy.clear(); - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), - QQuickXmlListModel::Loading); - QVERIFY(errorString(model).isEmpty()); - - QEventLoop loop; - QTimer timer; - timer.setSingleShot(true); - connect(model, SIGNAL(statusChanged(QQuickXmlListModel::Status)), &loop, SLOT(quit())); - connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - timer.start(20000); - loop.exec(); - - if (spy.count() == 0 && status != QQuickXmlListModel::Ready) { - qWarning("QQuickXmlListModel invalid source test timed out"); - } else { - QCOMPARE(spy.count(), 1); spy.clear(); - } - - QCOMPARE(qvariant_cast<QQuickXmlListModel::Status>(model->property("status")), status); - QCOMPARE(model->rowCount(), count); - - if (status == QQuickXmlListModel::Ready) - QCOMPARE(model->property("progress").toDouble(), qreal(1.0)); - - QCOMPARE(errorString(model).isEmpty(), status == QQuickXmlListModel::Ready); - - delete model; -} - -void tst_qquickxmllistmodel::source_data() -{ - QTest::addColumn<QUrl>("source"); - QTest::addColumn<int>("count"); - QTest::addColumn<QQuickXmlListModel::Status>("status"); - - QTest::newRow("valid") << testFileUrl("model2.xml") << 2 - << QQuickXmlListModel::Ready; - QTest::newRow("invalid") << QUrl("http://blah.blah/blah.xml") << 0 - << QQuickXmlListModel::Error; - - // empty file - QTemporaryFile *temp = new QTemporaryFile(this); - if (temp->open()) - QTest::newRow("empty file") << QUrl::fromLocalFile(temp->fileName()) << 0 - << QQuickXmlListModel::Ready; - temp->close(); -} - -void tst_qquickxmllistmodel::data() -{ - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - for (int i=0; i<9; i++) { - QModelIndex index = model->index(i, 0); - for (int j=0; j<model->roleNames().count(); j++) { - QCOMPARE(model->data(index, j), QVariant()); - } - } - QTRY_COMPARE(model->rowCount(), 9); - - delete model; -} - -void tst_qquickxmllistmodel::get() -{ - QQmlComponent component(&engine, testFileUrl("get.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - - QVERIFY(model != 0); - - QVERIFY(QMetaObject::invokeMethod(model, "runPreTest")); - QCOMPARE(model->property("preTest").toBool(), true); - - QTRY_COMPARE(model->rowCount(), 9); - - QVERIFY(QMetaObject::invokeMethod(model, "runPostTest")); - QCOMPARE(model->property("postTest").toBool(), true); - - delete model; -} - -void tst_qquickxmllistmodel::reload() -{ - // If no keys are used, the model should be rebuilt from scratch when - // reload() is called. - - QQmlComponent component(&engine, testFileUrl("model.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - //reload multiple times to test the xml query aborting - QMetaObject::invokeMethod(model, "reload"); - QMetaObject::invokeMethod(model, "reload"); - QCoreApplication::processEvents(); - QMetaObject::invokeMethod(model, "reload"); - QMetaObject::invokeMethod(model, "reload"); - QTRY_COMPARE(spyCount.count(), 0); - QTRY_COMPARE(spyInsert.count(), 1); - QTRY_COMPARE(spyRemove.count(), 1); - - QCOMPARE(spyInsert[0][1].toInt(), 0); - QCOMPARE(spyInsert[0][2].toInt(), 8); - - QCOMPARE(spyRemove[0][1].toInt(), 0); - QCOMPARE(spyRemove[0][2].toInt(), 8); - - delete model; -} - -void tst_qquickxmllistmodel::useKeys() -{ - // If using incremental updates through keys, the model should only - // insert & remove some of the items, instead of throwing everything - // away and causing the view to repaint the whole view. - - QFETCH(QString, oldXml); - QFETCH(int, oldCount); - QFETCH(QString, newXml); - QFETCH(QQmlXmlModelData, newData); - QFETCH(QList<QQuickXmlListRange>, insertRanges); - QFETCH(QList<QQuickXmlListRange>, removeRanges); - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - model->setProperty("xml",oldXml); - QTRY_COMPARE(model->rowCount(), oldCount); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - - model->setProperty("xml",newXml); - - if (oldCount != newData.count()) { - QTRY_COMPARE(model->rowCount(), newData.count()); - QCOMPARE(spyCount.count(), 1); - } else { - QTRY_VERIFY(spyInsert.count() > 0 || spyRemove.count() > 0); - QCOMPARE(spyCount.count(), 0); - } - - QList<int> roles = model->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - for (int i=0; i<model->rowCount(); i++) { - QModelIndex index = model->index(i, 0); - for (int j=0; j<roles.count(); j++) - QCOMPARE(model->data(index, roles.at(j)), newData[i][j]); - } - - QCOMPARE(spyInsert.count(), insertRanges.count()); - for (int i=0; i<spyInsert.count(); i++) { - QCOMPARE(spyInsert[i][1].toInt(), insertRanges[i].first); - QCOMPARE(spyInsert[i][2].toInt(), insertRanges[i].first + insertRanges[i].second - 1); - } - - QCOMPARE(spyRemove.count(), removeRanges.count()); - for (int i=0; i<spyRemove.count(); i++) { - QCOMPARE(spyRemove[i][1].toInt(), removeRanges[i].first); - QCOMPARE(spyRemove[i][2].toInt(), removeRanges[i].first + removeRanges[i].second - 1); - } - - delete model; -} - -void tst_qquickxmllistmodel::useKeys_data() -{ - QTest::addColumn<QString>("oldXml"); - QTest::addColumn<int>("oldCount"); - QTest::addColumn<QString>("newXml"); - QTest::addColumn<QQmlXmlModelData>("newData"); - QTest::addColumn<QList<QQuickXmlListRange> >("insertRanges"); - QTest::addColumn<QList<QQuickXmlListRange> >("removeRanges"); - - QQmlXmlModelData modelData; - - QTest::newRow("append 1") - << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 1)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("append multiple") - << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("insert in different spots") - << makeItemXmlAndData("name=B,age=35,sport=Athletics") << 1 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 1) << qMakePair(2,2)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("insert in middle") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=D,age=55,sport=Golf") << 2 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)) - << QList<QQuickXmlListRange>(); - - QTest::newRow("remove first") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics") << 2 - << makeItemXmlAndData("name=B,age=35,sport=Athletics", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(0, 1)); - - QTest::newRow("remove last") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics") << 2 - << makeItemXmlAndData("name=A,age=25,sport=Football", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(1, 1)); - - QTest::newRow("remove from multiple spots") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing") << 5 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=C,age=45,sport=Curling", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(1, 1) << qMakePair(3,2)); - - QTest::newRow("remove all") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling") << 3 - << makeItemXmlAndData("", &modelData) - << modelData - << QList<QQuickXmlListRange>() - << (QList<QQuickXmlListRange>() << qMakePair(0, 3)); - - QTest::newRow("replace item") - << makeItemXmlAndData("name=A,age=25,sport=Football") << 1 - << makeItemXmlAndData("name=ZZZ,age=25,sport=Football", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 1)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 1)); - - QTest::newRow("add and remove simultaneously, in different spots") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling;name=D,age=55,sport=Golf") << 4 - << makeItemXmlAndData("name=B,age=35,sport=Athletics;name=E,age=65,sport=Fencing", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 1)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 1) << qMakePair(2,2)); - - QTest::newRow("insert at start, remove at end i.e. rss feed") - << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing") << 3 - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)) - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)); - - QTest::newRow("remove at start, insert at end") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics;name=C,age=45,sport=Curling") << 3 - << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf;name=E,age=65,sport=Fencing", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(1, 2)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)); - - QTest::newRow("all data has changed") - << makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35") << 2 - << makeItemXmlAndData("name=C,age=45,sport=Curling;name=D,age=55,sport=Golf", &modelData) - << modelData - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)) - << (QList<QQuickXmlListRange>() << qMakePair(0, 2)); -} - -void tst_qquickxmllistmodel::noKeysValueChanges() -{ - // The 'key' roles are 'name' and 'age', as defined in roleKeys.qml. - // If a 'sport' value is changed, the model should not be reloaded, - // since 'sport' is not marked as a key. - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - QString xml; - - xml = makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics"); - model->setProperty("xml",xml); - QTRY_COMPARE(model->rowCount(), 2); - - model->setProperty("xml",""); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - - xml = makeItemXmlAndData("name=A,age=25,sport=AussieRules;name=B,age=35,sport=Athletics"); - model->setProperty("xml",xml); - - QList<int> roles = model->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - // wait for the new xml data to be set, and verify no signals were emitted - QTRY_VERIFY(model->data(model->index(0, 0), roles.at(2)).toString() != QLatin1String("Football")); - QCOMPARE(model->data(model->index(0, 0), roles.at(2)).toString(), QLatin1String("AussieRules")); - - QCOMPARE(spyInsert.count(), 0); - QCOMPARE(spyRemove.count(), 0); - QCOMPARE(spyCount.count(), 0); - - QCOMPARE(model->rowCount(), 2); - - delete model; -} - -void tst_qquickxmllistmodel::keysChanged() -{ - // If the key roles change, the next time the data is reloaded, it should - // delete all its data and build a clean model (i.e. same behaviour as - // if no keys are set). - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - - QString xml = makeItemXmlAndData("name=A,age=25,sport=Football;name=B,age=35,sport=Athletics"); - model->setProperty("xml",xml); - QTRY_COMPARE(model->rowCount(), 2); - - model->setProperty("xml",""); - - QSignalSpy spyInsert(model, SIGNAL(rowsInserted(QModelIndex,int,int))); - QSignalSpy spyRemove(model, SIGNAL(rowsRemoved(QModelIndex,int,int))); - QSignalSpy spyCount(model, SIGNAL(countChanged())); - - QVERIFY(QMetaObject::invokeMethod(model, "disableNameKey")); - model->setProperty("xml",xml); - - QTRY_VERIFY(spyInsert.count() > 0 && spyRemove.count() > 0); - - QCOMPARE(spyInsert.count(), 1); - QCOMPARE(spyInsert[0][1].toInt(), 0); - QCOMPARE(spyInsert[0][2].toInt(), 1); - - QCOMPARE(spyRemove.count(), 1); - QCOMPARE(spyRemove[0][1].toInt(), 0); - QCOMPARE(spyRemove[0][2].toInt(), 1); - - QCOMPARE(spyCount.count(), 0); - - delete model; -} - -void tst_qquickxmllistmodel::threading() -{ - QFETCH(int, xmlDataCount); - - QQmlComponent component(&engine, testFileUrl("roleKeys.qml")); - - QAbstractItemModel *m1 = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(m1 != 0); - QAbstractItemModel *m2 = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(m2 != 0); - QAbstractItemModel *m3 = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(m3 != 0); - - for (int dataCount=0; dataCount<xmlDataCount; dataCount++) { - - QString data1, data2, data3; - for (int i=0; i<dataCount; i++) { - data1 += "name=A" + QString::number(i) + ",age=1" + QString::number(i) + ",sport=Football;"; - data2 += "name=B" + QString::number(i) + ",age=2" + QString::number(i) + ",sport=Athletics;"; - data3 += "name=C" + QString::number(i) + ",age=3" + QString::number(i) + ",sport=Curling;"; - } - - //Set the xml data multiple times with randomized order and mixed with multiple event loops - //to test the xml query reloading/aborting, the result should be stable. - m1->setProperty("xml",makeItemXmlAndData(data1)); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m1->setProperty("xml",makeItemXmlAndData(data1)); - m2->setProperty("xml",makeItemXmlAndData(data2)); - QCoreApplication::processEvents(); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m1->setProperty("xml",makeItemXmlAndData(data1)); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - m2->setProperty("xml",makeItemXmlAndData(data2)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - m3->setProperty("xml",makeItemXmlAndData(data3)); - QCoreApplication::processEvents(); - - QTRY_VERIFY(m1->rowCount() == dataCount && m2->rowCount() == dataCount && m3->rowCount() == dataCount); - - for (int i=0; i<dataCount; i++) { - QModelIndex index = m1->index(i, 0); - QList<int> roles = m1->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - QCOMPARE(m1->data(index, roles.at(0)).toString(), QLatin1Char('A') + QString::number(i)); - QCOMPARE(m1->data(index, roles.at(1)).toString(), QLatin1Char('1') + QString::number(i)); - QCOMPARE(m1->data(index, roles.at(2)).toString(), QString("Football")); - - index = m2->index(i, 0); - roles = m2->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - QCOMPARE(m2->data(index, roles.at(0)).toString(), QLatin1Char('B') + QString::number(i)); - QCOMPARE(m2->data(index, roles.at(1)).toString(), QLatin1Char('2') + QString::number(i)); - QCOMPARE(m2->data(index, roles.at(2)).toString(), QString("Athletics")); - - index = m3->index(i, 0); - roles = m3->roleNames().keys(); - std::sort(roles.begin(), roles.end()); - QCOMPARE(m3->data(index, roles.at(0)).toString(), QLatin1Char('C') + QString::number(i)); - QCOMPARE(m3->data(index, roles.at(1)).toString(), QLatin1Char('3') + QString::number(i)); - QCOMPARE(m3->data(index, roles.at(2)).toString(), QString("Curling")); - } - } - - delete m1; - delete m2; - delete m3; -} - -void tst_qquickxmllistmodel::threading_data() -{ - QTest::addColumn<int>("xmlDataCount"); - - QTest::newRow("1") << 1; - QTest::newRow("2") << 2; - QTest::newRow("10") << 10; -} - -void tst_qquickxmllistmodel::propertyChanges() -{ - QQmlComponent component(&engine, testFileUrl("propertychanges.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel*>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 9); - - QObject *role = model->findChild<QObject*>("role"); - QVERIFY(role); - - QSignalSpy nameSpy(role, SIGNAL(nameChanged())); - QSignalSpy querySpy(role, SIGNAL(queryChanged())); - QSignalSpy isKeySpy(role, SIGNAL(isKeyChanged())); - - role->setProperty("name","size"); - role->setProperty("query","size/string()"); - role->setProperty("isKey",true); - - QCOMPARE(role->property("name").toString(), QString("size")); - QCOMPARE(role->property("query").toString(), QString("size/string()")); - QVERIFY(role->property("isKey").toBool()); - - QCOMPARE(nameSpy.count(),1); - QCOMPARE(querySpy.count(),1); - QCOMPARE(isKeySpy.count(),1); - - role->setProperty("name","size"); - role->setProperty("query","size/string()"); - role->setProperty("isKey",true); - - QCOMPARE(nameSpy.count(),1); - QCOMPARE(querySpy.count(),1); - QCOMPARE(isKeySpy.count(),1); - - QSignalSpy sourceSpy(model, SIGNAL(sourceChanged())); - QSignalSpy xmlSpy(model, SIGNAL(xmlChanged())); - QSignalSpy modelQuerySpy(model, SIGNAL(queryChanged())); - QSignalSpy namespaceDeclarationsSpy(model, SIGNAL(namespaceDeclarationsChanged())); - - model->setProperty("source",QUrl("")); - model->setProperty("xml","<Pets><Pet><name>Polly</name><type>Parrot</type><age>12</age><size>Small</size></Pet></Pets>"); - model->setProperty("query","/Pets"); - model->setProperty("namespaceDeclarations","declare namespace media=\"http://search.yahoo.com/mrss/\";"); - - QCOMPARE(model->property("source").toUrl(), QUrl("")); - QCOMPARE(model->property("xml").toString(), QString("<Pets><Pet><name>Polly</name><type>Parrot</type><age>12</age><size>Small</size></Pet></Pets>")); - QCOMPARE(model->property("query").toString(), QString("/Pets")); - QCOMPARE(model->property("namespaceDeclarations").toString(), QString("declare namespace media=\"http://search.yahoo.com/mrss/\";")); - - QTRY_COMPARE(model->rowCount(), 1); - - QCOMPARE(sourceSpy.count(),1); - QCOMPARE(xmlSpy.count(),1); - QCOMPARE(modelQuerySpy.count(),1); - QCOMPARE(namespaceDeclarationsSpy.count(),1); - - model->setProperty("source",QUrl("")); - model->setProperty("xml","<Pets><Pet><name>Polly</name><type>Parrot</type><age>12</age><size>Small</size></Pet></Pets>"); - model->setProperty("query","/Pets"); - model->setProperty("namespaceDeclarations","declare namespace media=\"http://search.yahoo.com/mrss/\";"); - - QCOMPARE(sourceSpy.count(),1); - QCOMPARE(xmlSpy.count(),1); - QCOMPARE(modelQuerySpy.count(),1); - QCOMPARE(namespaceDeclarationsSpy.count(),1); - - QTRY_COMPARE(model->rowCount(), 1); - delete model; -} - -void tst_qquickxmllistmodel::selectAncestor() -{ - QQmlComponent component(&engine, testFileUrl("groups.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - QTRY_COMPARE(model->rowCount(), 1); - - QModelIndex index = model->index(0, 0); - QCOMPARE(model->data(index, Qt::UserRole).toInt(), 12); - QCOMPARE(model->data(index, Qt::UserRole+1).toString(), QLatin1String("cats")); -} - -void tst_qquickxmllistmodel::roleCrash() -{ - // don't crash - QQmlComponent component(&engine, testFileUrl("roleCrash.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - delete model; -} - -class SortFilterProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - Q_PROPERTY(QObject *source READ source WRITE setSource) - -public: - SortFilterProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) { sort(0); } - QObject *source() const { return sourceModel(); } - void setSource(QObject *source) { setSourceModel(qobject_cast<QAbstractItemModel *>(source)); } -}; - -void tst_qquickxmllistmodel::proxyCrash() -{ - qmlRegisterType<SortFilterProxyModel>("SortFilterProxyModel", 1, 0, "SortFilterProxyModel"); - - // don't crash - QQmlComponent component(&engine, testFileUrl("proxyCrash.qml")); - QAbstractItemModel *model = qobject_cast<QAbstractItemModel *>(component.create()); - QVERIFY(model != 0); - delete model; -} - -QTEST_MAIN(tst_qquickxmllistmodel) - -#include "tst_qquickxmllistmodel.moc" diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 6fc3bb5b1b..7257a99d2a 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -41,11 +41,7 @@ PRIVATETESTS += \ qquickstyledtext \ qquickstates \ qquicksystempalette \ - qquicktimeline \ - qquickxmllistmodel - -# This test requires the xmlpatterns module -!qtHaveModule(xmlpatterns): PRIVATETESTS -= qquickxmllistmodel + qquicktimeline QUICKTESTS += \ pointerhandlers \ |