From b855240b782395f94315f43ea3e7e182299fac48 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Thu, 16 Feb 2012 14:43:03 +1000 Subject: Rename QDeclarative symbols to QQuick and QQml Symbols beginning with QDeclarative are already exported by the quick1 module. Users can apply the bin/rename-qtdeclarative-symbols.sh script to modify client code using the previous names of the renamed symbols. Task-number: QTBUG-23737 Change-Id: Ifaa482663767634931e8711a8e9bf6e404859e66 Reviewed-by: Martin Jones --- src/imports/folderlistmodel/folderlistmodel.pro | 8 +- src/imports/folderlistmodel/plugin.cpp | 12 +- .../qdeclarativefolderlistmodel.cpp | 529 --------- .../folderlistmodel/qdeclarativefolderlistmodel.h | 159 --- .../folderlistmodel/qquickfolderlistmodel.cpp | 529 +++++++++ .../folderlistmodel/qquickfolderlistmodel.h | 159 +++ src/imports/localstorage/localstorage.pro | 4 +- src/imports/localstorage/plugin.cpp | 46 +- src/imports/qimportbase.pri | 2 +- src/imports/qtquick2/plugin.cpp | 8 +- src/imports/qtquick2/qtquick2.pro | 4 +- src/imports/testlib/main.cpp | 28 +- src/imports/testlib/signalspy.h | 6 +- src/imports/testlib/testcase.h | 6 +- src/imports/testlib/testlib.pro | 6 +- src/imports/xmllistmodel/plugin.cpp | 14 +- .../xmllistmodel/qdeclarativexmllistmodel.cpp | 1160 -------------------- .../xmllistmodel/qdeclarativexmllistmodel_p.h | 212 ---- src/imports/xmllistmodel/qqmlxmllistmodel.cpp | 1160 ++++++++++++++++++++ src/imports/xmllistmodel/qqmlxmllistmodel_p.h | 212 ++++ src/imports/xmllistmodel/xmllistmodel.pro | 8 +- 21 files changed, 2136 insertions(+), 2136 deletions(-) delete mode 100644 src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp delete mode 100644 src/imports/folderlistmodel/qdeclarativefolderlistmodel.h create mode 100644 src/imports/folderlistmodel/qquickfolderlistmodel.cpp create mode 100644 src/imports/folderlistmodel/qquickfolderlistmodel.h delete mode 100644 src/imports/xmllistmodel/qdeclarativexmllistmodel.cpp delete mode 100644 src/imports/xmllistmodel/qdeclarativexmllistmodel_p.h create mode 100644 src/imports/xmllistmodel/qqmlxmllistmodel.cpp create mode 100644 src/imports/xmllistmodel/qqmlxmllistmodel_p.h (limited to 'src/imports') diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro index 26efc654b8..b4cfcea495 100644 --- a/src/imports/folderlistmodel/folderlistmodel.pro +++ b/src/imports/folderlistmodel/folderlistmodel.pro @@ -2,12 +2,12 @@ TARGET = qmlfolderlistmodelplugin TARGETPATH = Qt/labs/folderlistmodel include(../qimportbase.pri) -QT += widgets declarative +QT += widgets qml -SOURCES += qdeclarativefolderlistmodel.cpp plugin.cpp -HEADERS += qdeclarativefolderlistmodel.h +SOURCES += qquickfolderlistmodel.cpp plugin.cpp +HEADERS += qquickfolderlistmodel.h -DESTDIR = $$QT.declarative.imports/$$TARGETPATH +DESTDIR = $$QT.qml.imports/$$TARGETPATH target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir diff --git a/src/imports/folderlistmodel/plugin.cpp b/src/imports/folderlistmodel/plugin.cpp index 48d7b5b7cb..78fc230fdc 100644 --- a/src/imports/folderlistmodel/plugin.cpp +++ b/src/imports/folderlistmodel/plugin.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,15 +39,15 @@ ** ****************************************************************************/ -#include -#include +#include +#include -#include "qdeclarativefolderlistmodel.h" +#include "qquickfolderlistmodel.h" QT_BEGIN_NAMESPACE //![class decl] -class QmlFolderListModelPlugin : public QDeclarativeExtensionPlugin +class QmlFolderListModelPlugin : public QQmlExtensionPlugin { Q_OBJECT public: @@ -55,7 +55,7 @@ public: { Q_ASSERT(QLatin1String(uri) == QLatin1String("Qt.labs.folderlistmodel")); #ifndef QT_NO_DIRMODEL - qmlRegisterType(uri,1,0,"FolderListModel"); + qmlRegisterType(uri,1,0,"FolderListModel"); #endif } }; diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp deleted file mode 100644 index 870479afad..0000000000 --- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.cpp +++ /dev/null @@ -1,529 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -//![code] -#include "qdeclarativefolderlistmodel.h" -#include -#include -#include - -#ifndef QT_NO_DIRMODEL - -QT_BEGIN_NAMESPACE - -class QDeclarativeFolderListModelPrivate -{ -public: - QDeclarativeFolderListModelPrivate() - : sortField(QDeclarativeFolderListModel::Name), sortReversed(false), count(0), showDirs(true), showDots(false), showOnlyReadable(false), insideRefresh(false) { - nameFilters << QLatin1String("*"); - } - - void updateSorting() { - QDir::SortFlags flags = 0; - switch(sortField) { - case QDeclarativeFolderListModel::Unsorted: - flags |= QDir::Unsorted; - break; - case QDeclarativeFolderListModel::Name: - flags |= QDir::Name; - break; - case QDeclarativeFolderListModel::Time: - flags |= QDir::Time; - break; - case QDeclarativeFolderListModel::Size: - flags |= QDir::Size; - break; - case QDeclarativeFolderListModel::Type: - flags |= QDir::Type; - break; - } - - if (sortReversed) - flags |= QDir::Reversed; - - model.setSorting(flags); - } - - QDirModel model; - QUrl folder; - QStringList nameFilters; - QModelIndex folderIndex; - QDeclarativeFolderListModel::SortField sortField; - bool sortReversed; - int count; - bool showDirs; - bool showDots; - bool showOnlyReadable; - bool insideRefresh; -}; - -/*! - \qmlclass FolderListModel QDeclarativeFolderListModel - \ingroup qml-working-with-data - \brief The FolderListModel provides a model of the contents of a file system folder. - - FolderListModel provides access to information about the contents of a folder - in the local file system, exposing a list of files to views and other data components. - - \note This type is made available by importing the \c Qt.labs.folderlistmodel module. - \e{Elements in the Qt.labs module are not guaranteed to remain compatible - in future versions.} - - \bold{import Qt.labs.folderlistmodel 1.0} - - The \l folder property specifies the folder to access. Information about the - files and directories in the folder is supplied via the model's interface. - Components access names and paths via the following roles: - - \list - \o fileName - \o filePath - \endlist - - Additionally a file entry can be differentiated from a folder entry via the - isFolder() method. - - \section1 Filtering - - Various properties can be set to filter the number of files and directories - exposed by the model. - - The \l nameFilters property can be set to contain a list of wildcard filters - that are applied to names of files and directories, causing only those that - match the filters to be exposed. - - Directories can be included or excluded using the \l showDirs property, and - navigation directories can also be excluded by setting the \l showDotAndDotDot - property to false. - - It is sometimes useful to limit the files and directories exposed to those - that the user can access. The \l showOnlyReadable property can be set to - enable this feature. - - \section1 Example Usage - - The following example shows a FolderListModel being used to provide a list - of QML files in a \l ListView: - - \snippet doc/src/snippets/declarative/folderlistmodel.qml 0 - - \section1 Path Separators - - Qt uses "/" as a universal directory separator in the same way that "/" is - used as a path separator in URLs. If you always use "/" as a directory - separator, Qt will translate your paths to conform to the underlying - operating system. - - \sa {QML Data Models} -*/ - -QDeclarativeFolderListModel::QDeclarativeFolderListModel(QObject *parent) - : QAbstractListModel(parent) -{ - QHash roles; - roles[FileNameRole] = "fileName"; - roles[FilePathRole] = "filePath"; - setRoleNames(roles); - - d = new QDeclarativeFolderListModelPrivate; - d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); - connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) - , this, SLOT(inserted(const QModelIndex&,int,int))); - connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) - , this, SLOT(removed(const QModelIndex&,int,int))); - connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) - , this, SLOT(handleDataChanged(const QModelIndex&,const QModelIndex&))); - connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); - connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); -} - -QDeclarativeFolderListModel::~QDeclarativeFolderListModel() -{ - delete d; -} - -QVariant QDeclarativeFolderListModel::data(const QModelIndex &index, int role) const -{ - QVariant rv; - QModelIndex modelIndex = d->model.index(index.row(), 0, d->folderIndex); - if (modelIndex.isValid()) { - if (role == FileNameRole) - rv = d->model.data(modelIndex, QDirModel::FileNameRole).toString(); - else if (role == FilePathRole) - rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); - } - return rv; -} - -/*! - \qmlproperty int FolderListModel::count - - Returns the number of items in the current folder that match the - filter criteria. -*/ -int QDeclarativeFolderListModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return d->count; -} - -/*! - \qmlproperty string FolderListModel::folder - - The \a folder property holds a URL for the folder that the model is - currently providing. - - The value is a URL expressed as a string, and must be a \c file: or \c qrc: - URL, or a relative URL. - - By default, the value is an invalid URL. -*/ -QUrl QDeclarativeFolderListModel::folder() const -{ - return d->folder; -} - -void QDeclarativeFolderListModel::setFolder(const QUrl &folder) -{ - if (folder == d->folder) - return; - - QModelIndex index = d->model.index(folder.toLocalFile()); // This can modify the filtering rules. - if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) { - d->folder = folder; - QMetaObject::invokeMethod(this, "resetFiltering", Qt::QueuedConnection); // resetFiltering will invoke refresh(). - emit folderChanged(); - } -} - -void QDeclarativeFolderListModel::resetFiltering() -{ - // ensure that we reset the filtering rules, because the QDirModel::index() - // function isn't quite as const as it claims to be. - QDir::Filters filt = d->model.filter(); - - if (d->showDirs) - filt |= (QDir::AllDirs | QDir::Drives); - else - filt &= ~(QDir::AllDirs | QDir::Drives); - - if (d->showDots) - filt &= ~QDir::NoDotAndDotDot; - else - filt |= QDir::NoDotAndDotDot; - - if (d->showOnlyReadable) - filt |= QDir::Readable; - else - filt &= ~QDir::Readable; - - d->model.setFilter(filt); // this causes a refresh(). -} - -/*! - \qmlproperty url FolderListModel::parentFolder - - Returns the URL of the parent of of the current \l folder. -*/ -QUrl QDeclarativeFolderListModel::parentFolder() const -{ - QString localFile = d->folder.toLocalFile(); - if (!localFile.isEmpty()) { - QDir dir(localFile); -#if defined(Q_OS_WIN) - if (dir.isRoot()) - dir.setPath(""); - else -#endif - dir.cdUp(); - localFile = dir.path(); - } else { - int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); - if (pos == -1) - return QUrl(); - localFile = d->folder.path().left(pos); - } - return QUrl::fromLocalFile(localFile); -} - -/*! - \qmlproperty list FolderListModel::nameFilters - - The \a nameFilters property contains a list of file name filters. - The filters may include the ? and * wildcards. - - The example below filters on PNG and JPEG files: - - \qml - FolderListModel { - nameFilters: [ "*.png", "*.jpg" ] - } - \endqml - - \note Directories are not excluded by filters. -*/ -QStringList QDeclarativeFolderListModel::nameFilters() const -{ - return d->nameFilters; -} - -void QDeclarativeFolderListModel::setNameFilters(const QStringList &filters) -{ - d->nameFilters = filters; - d->model.setNameFilters(d->nameFilters); -} - -void QDeclarativeFolderListModel::classBegin() -{ -} - -void QDeclarativeFolderListModel::componentComplete() -{ - if (!d->folder.isValid() || d->folder.toLocalFile().isEmpty() || !QDir().exists(d->folder.toLocalFile())) - setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); - - if (!d->folderIndex.isValid()) - QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); -} - -/*! - \qmlproperty enumeration FolderListModel::sortField - - The \a sortField property contains field to use for sorting. sortField - may be one of: - \list - \o Unsorted - no sorting is applied. The order is system default. - \o Name - sort by filename - \o Time - sort by time modified - \o Size - sort by file size - \o Type - sort by file type (extension) - \endlist - - \sa sortReversed -*/ -QDeclarativeFolderListModel::SortField QDeclarativeFolderListModel::sortField() const -{ - return d->sortField; -} - -void QDeclarativeFolderListModel::setSortField(SortField field) -{ - if (field != d->sortField) { - d->sortField = field; - d->updateSorting(); - } -} - -/*! - \qmlproperty bool FolderListModel::sortReversed - - If set to true, reverses the sort order. The default is false. - - \sa sortField -*/ -bool QDeclarativeFolderListModel::sortReversed() const -{ - return d->sortReversed; -} - -void QDeclarativeFolderListModel::setSortReversed(bool rev) -{ - if (rev != d->sortReversed) { - d->sortReversed = rev; - d->updateSorting(); - } -} - -/*! - \qmlmethod bool FolderListModel::isFolder(int index) - - Returns true if the entry \a index is a folder; otherwise - returns false. -*/ -bool QDeclarativeFolderListModel::isFolder(int index) const -{ - if (index != -1) { - QModelIndex idx = d->model.index(index, 0, d->folderIndex); - if (idx.isValid()) - return d->model.isDir(idx); - } - return false; -} - -void QDeclarativeFolderListModel::refresh() -{ - if (d->insideRefresh) - return; - d->insideRefresh = true; - - d->folderIndex = QModelIndex(); - if (d->count) { - emit beginRemoveRows(QModelIndex(), 0, d->count-1); - d->count = 0; - emit endRemoveRows(); - } - - d->folderIndex = d->model.index(d->folder.toLocalFile()); - int newcount = d->model.rowCount(d->folderIndex); - if (newcount) { - emit beginInsertRows(QModelIndex(), 0, newcount-1); - d->count = newcount; - emit endInsertRows(); - } - - d->insideRefresh = false; // finished refreshing. -} - -void QDeclarativeFolderListModel::inserted(const QModelIndex &index, int start, int end) -{ - if (index == d->folderIndex) { - emit beginInsertRows(QModelIndex(), start, end); - d->count = d->model.rowCount(d->folderIndex); - emit endInsertRows(); - } -} - -void QDeclarativeFolderListModel::removed(const QModelIndex &index, int start, int end) -{ - if (index == d->folderIndex) { - emit beginRemoveRows(QModelIndex(), start, end); - d->count = d->model.rowCount(d->folderIndex); - emit endRemoveRows(); - } -} - -void QDeclarativeFolderListModel::handleDataChanged(const QModelIndex &start, const QModelIndex &end) -{ - if (start.parent() == d->folderIndex) - emit dataChanged(index(start.row(),0), index(end.row(),0)); -} - -/*! - \qmlproperty bool FolderListModel::showDirs - - If true, directories are included in the model; otherwise only files - are included. - - By default, this property is true. - - Note that the nameFilters are not applied to directories. - - \sa showDotAndDotDot -*/ -bool QDeclarativeFolderListModel::showDirs() const -{ - return d->model.filter() & QDir::AllDirs; -} - -void QDeclarativeFolderListModel::setShowDirs(bool on) -{ - if (!(d->model.filter() & QDir::AllDirs) == !on) - return; - if (on) { - d->showDirs = true; - d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); - } else { - d->showDirs = false; - d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); - } -} - -/*! - \qmlproperty bool FolderListModel::showDotAndDotDot - - If true, the "." and ".." directories are included in the model; otherwise - they are excluded. - - By default, this property is false. - - \sa showDirs -*/ -bool QDeclarativeFolderListModel::showDotAndDotDot() const -{ - return !(d->model.filter() & QDir::NoDotAndDotDot); -} - -void QDeclarativeFolderListModel::setShowDotAndDotDot(bool on) -{ - if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) - return; - if (on) { - d->showDots = true; - d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); - } else { - d->showDots = false; - d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); - } -} - -/*! - \qmlproperty bool FolderListModel::showOnlyReadable - - If true, only readable files and directories are shown; otherwise all files - and directories are shown. - - By default, this property is false. - - \sa showDirs -*/ -bool QDeclarativeFolderListModel::showOnlyReadable() const -{ - return d->model.filter() & QDir::Readable; -} - -void QDeclarativeFolderListModel::setShowOnlyReadable(bool on) -{ - if (!(d->model.filter() & QDir::Readable) == !on) - return; - if (on) { - d->showOnlyReadable = true; - d->model.setFilter(d->model.filter() | QDir::Readable); - } else { - d->showOnlyReadable = false; - d->model.setFilter(d->model.filter() & ~QDir::Readable); - } -} - -//![code] -QT_END_NAMESPACE - -#endif // QT_NO_DIRMODEL diff --git a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h b/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h deleted file mode 100644 index 5f9cb0e81a..0000000000 --- a/src/imports/folderlistmodel/qdeclarativefolderlistmodel.h +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the examples of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEFOLDERLISTMODEL_H -#define QDECLARATIVEFOLDERLISTMODEL_H - -#include -#include -#include -#include - -#ifndef QT_NO_DIRMODEL - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - - -class QDeclarativeContext; -class QModelIndex; - -class QDeclarativeFolderListModelPrivate; - -//![class begin] -class QDeclarativeFolderListModel : public QAbstractListModel, public QDeclarativeParserStatus -{ - Q_OBJECT - Q_INTERFACES(QDeclarativeParserStatus) -//![class begin] - -//![class props] - Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) - Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) - Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) - Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) - Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) - Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) - Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) - Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) - Q_PROPERTY(int count READ count) -//![class props] - -//![abslistmodel] -public: - QDeclarativeFolderListModel(QObject *parent = 0); - ~QDeclarativeFolderListModel(); - - enum Roles { FileNameRole = Qt::UserRole+1, FilePathRole = Qt::UserRole+2 }; - - int rowCount(const QModelIndex &parent) const; - QVariant data(const QModelIndex &index, int role) const; -//![abslistmodel] - -//![count] - int count() const { return rowCount(QModelIndex()); } -//![count] - -//![prop funcs] - QUrl folder() const; - void setFolder(const QUrl &folder); - - QUrl parentFolder() const; - - QStringList nameFilters() const; - void setNameFilters(const QStringList &filters); - - enum SortField { Unsorted, Name, Time, Size, Type }; - SortField sortField() const; - void setSortField(SortField field); - Q_ENUMS(SortField) - - bool sortReversed() const; - void setSortReversed(bool rev); - - bool showDirs() const; - void setShowDirs(bool); - bool showDotAndDotDot() const; - void setShowDotAndDotDot(bool); - bool showOnlyReadable() const; - void setShowOnlyReadable(bool); -//![prop funcs] - -//![isfolder] - Q_INVOKABLE bool isFolder(int index) const; -//![isfolder] - -//![parserstatus] - virtual void classBegin(); - virtual void componentComplete(); -//![parserstatus] - -//![notifier] -Q_SIGNALS: - void folderChanged(); -//![notifier] - -//![class end] -private Q_SLOTS: - void refresh(); - void resetFiltering(); - void inserted(const QModelIndex &index, int start, int end); - void removed(const QModelIndex &index, int start, int end); - void handleDataChanged(const QModelIndex &start, const QModelIndex &end); - -private: - Q_DISABLE_COPY(QDeclarativeFolderListModel) - QDeclarativeFolderListModelPrivate *d; -}; -//![class end] - -QT_END_NAMESPACE - -//![qml decl] -QML_DECLARE_TYPE(QDeclarativeFolderListModel) -//![qml decl] - -QT_END_HEADER - -#endif // QT_NO_DIRMODEL - -#endif // QDECLARATIVEFOLDERLISTMODEL_H diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp new file mode 100644 index 0000000000..5621622cca --- /dev/null +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp @@ -0,0 +1,529 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//![code] +#include "qquickfolderlistmodel.h" +#include +#include +#include + +#ifndef QT_NO_DIRMODEL + +QT_BEGIN_NAMESPACE + +class QQuickFolderListModelPrivate +{ +public: + QQuickFolderListModelPrivate() + : sortField(QQuickFolderListModel::Name), sortReversed(false), count(0), showDirs(true), showDots(false), showOnlyReadable(false), insideRefresh(false) { + nameFilters << QLatin1String("*"); + } + + void updateSorting() { + QDir::SortFlags flags = 0; + switch(sortField) { + case QQuickFolderListModel::Unsorted: + flags |= QDir::Unsorted; + break; + case QQuickFolderListModel::Name: + flags |= QDir::Name; + break; + case QQuickFolderListModel::Time: + flags |= QDir::Time; + break; + case QQuickFolderListModel::Size: + flags |= QDir::Size; + break; + case QQuickFolderListModel::Type: + flags |= QDir::Type; + break; + } + + if (sortReversed) + flags |= QDir::Reversed; + + model.setSorting(flags); + } + + QDirModel model; + QUrl folder; + QStringList nameFilters; + QModelIndex folderIndex; + QQuickFolderListModel::SortField sortField; + bool sortReversed; + int count; + bool showDirs; + bool showDots; + bool showOnlyReadable; + bool insideRefresh; +}; + +/*! + \qmlclass FolderListModel QQuickFolderListModel + \ingroup qml-working-with-data + \brief The FolderListModel provides a model of the contents of a file system folder. + + FolderListModel provides access to information about the contents of a folder + in the local file system, exposing a list of files to views and other data components. + + \note This type is made available by importing the \c Qt.labs.folderlistmodel module. + \e{Elements in the Qt.labs module are not guaranteed to remain compatible + in future versions.} + + \bold{import Qt.labs.folderlistmodel 1.0} + + The \l folder property specifies the folder to access. Information about the + files and directories in the folder is supplied via the model's interface. + Components access names and paths via the following roles: + + \list + \o fileName + \o filePath + \endlist + + Additionally a file entry can be differentiated from a folder entry via the + isFolder() method. + + \section1 Filtering + + Various properties can be set to filter the number of files and directories + exposed by the model. + + The \l nameFilters property can be set to contain a list of wildcard filters + that are applied to names of files and directories, causing only those that + match the filters to be exposed. + + Directories can be included or excluded using the \l showDirs property, and + navigation directories can also be excluded by setting the \l showDotAndDotDot + property to false. + + It is sometimes useful to limit the files and directories exposed to those + that the user can access. The \l showOnlyReadable property can be set to + enable this feature. + + \section1 Example Usage + + The following example shows a FolderListModel being used to provide a list + of QML files in a \l ListView: + + \snippet doc/src/snippets/qml/folderlistmodel.qml 0 + + \section1 Path Separators + + Qt uses "/" as a universal directory separator in the same way that "/" is + used as a path separator in URLs. If you always use "/" as a directory + separator, Qt will translate your paths to conform to the underlying + operating system. + + \sa {QML Data Models} +*/ + +QQuickFolderListModel::QQuickFolderListModel(QObject *parent) + : QAbstractListModel(parent) +{ + QHash roles; + roles[FileNameRole] = "fileName"; + roles[FilePathRole] = "filePath"; + setRoleNames(roles); + + d = new QQuickFolderListModelPrivate; + d->model.setFilter(QDir::AllDirs | QDir::Files | QDir::Drives | QDir::NoDotAndDotDot); + connect(&d->model, SIGNAL(rowsInserted(const QModelIndex&,int,int)) + , this, SLOT(inserted(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(rowsRemoved(const QModelIndex&,int,int)) + , this, SLOT(removed(const QModelIndex&,int,int))); + connect(&d->model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)) + , this, SLOT(handleDataChanged(const QModelIndex&,const QModelIndex&))); + connect(&d->model, SIGNAL(modelReset()), this, SLOT(refresh())); + connect(&d->model, SIGNAL(layoutChanged()), this, SLOT(refresh())); +} + +QQuickFolderListModel::~QQuickFolderListModel() +{ + delete d; +} + +QVariant QQuickFolderListModel::data(const QModelIndex &index, int role) const +{ + QVariant rv; + QModelIndex modelIndex = d->model.index(index.row(), 0, d->folderIndex); + if (modelIndex.isValid()) { + if (role == FileNameRole) + rv = d->model.data(modelIndex, QDirModel::FileNameRole).toString(); + else if (role == FilePathRole) + rv = QUrl::fromLocalFile(d->model.data(modelIndex, QDirModel::FilePathRole).toString()); + } + return rv; +} + +/*! + \qmlproperty int FolderListModel::count + + Returns the number of items in the current folder that match the + filter criteria. +*/ +int QQuickFolderListModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return d->count; +} + +/*! + \qmlproperty string FolderListModel::folder + + The \a folder property holds a URL for the folder that the model is + currently providing. + + The value is a URL expressed as a string, and must be a \c file: or \c qrc: + URL, or a relative URL. + + By default, the value is an invalid URL. +*/ +QUrl QQuickFolderListModel::folder() const +{ + return d->folder; +} + +void QQuickFolderListModel::setFolder(const QUrl &folder) +{ + if (folder == d->folder) + return; + + QModelIndex index = d->model.index(folder.toLocalFile()); // This can modify the filtering rules. + if ((index.isValid() && d->model.isDir(index)) || folder.toLocalFile().isEmpty()) { + d->folder = folder; + QMetaObject::invokeMethod(this, "resetFiltering", Qt::QueuedConnection); // resetFiltering will invoke refresh(). + emit folderChanged(); + } +} + +void QQuickFolderListModel::resetFiltering() +{ + // ensure that we reset the filtering rules, because the QDirModel::index() + // function isn't quite as const as it claims to be. + QDir::Filters filt = d->model.filter(); + + if (d->showDirs) + filt |= (QDir::AllDirs | QDir::Drives); + else + filt &= ~(QDir::AllDirs | QDir::Drives); + + if (d->showDots) + filt &= ~QDir::NoDotAndDotDot; + else + filt |= QDir::NoDotAndDotDot; + + if (d->showOnlyReadable) + filt |= QDir::Readable; + else + filt &= ~QDir::Readable; + + d->model.setFilter(filt); // this causes a refresh(). +} + +/*! + \qmlproperty url FolderListModel::parentFolder + + Returns the URL of the parent of of the current \l folder. +*/ +QUrl QQuickFolderListModel::parentFolder() const +{ + QString localFile = d->folder.toLocalFile(); + if (!localFile.isEmpty()) { + QDir dir(localFile); +#if defined(Q_OS_WIN) + if (dir.isRoot()) + dir.setPath(""); + else +#endif + dir.cdUp(); + localFile = dir.path(); + } else { + int pos = d->folder.path().lastIndexOf(QLatin1Char('/')); + if (pos == -1) + return QUrl(); + localFile = d->folder.path().left(pos); + } + return QUrl::fromLocalFile(localFile); +} + +/*! + \qmlproperty list FolderListModel::nameFilters + + The \a nameFilters property contains a list of file name filters. + The filters may include the ? and * wildcards. + + The example below filters on PNG and JPEG files: + + \qml + FolderListModel { + nameFilters: [ "*.png", "*.jpg" ] + } + \endqml + + \note Directories are not excluded by filters. +*/ +QStringList QQuickFolderListModel::nameFilters() const +{ + return d->nameFilters; +} + +void QQuickFolderListModel::setNameFilters(const QStringList &filters) +{ + d->nameFilters = filters; + d->model.setNameFilters(d->nameFilters); +} + +void QQuickFolderListModel::classBegin() +{ +} + +void QQuickFolderListModel::componentComplete() +{ + if (!d->folder.isValid() || d->folder.toLocalFile().isEmpty() || !QDir().exists(d->folder.toLocalFile())) + setFolder(QUrl(QLatin1String("file://")+QDir::currentPath())); + + if (!d->folderIndex.isValid()) + QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection); +} + +/*! + \qmlproperty enumeration FolderListModel::sortField + + The \a sortField property contains field to use for sorting. sortField + may be one of: + \list + \o Unsorted - no sorting is applied. The order is system default. + \o Name - sort by filename + \o Time - sort by time modified + \o Size - sort by file size + \o Type - sort by file type (extension) + \endlist + + \sa sortReversed +*/ +QQuickFolderListModel::SortField QQuickFolderListModel::sortField() const +{ + return d->sortField; +} + +void QQuickFolderListModel::setSortField(SortField field) +{ + if (field != d->sortField) { + d->sortField = field; + d->updateSorting(); + } +} + +/*! + \qmlproperty bool FolderListModel::sortReversed + + If set to true, reverses the sort order. The default is false. + + \sa sortField +*/ +bool QQuickFolderListModel::sortReversed() const +{ + return d->sortReversed; +} + +void QQuickFolderListModel::setSortReversed(bool rev) +{ + if (rev != d->sortReversed) { + d->sortReversed = rev; + d->updateSorting(); + } +} + +/*! + \qmlmethod bool FolderListModel::isFolder(int index) + + Returns true if the entry \a index is a folder; otherwise + returns false. +*/ +bool QQuickFolderListModel::isFolder(int index) const +{ + if (index != -1) { + QModelIndex idx = d->model.index(index, 0, d->folderIndex); + if (idx.isValid()) + return d->model.isDir(idx); + } + return false; +} + +void QQuickFolderListModel::refresh() +{ + if (d->insideRefresh) + return; + d->insideRefresh = true; + + d->folderIndex = QModelIndex(); + if (d->count) { + emit beginRemoveRows(QModelIndex(), 0, d->count-1); + d->count = 0; + emit endRemoveRows(); + } + + d->folderIndex = d->model.index(d->folder.toLocalFile()); + int newcount = d->model.rowCount(d->folderIndex); + if (newcount) { + emit beginInsertRows(QModelIndex(), 0, newcount-1); + d->count = newcount; + emit endInsertRows(); + } + + d->insideRefresh = false; // finished refreshing. +} + +void QQuickFolderListModel::inserted(const QModelIndex &index, int start, int end) +{ + if (index == d->folderIndex) { + emit beginInsertRows(QModelIndex(), start, end); + d->count = d->model.rowCount(d->folderIndex); + emit endInsertRows(); + } +} + +void QQuickFolderListModel::removed(const QModelIndex &index, int start, int end) +{ + if (index == d->folderIndex) { + emit beginRemoveRows(QModelIndex(), start, end); + d->count = d->model.rowCount(d->folderIndex); + emit endRemoveRows(); + } +} + +void QQuickFolderListModel::handleDataChanged(const QModelIndex &start, const QModelIndex &end) +{ + if (start.parent() == d->folderIndex) + emit dataChanged(index(start.row(),0), index(end.row(),0)); +} + +/*! + \qmlproperty bool FolderListModel::showDirs + + If true, directories are included in the model; otherwise only files + are included. + + By default, this property is true. + + Note that the nameFilters are not applied to directories. + + \sa showDotAndDotDot +*/ +bool QQuickFolderListModel::showDirs() const +{ + return d->model.filter() & QDir::AllDirs; +} + +void QQuickFolderListModel::setShowDirs(bool on) +{ + if (!(d->model.filter() & QDir::AllDirs) == !on) + return; + if (on) { + d->showDirs = true; + d->model.setFilter(d->model.filter() | QDir::AllDirs | QDir::Drives); + } else { + d->showDirs = false; + d->model.setFilter(d->model.filter() & ~(QDir::AllDirs | QDir::Drives)); + } +} + +/*! + \qmlproperty bool FolderListModel::showDotAndDotDot + + If true, the "." and ".." directories are included in the model; otherwise + they are excluded. + + By default, this property is false. + + \sa showDirs +*/ +bool QQuickFolderListModel::showDotAndDotDot() const +{ + return !(d->model.filter() & QDir::NoDotAndDotDot); +} + +void QQuickFolderListModel::setShowDotAndDotDot(bool on) +{ + if (!(d->model.filter() & QDir::NoDotAndDotDot) == on) + return; + if (on) { + d->showDots = true; + d->model.setFilter(d->model.filter() & ~QDir::NoDotAndDotDot); + } else { + d->showDots = false; + d->model.setFilter(d->model.filter() | QDir::NoDotAndDotDot); + } +} + +/*! + \qmlproperty bool FolderListModel::showOnlyReadable + + If true, only readable files and directories are shown; otherwise all files + and directories are shown. + + By default, this property is false. + + \sa showDirs +*/ +bool QQuickFolderListModel::showOnlyReadable() const +{ + return d->model.filter() & QDir::Readable; +} + +void QQuickFolderListModel::setShowOnlyReadable(bool on) +{ + if (!(d->model.filter() & QDir::Readable) == !on) + return; + if (on) { + d->showOnlyReadable = true; + d->model.setFilter(d->model.filter() | QDir::Readable); + } else { + d->showOnlyReadable = false; + d->model.setFilter(d->model.filter() & ~QDir::Readable); + } +} + +//![code] +QT_END_NAMESPACE + +#endif // QT_NO_DIRMODEL diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h new file mode 100644 index 0000000000..10af7c8075 --- /dev/null +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKFOLDERLISTMODEL_H +#define QQUICKFOLDERLISTMODEL_H + +#include +#include +#include +#include + +#ifndef QT_NO_DIRMODEL + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QQmlContext; +class QModelIndex; + +class QQuickFolderListModelPrivate; + +//![class begin] +class QQuickFolderListModel : public QAbstractListModel, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) +//![class begin] + +//![class props] + Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged) + Q_PROPERTY(QUrl parentFolder READ parentFolder NOTIFY folderChanged) + Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters) + Q_PROPERTY(SortField sortField READ sortField WRITE setSortField) + Q_PROPERTY(bool sortReversed READ sortReversed WRITE setSortReversed) + Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) + Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) + Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) + Q_PROPERTY(int count READ count) +//![class props] + +//![abslistmodel] +public: + QQuickFolderListModel(QObject *parent = 0); + ~QQuickFolderListModel(); + + enum Roles { FileNameRole = Qt::UserRole+1, FilePathRole = Qt::UserRole+2 }; + + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; +//![abslistmodel] + +//![count] + int count() const { return rowCount(QModelIndex()); } +//![count] + +//![prop funcs] + QUrl folder() const; + void setFolder(const QUrl &folder); + + QUrl parentFolder() const; + + QStringList nameFilters() const; + void setNameFilters(const QStringList &filters); + + enum SortField { Unsorted, Name, Time, Size, Type }; + SortField sortField() const; + void setSortField(SortField field); + Q_ENUMS(SortField) + + bool sortReversed() const; + void setSortReversed(bool rev); + + bool showDirs() const; + void setShowDirs(bool); + bool showDotAndDotDot() const; + void setShowDotAndDotDot(bool); + bool showOnlyReadable() const; + void setShowOnlyReadable(bool); +//![prop funcs] + +//![isfolder] + Q_INVOKABLE bool isFolder(int index) const; +//![isfolder] + +//![parserstatus] + virtual void classBegin(); + virtual void componentComplete(); +//![parserstatus] + +//![notifier] +Q_SIGNALS: + void folderChanged(); +//![notifier] + +//![class end] +private Q_SLOTS: + void refresh(); + void resetFiltering(); + void inserted(const QModelIndex &index, int start, int end); + void removed(const QModelIndex &index, int start, int end); + void handleDataChanged(const QModelIndex &start, const QModelIndex &end); + +private: + Q_DISABLE_COPY(QQuickFolderListModel) + QQuickFolderListModelPrivate *d; +}; +//![class end] + +QT_END_NAMESPACE + +//![qml decl] +QML_DECLARE_TYPE(QQuickFolderListModel) +//![qml decl] + +QT_END_HEADER + +#endif // QT_NO_DIRMODEL + +#endif // QQUICKFOLDERLISTMODEL_H diff --git a/src/imports/localstorage/localstorage.pro b/src/imports/localstorage/localstorage.pro index 51a69aac4f..c54bc564d9 100644 --- a/src/imports/localstorage/localstorage.pro +++ b/src/imports/localstorage/localstorage.pro @@ -2,11 +2,11 @@ TARGET = qmllocalstorageplugin TARGETPATH = QtQuick/LocalStorage include(../qimportbase.pri) -QT += sql declarative declarative-private v8-private core-private +QT += sql qml qml-private v8-private core-private SOURCES += plugin.cpp -DESTDIR = $$QT.declarative.imports/$$TARGETPATH +DESTDIR = $$QT.qml.imports/$$TARGETPATH target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index dd747d0d09..77e68877d4 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -39,9 +39,9 @@ ** ****************************************************************************/ #include -#include -#include -#include +#include +#include +#include #include #include #include @@ -83,18 +83,18 @@ return; \ } -class QDeclarativeSqlDatabaseData : public QV8Engine::Deletable +class QQmlSqlDatabaseData : public QV8Engine::Deletable { public: - QDeclarativeSqlDatabaseData(QV8Engine *engine); - ~QDeclarativeSqlDatabaseData(); + QQmlSqlDatabaseData(QV8Engine *engine); + ~QQmlSqlDatabaseData(); v8::Persistent constructor; v8::Persistent queryConstructor; v8::Persistent rowsConstructor; }; -V8_DEFINE_EXTENSION(QDeclarativeSqlDatabaseData, databaseData) +V8_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData) class QV8SqlDatabaseResource : public QV8ObjectResource { @@ -167,7 +167,7 @@ static void qmlsqldatabase_rows_setForwardOnly(v8::Local /* property r->query.setForwardOnly(value->BooleanValue()); } -QDeclarativeSqlDatabaseData::~QDeclarativeSqlDatabaseData() +QQmlSqlDatabaseData::~QQmlSqlDatabaseData() { qPersistentDispose(constructor); qPersistentDispose(queryConstructor); @@ -239,14 +239,14 @@ static v8::Handle qmlsqldatabase_executeSql(const v8::Arguments& args QV8Engine *engine = r->engine; if (!r->inTransaction) - V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QDeclarativeEngine::tr("executeSql called outside transaction()")); + V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()")); QSqlDatabase db = r->database; QString sql = engine->toString(args[0]); if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) { - V8THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QDeclarativeEngine::tr("Read-only Transaction")); + V8THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction")); } QSqlQuery query(db); @@ -316,7 +316,7 @@ static v8::Handle qmlsqldatabase_changeVersion(const v8::Arguments& a v8::Handle callback = args[2]; if (from_version != r->version) - V8THROW_SQL(SQLEXCEPTION_VERSION_ERR, QDeclarativeEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version)); + V8THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version)); v8::Local instance = databaseData(engine)->queryConstructor->NewInstance(); QV8SqlDatabaseResource *r2 = new QV8SqlDatabaseResource(engine); @@ -341,7 +341,7 @@ static v8::Handle qmlsqldatabase_changeVersion(const v8::Arguments& a return v8::Handle(); } else if (!db.commit()) { db.rollback(); - V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed")); + V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed")); } else { ok = true; } @@ -369,7 +369,7 @@ static v8::Handle qmlsqldatabase_transaction_shared(const v8::Argumen QV8Engine *engine = r->engine; if (args.Length() == 0 || !args[0]->IsFunction()) - V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback")); + V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("transaction: missing callback")); QSqlDatabase db = r->database; v8::Handle callback = v8::Handle::Cast(args[0]); @@ -410,7 +410,7 @@ static v8::Handle qmlsqldatabase_read_transaction(const v8::Arguments return qmlsqldatabase_transaction_shared(args, true); } -QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine) +QQmlSqlDatabaseData::QQmlSqlDatabaseData(QV8Engine *engine) { { v8::Local ft = v8::FunctionTemplate::New(); @@ -460,7 +460,7 @@ through the data. These databases are user-specific and QML-specific, but accessible to all QML applications. They are stored in the \c Databases subdirectory -of QDeclarativeEngine::offlineStoragePath(), currently as SQLite databases. +of QQmlEngine::offlineStoragePath(), currently as SQLite databases. Database connections are automatically closed during Javascript garbage collection. @@ -549,7 +549,7 @@ public: ~QQuickLocalStorage() { } - Q_INVOKABLE void openDatabaseSync(QDeclarativeV8Function* args); + Q_INVOKABLE void openDatabaseSync(QQmlV8Function* args); }; /*! @@ -563,7 +563,7 @@ public: * \c callback is an optional parameter, which is invoked if the database has not yet been created. * \return the database object */ -void QQuickLocalStorage::openDatabaseSync(QDeclarativeV8Function *args) +void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args) { #ifndef QT_NO_SETTINGS QV8Engine *engine = args->engine(); @@ -592,7 +592,7 @@ void QQuickLocalStorage::openDatabaseSync(QDeclarativeV8Function *args) database = QSqlDatabase::database(dbid); version = ini.value(QLatin1String("Version")).toString(); if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty()) - V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR, QDeclarativeEngine::tr("SQL: database version mismatch")); + V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch")); } else { created = !QFile::exists(basename+QLatin1String(".sqlite")); database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); @@ -607,7 +607,7 @@ void QQuickLocalStorage::openDatabaseSync(QDeclarativeV8Function *args) } else { if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) { // Incompatible - V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch")); + V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch")); } version = ini.value(QLatin1String("Version")).toString(); } @@ -639,7 +639,7 @@ void QQuickLocalStorage::openDatabaseSync(QDeclarativeV8Function *args) #endif // QT_NO_SETTINGS } -static QObject *module_api_factory(QDeclarativeEngine *engine, QJSEngine *scriptEngine) +static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine) { Q_UNUSED(engine) Q_UNUSED(scriptEngine) @@ -648,11 +648,11 @@ static QObject *module_api_factory(QDeclarativeEngine *engine, QJSEngine *script return api; } -class QDeclarativeLocalStoragePlugin : public QDeclarativeExtensionPlugin +class QQmlLocalStoragePlugin : public QQmlExtensionPlugin { Q_OBJECT public: - QDeclarativeLocalStoragePlugin() + QQmlLocalStoragePlugin() { } @@ -665,4 +665,4 @@ public: #include "plugin.moc" -Q_EXPORT_PLUGIN2(plugin, QDeclarativeLocalStoragePlugin); +Q_EXPORT_PLUGIN2(plugin, QQmlLocalStoragePlugin); diff --git a/src/imports/qimportbase.pri b/src/imports/qimportbase.pri index 110d145e94..ab54e4b1b9 100644 --- a/src/imports/qimportbase.pri +++ b/src/imports/qimportbase.pri @@ -14,7 +14,7 @@ isEmpty(TARGET) { QMLDIRFILE = $${_PRO_FILE_PWD_}/qmldir copy2build.input = QMLDIRFILE -copy2build.output = $$QT.declarative.imports/$$TARGETPATH/qmldir +copy2build.output = $$QT.qml.imports/$$TARGETPATH/qmldir !contains(TEMPLATE_PREFIX, vc):copy2build.variable_out = PRE_TARGETDEPS copy2build.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT} copy2build.name = COPY ${QMAKE_FILE_IN} diff --git a/src/imports/qtquick2/plugin.cpp b/src/imports/qtquick2/plugin.cpp index 808d5196b2..2cb70a4fd3 100644 --- a/src/imports/qtquick2/plugin.cpp +++ b/src/imports/qtquick2/plugin.cpp @@ -39,23 +39,23 @@ ** ****************************************************************************/ -#include +#include #include QT_BEGIN_NAMESPACE //![class decl] -class QtQuick2Plugin : public QDeclarativeExtensionPlugin +class QtQuick2Plugin : public QQmlExtensionPlugin { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QDeclarativeExtensionInterface/1.0") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") public: virtual void registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick")); Q_UNUSED(uri); - QDeclarativeQtQuick2Module::defineModule(); + QQmlQtQuick2Module::defineModule(); } }; //![class decl] diff --git a/src/imports/qtquick2/qtquick2.pro b/src/imports/qtquick2/qtquick2.pro index 3f76abd87f..3a95c5fd21 100644 --- a/src/imports/qtquick2/qtquick2.pro +++ b/src/imports/qtquick2/qtquick2.pro @@ -5,12 +5,12 @@ include(../qimportbase.pri) SOURCES += \ plugin.cpp -QT += quick-private declarative-private +QT += quick-private qml-private OTHER_FILES += \ qmldir -DESTDIR = $$QT.declarative.imports/$$TARGETPATH +DESTDIR = $$QT.qml.imports/$$TARGETPATH target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 672de10639..8ab745a7d2 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -39,15 +39,15 @@ ** ****************************************************************************/ -#include -#include -#include -#include +#include +#include +#include +#include #include "QtQuickTest/private/quicktestresult_p.h" #include "QtQuickTest/private/quicktestevent_p.h" #include "private/qtestoptions_p.h" #include "QtQuick/qquickitem.h" -#include +#include QML_DECLARE_TYPE(QuickTestResult) QML_DECLARE_TYPE(QuickTestEvent) @@ -81,15 +81,15 @@ Q_SIGNALS: void wrapperChanged(); public Q_SLOTS: - QDeclarativeV8Handle typeName(const QVariant& v) const + QQmlV8Handle typeName(const QVariant& v) const { QString name(v.typeName()); //qDebug() << "type:" << name << " string value:" << v.toString() << " value:" << v; if (v.canConvert()) { - QDeclarativeType *type = 0; + QQmlType *type = 0; const QMetaObject *mo = v.value()->metaObject(); while (!type && mo) { - type = QDeclarativeMetaType::qmlType(mo); + type = QQmlMetaType::qmlType(mo); mo = mo->superClass(); } if (type) { @@ -97,22 +97,22 @@ public Q_SLOTS: } } - return QDeclarativeV8Handle::fromHandle(v8::String::New(name.toUtf8())); + return QQmlV8Handle::fromHandle(v8::String::New(name.toUtf8())); } bool compare(const QVariant& act, const QVariant& exp) const { return act == exp; } - QDeclarativeV8Handle callerFile(int frameIndex = 0) const + QQmlV8Handle callerFile(int frameIndex = 0) const { v8::Local stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); int count = stacks->GetFrameCount(); if (count >= frameIndex + 1) { v8::Local frame = stacks->GetFrame(frameIndex + 1); - return QDeclarativeV8Handle::fromHandle(frame->GetScriptNameOrSourceURL()); + return QQmlV8Handle::fromHandle(frame->GetScriptNameOrSourceURL()); } - return QDeclarativeV8Handle(); + return QQmlV8Handle(); } int callerLine(int frameIndex = 0) const { @@ -132,7 +132,7 @@ QML_DECLARE_TYPE(QuickTestUtil) QT_BEGIN_NAMESPACE -class QTestQmlModule : public QDeclarativeExtensionPlugin +class QTestQmlModule : public QQmlExtensionPlugin { Q_OBJECT public: @@ -144,7 +144,7 @@ public: qmlRegisterType(uri,1,0,"TestUtil"); } - void initializeEngine(QDeclarativeEngine *, const char *) + void initializeEngine(QQmlEngine *, const char *) { } }; diff --git a/src/imports/testlib/signalspy.h b/src/imports/testlib/signalspy.h index 6b5166d8e0..6542203ce4 100644 --- a/src/imports/testlib/signalspy.h +++ b/src/imports/testlib/signalspy.h @@ -44,20 +44,20 @@ // This is a dummy header for defining the interface of "SignalSpy.qml" to qdoc. -#include +#include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class SignalSpy : public QDeclarativeItem +class SignalSpy : public QQuickItem { Q_OBJECT Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged) Q_PROPERTY(QString signalName READ signalName WRITE signalName NOTIFY signalNameChanged) Q_PROPERTY(int count READ count countChanged) public: - SignalSpy(QDeclarativeItem *parent) : QDeclarativeItem(parent) {} + SignalSpy(QQuickItem *parent) : QQuickItem(parent) {} ~SignalSpy() QObject *target() const; diff --git a/src/imports/testlib/testcase.h b/src/imports/testlib/testcase.h index 1793cca0f2..e7758ec9df 100644 --- a/src/imports/testlib/testcase.h +++ b/src/imports/testlib/testcase.h @@ -44,13 +44,13 @@ // This is a dummy header for defining the interface of "TestCase.qml" to qdoc. -#include +#include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class TestCase : public QDeclarativeItem +class TestCase : public QQuickItem { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) @@ -60,7 +60,7 @@ class TestCase : public QDeclarativeItem Q_PROPERTY(bool running READ running NOTIFY runningChanged) Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged) public: - TestCase(QDeclarativeItem *parent) : QDeclarativeItem(parent) {} + TestCase(QQuickItem *parent) : QQuickItem(parent) {} ~TestCase() QString name() const; diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro index 3b8a5bf75e..a4cb03466e 100644 --- a/src/imports/testlib/testlib.pro +++ b/src/imports/testlib/testlib.pro @@ -4,12 +4,12 @@ include(../qimportbase.pri) CONFIG += qt plugin -QT += declarative quick qmltest qmltest-private v8-private declarative-private core-private testlib +QT += qml quick qmltest qmltest-private v8-private qml-private core-private testlib SOURCES += main.cpp HEADERS += -DESTDIR = $$QT.declarative.imports/$$TARGETPATH +DESTDIR = $$QT.qml.imports/$$TARGETPATH target.path += $$[QT_INSTALL_IMPORTS]/QtTest OTHER_IMPORT_FILES = \ @@ -23,7 +23,7 @@ otherImportFiles.files += $$OTHER_IMPORT_FILES otherImportFiles.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH copy2build.input = OTHER_IMPORT_FILES -copy2build.output = $$QT.declarative.imports/$$TARGETPATH/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT} +copy2build.output = $$QT.qml.imports/$$TARGETPATH/${QMAKE_FILE_BASE}${QMAKE_FILE_EXT} INSTALLS += target otherImportFiles diff --git a/src/imports/xmllistmodel/plugin.cpp b/src/imports/xmllistmodel/plugin.cpp index 9085a60885..54a6d5e212 100644 --- a/src/imports/xmllistmodel/plugin.cpp +++ b/src/imports/xmllistmodel/plugin.cpp @@ -3,7 +3,7 @@ ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/ ** -** This file is part of the QtDeclarative module of the Qt Toolkit. +** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage @@ -39,22 +39,22 @@ ** ****************************************************************************/ -#include -#include +#include +#include -#include "qdeclarativexmllistmodel_p.h" +#include "qqmlxmllistmodel_p.h" QT_BEGIN_NAMESPACE -class QmlXmlListModelPlugin : public QDeclarativeExtensionPlugin +class QmlXmlListModelPlugin : public QQmlExtensionPlugin { Q_OBJECT public: virtual void registerTypes(const char *uri) { Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.XmlListModel")); - qmlRegisterType(uri,2,0,"XmlListModel"); - qmlRegisterType(uri,2,0,"XmlRole"); + qmlRegisterType(uri,2,0,"XmlListModel"); + qmlRegisterType(uri,2,0,"XmlRole"); } }; diff --git a/src/imports/xmllistmodel/qdeclarativexmllistmodel.cpp b/src/imports/xmllistmodel/qdeclarativexmllistmodel.cpp deleted file mode 100644 index db7fec2c97..0000000000 --- a/src/imports/xmllistmodel/qdeclarativexmllistmodel.cpp +++ /dev/null @@ -1,1160 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qdeclarativexmllistmodel_p.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -Q_DECLARE_METATYPE(QDeclarativeXmlQueryResult) - -QT_BEGIN_NAMESPACE - - -typedef QPair QDeclarativeXmlListRange; - -#define XMLLISTMODEL_CLEAR_ID 0 - -/*! - \qmlclass XmlRole QDeclarativeXmlListModelRole - \inqmlmodule QtQuick 2 - \ingroup qml-working-with-data - \brief The XmlRole element allows you to specify a role for an XmlListModel. - - \sa {QtDeclarative} -*/ - -/*! - \qmlproperty string QtQuick2::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 QtQuick2::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 doc/src/snippets/declarative/xmlrole.xml - Here are some valid XPath expressions for XmlRole queries on this document: - - \snippet doc/src/snippets/declarative/xmlrole.qml 0 - \dots 4 - \snippet doc/src/snippets/declarative/xmlrole.qml 1 - - See the \l{http://www.w3.org/TR/xpath20/}{W3C XPath 2.0 specification} for more information. -*/ - -/*! - \qmlproperty bool QtQuick2::XmlRole::isKey - Defines whether this is a key role. - Key roles are used to 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 roleQueryErrorId; // the ptr to send back if there is an error - QStringList keyRoleQueries; - QStringList keyRoleResultsCache; - QString prefix; -}; - - -class QDeclarativeXmlQueryEngine; -class QDeclarativeXmlQueryThreadObject : public QObject -{ - Q_OBJECT -public: - QDeclarativeXmlQueryThreadObject(QDeclarativeXmlQueryEngine *); - - void processJobs(); - virtual bool event(QEvent *e); - -private: - QDeclarativeXmlQueryEngine *m_queryEngine; -}; - - -class QDeclarativeXmlQueryEngine : public QThread -{ - Q_OBJECT -public: - QDeclarativeXmlQueryEngine(QDeclarativeEngine *eng); - ~QDeclarativeXmlQueryEngine(); - - int doQuery(QString query, QString namespaces, QByteArray data, QList* roleObjects, QStringList keyRoleResultsCache); - void abort(int id); - - void processJobs(); - - static QDeclarativeXmlQueryEngine *instance(QDeclarativeEngine *engine); - -signals: - void queryCompleted(const QDeclarativeXmlQueryResult &); - void error(void*, const QString&); - -protected: - void run(); - -private: - void processQuery(XmlQueryJob *job); - void doQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult); - void doSubQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult); - void getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const; - void addIndexToRangeList(QList *ranges, int index) const; - - QMutex m_mutex; - QDeclarativeXmlQueryThreadObject *m_threadObject; - QList m_jobs; - QSet m_cancelledJobs; - QAtomicInt m_queryIds; - - QDeclarativeEngine *m_engine; - QObject *m_eventLoopQuitHack; - - static QHash queryEngines; - static QMutex queryEnginesMutex; -}; -QHash QDeclarativeXmlQueryEngine::queryEngines; -QMutex QDeclarativeXmlQueryEngine::queryEnginesMutex; - - -QDeclarativeXmlQueryThreadObject::QDeclarativeXmlQueryThreadObject(QDeclarativeXmlQueryEngine *e) - : m_queryEngine(e) -{ -} - -void QDeclarativeXmlQueryThreadObject::processJobs() -{ - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); -} - -bool QDeclarativeXmlQueryThreadObject::event(QEvent *e) -{ - if (e->type() == QEvent::User) { - m_queryEngine->processJobs(); - return true; - } else { - return QObject::event(e); - } -} - - - -QDeclarativeXmlQueryEngine::QDeclarativeXmlQueryEngine(QDeclarativeEngine *eng) -: QThread(eng), m_threadObject(0), m_queryIds(XMLLISTMODEL_CLEAR_ID + 1), m_engine(eng), m_eventLoopQuitHack(0) -{ - qRegisterMetaType("QDeclarativeXmlQueryResult"); - - m_eventLoopQuitHack = new QObject; - m_eventLoopQuitHack->moveToThread(this); - connect(m_eventLoopQuitHack, SIGNAL(destroyed(QObject*)), SLOT(quit()), Qt::DirectConnection); - start(QThread::IdlePriority); -} - -QDeclarativeXmlQueryEngine::~QDeclarativeXmlQueryEngine() -{ - queryEnginesMutex.lock(); - queryEngines.remove(m_engine); - queryEnginesMutex.unlock(); - - m_eventLoopQuitHack->deleteLater(); - wait(); -} - -int QDeclarativeXmlQueryEngine::doQuery(QString query, QString namespaces, QByteArray data, QList* 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; icount(); i++) { - if (!roleObjects->at(i)->isValid()) { - job.roleQueries << QString(); - continue; - } - job.roleQueries << roleObjects->at(i)->query(); - job.roleQueryErrorId << static_cast(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 QDeclarativeXmlQueryEngine::abort(int id) -{ - QMutexLocker ml(&m_mutex); - if (id != -1) - m_cancelledJobs.insert(id); -} - -void QDeclarativeXmlQueryEngine::run() -{ - m_mutex.lock(); - m_threadObject = new QDeclarativeXmlQueryThreadObject(this); - m_mutex.unlock(); - - processJobs(); - exec(); - - delete m_threadObject; - m_threadObject = 0; -} - -void QDeclarativeXmlQueryEngine::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(); - } -} - -QDeclarativeXmlQueryEngine *QDeclarativeXmlQueryEngine::instance(QDeclarativeEngine *engine) -{ - queryEnginesMutex.lock(); - QDeclarativeXmlQueryEngine *queryEng = queryEngines.value(engine); - if (!queryEng) { - queryEng = new QDeclarativeXmlQueryEngine(engine); - queryEngines.insert(engine, queryEng); - } - queryEnginesMutex.unlock(); - - return queryEng; -} - -void QDeclarativeXmlQueryEngine::processQuery(XmlQueryJob *job) -{ - QDeclarativeXmlQueryResult 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 QDeclarativeXmlQueryEngine::doQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *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 = "\n" + r.toUtf8() + ""; - 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") + - currentJob->query.mid(currentJob->query.lastIndexOf(QLatin1Char('/'))); - - //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 QDeclarativeXmlQueryEngine::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(QLatin1String(",")) + QLatin1String(")"); - - 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 QDeclarativeXmlQueryEngine::addIndexToRangeList(QList *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 QDeclarativeXmlQueryEngine::doSubQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *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; ikeyRoleResultsCache.count(); i++) { - if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i])) - addIndexToRangeList(¤tResult->removed, i); - else - temp << currentJob->keyRoleResultsCache[i]; - } - for (int i=0; iinserted, 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 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 resultList; - for (int i = 0; i < m_roleObjects->size(); ++i) { - QDeclarativeXmlListModelRole *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 QDeclarativeXmlListModelPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QDeclarativeXmlListModel) -public: - QDeclarativeXmlListModelPrivate() - : isComponentComplete(true), size(-1), highestRole(Qt::UserRole) - , reply(0), status(QDeclarativeXmlListModel::Null), progress(0.0) - , queryId(-1), roleObjects(), redirectCount(0) {} - - - void notifyQueryStarted(bool remoteSource) { - Q_Q(QDeclarativeXmlListModel); - progress = remoteSource ? 0.0 : 1.0; - status = QDeclarativeXmlListModel::Loading; - errorString.clear(); - emit q->progressChanged(progress); - emit q->statusChanged(status); - } - - void deleteReply() { - Q_Q(QDeclarativeXmlListModel); - if (reply) { - QObject::disconnect(reply, 0, q, 0); - reply->deleteLater(); - reply = 0; - } - } - - bool isComponentComplete; - QUrl src; - QString xml; - QString query; - QString namespaces; - int size; - QList roles; - QStringList roleNames; - int highestRole; - - QNetworkReply *reply; - QDeclarativeXmlListModel::Status status; - QString errorString; - qreal progress; - int queryId; - QStringList keyRoleResultsCache; - QList roleObjects; - - static void append_role(QDeclarativeListProperty *list, QDeclarativeXmlListModelRole *role); - static void clear_role(QDeclarativeListProperty *list); - QList > data; - int redirectCount; -}; - - -void QDeclarativeXmlListModelPrivate::append_role(QDeclarativeListProperty *list, QDeclarativeXmlListModelRole *role) -{ - QDeclarativeXmlListModel *_this = qobject_cast(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())) { - qmlInfo(role) << QObject::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 QDeclarativeXmlListModelPrivate::clear_role(QDeclarativeListProperty *list) -{ - QDeclarativeXmlListModel *_this = static_cast(list->object); - _this->d_func()->roles.clear(); - _this->d_func()->roleNames.clear(); - _this->d_func()->roleObjects.clear(); -} - -/*! - \qmlclass XmlListModel QDeclarativeXmlListModel - \inqmlmodule QtQuick 2 - \ingroup qml-working-with-data - \brief The XmlListModel element is used to specify a read-only model using XPath expressions. - - 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 - - - ... - - - A blog post - Sat, 07 Sep 2010 10:00:01 GMT - - - Another blog post - Sat, 07 Sep 2010 15:35:01 GMT - - - - \endcode - - A XmlListModel could create a model from this data, like this: - - \qml - import QtQuick 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 in the XML document. - - The XmlRole objects define the - model item attributes. Here, each model item will have \c title and \c pubDate - attributes that match the \c title and \c pubDate values of its corresponding \c . - (See \l XmlRole::query for more examples of valid XPath expressions for XmlRole.) - - The model could be used in a ListView, like this: - - \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 {RSS News} -*/ - -QDeclarativeXmlListModel::QDeclarativeXmlListModel(QObject *parent) - : QListModelInterface(*(new QDeclarativeXmlListModelPrivate), parent) -{ -} - -QDeclarativeXmlListModel::~QDeclarativeXmlListModel() -{ -} - -/*! - \qmlproperty list QtQuick2::XmlListModel::roles - - The roles to make available for this model. -*/ -QDeclarativeListProperty QDeclarativeXmlListModel::roleObjects() -{ - Q_D(QDeclarativeXmlListModel); - QDeclarativeListProperty list(this, d->roleObjects); - list.append = &QDeclarativeXmlListModelPrivate::append_role; - list.clear = &QDeclarativeXmlListModelPrivate::clear_role; - return list; -} - -QHash QDeclarativeXmlListModel::data(int index, const QList &roles) const -{ - Q_D(const QDeclarativeXmlListModel); - QHash rv; - for (int i = 0; i < roles.size(); ++i) { - int role = roles.at(i); - int roleIndex = d->roles.indexOf(role); - rv.insert(role, roleIndex == -1 ? QVariant() : d->data.value(roleIndex).value(index)); - } - return rv; -} - -QVariant QDeclarativeXmlListModel::data(int index, int role) const -{ - Q_D(const QDeclarativeXmlListModel); - int roleIndex = d->roles.indexOf(role); - return (roleIndex == -1) ? QVariant() : d->data.value(roleIndex).value(index); -} - -/*! - \qmlproperty int QtQuick2::XmlListModel::count - The number of data entries in the model. -*/ -int QDeclarativeXmlListModel::count() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->size; -} - -QList QDeclarativeXmlListModel::roles() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->roles; -} - -QString QDeclarativeXmlListModel::toString(int role) const -{ - Q_D(const QDeclarativeXmlListModel); - int index = d->roles.indexOf(role); - if (index == -1) - return QString(); - return d->roleNames.at(index); -} - -/*! - \qmlproperty url QtQuick2::XmlListModel::source - The location of the XML data source. - - If both \c source and \l xml are set, \l xml is used. -*/ -QUrl QDeclarativeXmlListModel::source() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->src; -} - -void QDeclarativeXmlListModel::setSource(const QUrl &src) -{ - Q_D(QDeclarativeXmlListModel); - 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 QtQuick2::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 QDeclarativeXmlListModel::xml() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->xml; -} - -void QDeclarativeXmlListModel::setXml(const QString &xml) -{ - Q_D(QDeclarativeXmlListModel); - if (d->xml != xml) { - d->xml = xml; - reload(); - emit xmlChanged(); - } -} - -/*! - \qmlproperty string QtQuick2::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 QDeclarativeXmlListModel::query() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->query; -} - -void QDeclarativeXmlListModel::setQuery(const QString &query) -{ - Q_D(QDeclarativeXmlListModel); - if (!query.startsWith(QLatin1Char('/'))) { - qmlInfo(this) << QCoreApplication::translate("QDeclarativeXmlRoleList", "An XmlListModel query must start with '/' or \"//\""); - return; - } - - if (d->query != query) { - d->query = query; - reload(); - emit queryChanged(); - } -} - -/*! - \qmlproperty string QtQuick2::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 QDeclarativeXmlListModel::namespaceDeclarations() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->namespaces; -} - -void QDeclarativeXmlListModel::setNamespaceDeclarations(const QString &declarations) -{ - Q_D(QDeclarativeXmlListModel); - if (d->namespaces != declarations) { - d->namespaces = declarations; - reload(); - emit namespaceDeclarationsChanged(); - } -} - -/*! - \qmlmethod object QtQuick2::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 -*/ -QDeclarativeV8Handle QDeclarativeXmlListModel::get(int index) const -{ - // Must be called with a context and handle scope - Q_D(const QDeclarativeXmlListModel); - - if (index < 0 || index >= count()) - return QDeclarativeV8Handle::fromHandle(v8::Undefined()); - - QDeclarativeEngine *engine = qmlContext(this)->engine(); - QV8Engine *v8engine = QDeclarativeEnginePrivate::getV8Engine(engine); - v8::Local rv = v8::Object::New(); - for (int ii = 0; ii < d->roleObjects.count(); ++ii) - rv->Set(v8engine->toString(d->roleObjects[ii]->name()), - v8engine->fromVariant(d->data.value(ii).value(index))); - - return QDeclarativeV8Handle::fromHandle(rv); -} - -/*! - \qmlproperty enumeration QtQuick2::XmlListModel::status - Specifies the model loading status, which can be one of the following: - - \list - \o XmlListModel.Null - No XML data has been set for this model. - \o XmlListModel.Ready - The XML data has been loaded into the model. - \o XmlListModel.Loading - The model is in the process of reading and loading XML data. - \o XmlListModel.Error - An error occurred while the model was loading. See errorString() for details - about the error. - \endlist - - \sa progress - -*/ -QDeclarativeXmlListModel::Status QDeclarativeXmlListModel::status() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->status; -} - -/*! - \qmlproperty real QtQuick2::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 QDeclarativeXmlListModel::progress() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->progress; -} - -/*! - \qmlmethod void QtQuick2::XmlListModel::errorString() - - Returns a string description of the last error that occurred - if \l status is XmlListModel::Error. -*/ -QString QDeclarativeXmlListModel::errorString() const -{ - Q_D(const QDeclarativeXmlListModel); - return d->errorString; -} - -void QDeclarativeXmlListModel::classBegin() -{ - Q_D(QDeclarativeXmlListModel); - d->isComponentComplete = false; - - QDeclarativeXmlQueryEngine *queryEngine = QDeclarativeXmlQueryEngine::instance(qmlEngine(this)); - connect(queryEngine, SIGNAL(queryCompleted(QDeclarativeXmlQueryResult)), - SLOT(queryCompleted(QDeclarativeXmlQueryResult))); - connect(queryEngine, SIGNAL(error(void*,QString)), - SLOT(queryError(void*,QString))); -} - -void QDeclarativeXmlListModel::componentComplete() -{ - Q_D(QDeclarativeXmlListModel); - d->isComponentComplete = true; - reload(); -} - -/*! - \qmlmethod QtQuick2::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 QDeclarativeXmlListModel::reload() -{ - Q_D(QDeclarativeXmlListModel); - - if (!d->isComponentComplete) - return; - - QDeclarativeXmlQueryEngine::instance(qmlEngine(this))->abort(d->queryId); - d->queryId = -1; - - if (d->size < 0) - d->size = 0; - - if (d->reply) { - d->reply->abort(); - d->deleteReply(); - } - - if (!d->xml.isEmpty()) { - d->queryId = QDeclarativeXmlQueryEngine::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 { - 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))); - } -} - -#define XMLLISTMODEL_MAX_REDIRECT 16 - -void QDeclarativeXmlListModel::requestFinished() -{ - Q_D(QDeclarativeXmlListModel); - - 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(); - - int count = this->count(); - d->data.clear(); - d->size = 0; - if (count > 0) { - emit itemsRemoved(0, count); - 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 = QDeclarativeXmlQueryEngine::instance(qmlEngine(this))->doQuery(d->query, d->namespaces, data, &d->roleObjects, d->keyRoleResultsCache); - } - d->deleteReply(); - - d->progress = 1.0; - emit progressChanged(d->progress); - } -} - -void QDeclarativeXmlListModel::requestProgress(qint64 received, qint64 total) -{ - Q_D(QDeclarativeXmlListModel); - if (d->status == Loading && total > 0) { - d->progress = qreal(received)/total; - emit progressChanged(d->progress); - } -} - -void QDeclarativeXmlListModel::dataCleared() -{ - Q_D(QDeclarativeXmlListModel); - QDeclarativeXmlQueryResult r; - r.queryId = XMLLISTMODEL_CLEAR_ID; - r.size = 0; - r.removed << qMakePair(0, count()); - r.keyRoleResultsCache = d->keyRoleResultsCache; - queryCompleted(r); -} - -void QDeclarativeXmlListModel::queryError(void* object, const QString& error) -{ - // Be extra careful, object may no longer exist, it's just an ID. - Q_D(QDeclarativeXmlListModel); - for (int i=0; iroleObjects.count(); i++) { - if (d->roleObjects.at(i) == static_cast(object)) { - qmlInfo(d->roleObjects.at(i)) << QObject::tr("invalid query: \"%1\"").arg(error); - return; - } - } - qmlInfo(this) << QObject::tr("invalid query: \"%1\"").arg(error); -} - -void QDeclarativeXmlListModel::queryCompleted(const QDeclarativeXmlQueryResult &result) -{ - Q_D(QDeclarativeXmlListModel); - if (result.queryId != d->queryId) - return; - - int origCount = d->size; - bool sizeChanged = result.size != d->size; - - d->size = result.size; - d->data = result.data; - 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; iroleObjects.count(); i++) { - if (d->roleObjects[i]->isKey()) { - hasKeys = true; - break; - } - } - if (!hasKeys) { - if (!(origCount == 0 && d->size == 0)) { - emit itemsRemoved(0, origCount); - emit itemsInserted(0, d->size); - emit countChanged(); - } - - } else { - for (int i=0; istatus); -} - -QT_END_NAMESPACE - -#include diff --git a/src/imports/xmllistmodel/qdeclarativexmllistmodel_p.h b/src/imports/xmllistmodel/qdeclarativexmllistmodel_p.h deleted file mode 100644 index f34591d0a3..0000000000 --- a/src/imports/xmllistmodel/qdeclarativexmllistmodel_p.h +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QDECLARATIVEXMLLISTMODEL_H -#define QDECLARATIVEXMLLISTMODEL_H - -#include -#include - -#include -#include - -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - - -class QDeclarativeContext; -class QDeclarativeXmlListModelRole; -class QDeclarativeXmlListModelPrivate; - -struct QDeclarativeXmlQueryResult { - int queryId; - int size; - QList > data; - QList > inserted; - QList > removed; - QStringList keyRoleResultsCache; -}; - -class QDeclarativeXmlListModel : public QListModelInterface, public QDeclarativeParserStatus -{ - Q_OBJECT - Q_INTERFACES(QDeclarativeParserStatus) - Q_ENUMS(Status) - - 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(QDeclarativeListProperty roles READ roleObjects) - Q_PROPERTY(int count READ count NOTIFY countChanged) - Q_CLASSINFO("DefaultProperty", "roles") - -public: - QDeclarativeXmlListModel(QObject *parent = 0); - ~QDeclarativeXmlListModel(); - - virtual QHash data(int index, const QList &roles = (QList())) const; - virtual QVariant data(int index, int role) const; - virtual int count() const; - virtual QList roles() const; - virtual QString toString(int role) const; - - QDeclarativeListProperty 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 QDeclarativeV8Handle get(int index) const; - - enum Status { Null, Ready, Loading, Error }; - Status status() const; - qreal progress() const; - - Q_INVOKABLE QString errorString() const; - - virtual void classBegin(); - virtual void componentComplete(); - -Q_SIGNALS: - void statusChanged(QDeclarativeXmlListModel::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: - void requestFinished(); - void requestProgress(qint64,qint64); - void dataCleared(); - void queryCompleted(const QDeclarativeXmlQueryResult &); - void queryError(void* object, const QString& error); - -private: - Q_DECLARE_PRIVATE(QDeclarativeXmlListModel) - Q_DISABLE_COPY(QDeclarativeXmlListModel) -}; - -class QDeclarativeXmlListModelRole : 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: - QDeclarativeXmlListModelRole() : m_isKey(false) {} - ~QDeclarativeXmlListModelRole() {} - - QString name() const { return m_name; } - void setName(const QString &name) { - if (name == m_name) - return; - m_name = name; - emit nameChanged(); - } - - QString query() const { return m_query; } - void setQuery(const QString &query) - { - if (query.startsWith(QLatin1Char('/'))) { - qmlInfo(this) << tr("An XmlRole query must not start with '/'"); - return; - } - if (m_query == query) - return; - m_query = query; - emit queryChanged(); - } - - bool isKey() const { return m_isKey; } - void setIsKey(bool b) { - if (m_isKey == b) - return; - m_isKey = b; - emit isKeyChanged(); - } - - bool isValid() { - 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(QDeclarativeXmlListModel) -QML_DECLARE_TYPE(QDeclarativeXmlListModelRole) - -QT_END_HEADER - -#endif // QDECLARATIVEXMLLISTMODEL_H diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp new file mode 100644 index 0000000000..1377859b5e --- /dev/null +++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp @@ -0,0 +1,1160 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlxmllistmodel_p.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +Q_DECLARE_METATYPE(QQuickXmlQueryResult) + +QT_BEGIN_NAMESPACE + + +typedef QPair QQuickXmlListRange; + +#define XMLLISTMODEL_CLEAR_ID 0 + +/*! + \qmlclass XmlRole QQuickXmlListModelRole + \inqmlmodule QtQuick 2 + \ingroup qml-working-with-data + \brief The XmlRole element allows you to specify a role for an XmlListModel. + + \sa {QtQml} +*/ + +/*! + \qmlproperty string QtQuick2::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 QtQuick2::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 doc/src/snippets/qml/xmlrole.xml + Here are some valid XPath expressions for XmlRole queries on this document: + + \snippet doc/src/snippets/qml/xmlrole.qml 0 + \dots 4 + \snippet doc/src/snippets/qml/xmlrole.qml 1 + + See the \l{http://www.w3.org/TR/xpath20/}{W3C XPath 2.0 specification} for more information. +*/ + +/*! + \qmlproperty bool QtQuick2::XmlRole::isKey + Defines whether this is a key role. + Key roles are used to 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 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(); + virtual bool event(QEvent *e); + +private: + QQuickXmlQueryEngine *m_queryEngine; +}; + + +class QQuickXmlQueryEngine : public QThread +{ + Q_OBJECT +public: + QQuickXmlQueryEngine(QQmlEngine *eng); + ~QQuickXmlQueryEngine(); + + int doQuery(QString query, QString namespaces, QByteArray data, QList* 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(); + +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 *ranges, int index) const; + + QMutex m_mutex; + QQuickXmlQueryThreadObject *m_threadObject; + QList m_jobs; + QSet m_cancelledJobs; + QAtomicInt m_queryIds; + + QQmlEngine *m_engine; + QObject *m_eventLoopQuitHack; + + static QHash queryEngines; + static QMutex queryEnginesMutex; +}; +QHash 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"); + + 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* 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; icount(); i++) { + if (!roleObjects->at(i)->isValid()) { + job.roleQueries << QString(); + continue; + } + job.roleQueries << roleObjects->at(i)->query(); + job.roleQueryErrorId << static_cast(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 = "\n" + r.toUtf8() + ""; + 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") + + currentJob->query.mid(currentJob->query.lastIndexOf(QLatin1Char('/'))); + + //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(QLatin1String(",")) + QLatin1String(")"); + + 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 *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; ikeyRoleResultsCache.count(); i++) { + if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i])) + addIndexToRangeList(¤tResult->removed, i); + else + temp << currentJob->keyRoleResultsCache[i]; + } + for (int i=0; iinserted, 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 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 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 QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickXmlListModel) +public: + QQuickXmlListModelPrivate() + : isComponentComplete(true), size(-1), highestRole(Qt::UserRole) + , reply(0), 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); + } + + void deleteReply() { + Q_Q(QQuickXmlListModel); + if (reply) { + QObject::disconnect(reply, 0, q, 0); + reply->deleteLater(); + reply = 0; + } + } + + bool isComponentComplete; + QUrl src; + QString xml; + QString query; + QString namespaces; + int size; + QList roles; + QStringList roleNames; + int highestRole; + + QNetworkReply *reply; + QQuickXmlListModel::Status status; + QString errorString; + qreal progress; + int queryId; + QStringList keyRoleResultsCache; + QList roleObjects; + + static void append_role(QQmlListProperty *list, QQuickXmlListModelRole *role); + static void clear_role(QQmlListProperty *list); + QList > data; + int redirectCount; +}; + + +void QQuickXmlListModelPrivate::append_role(QQmlListProperty *list, QQuickXmlListModelRole *role) +{ + QQuickXmlListModel *_this = qobject_cast(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())) { + qmlInfo(role) << QObject::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 *list) +{ + QQuickXmlListModel *_this = static_cast(list->object); + _this->d_func()->roles.clear(); + _this->d_func()->roleNames.clear(); + _this->d_func()->roleObjects.clear(); +} + +/*! + \qmlclass XmlListModel QQuickXmlListModel + \inqmlmodule QtQuick 2 + \ingroup qml-working-with-data + \brief The XmlListModel element is used to specify a read-only model using XPath expressions. + + 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 + + + ... + + + A blog post + Sat, 07 Sep 2010 10:00:01 GMT + + + Another blog post + Sat, 07 Sep 2010 15:35:01 GMT + + + + \endcode + + A XmlListModel could create a model from this data, like this: + + \qml + import QtQuick 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 in the XML document. + + The XmlRole objects define the + model item attributes. Here, each model item will have \c title and \c pubDate + attributes that match the \c title and \c pubDate values of its corresponding \c . + (See \l XmlRole::query for more examples of valid XPath expressions for XmlRole.) + + The model could be used in a ListView, like this: + + \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 {RSS News} +*/ + +QQuickXmlListModel::QQuickXmlListModel(QObject *parent) + : QListModelInterface(*(new QQuickXmlListModelPrivate), parent) +{ +} + +QQuickXmlListModel::~QQuickXmlListModel() +{ +} + +/*! + \qmlproperty list QtQuick2::XmlListModel::roles + + The roles to make available for this model. +*/ +QQmlListProperty QQuickXmlListModel::roleObjects() +{ + Q_D(QQuickXmlListModel); + QQmlListProperty list(this, d->roleObjects); + list.append = &QQuickXmlListModelPrivate::append_role; + list.clear = &QQuickXmlListModelPrivate::clear_role; + return list; +} + +QHash QQuickXmlListModel::data(int index, const QList &roles) const +{ + Q_D(const QQuickXmlListModel); + QHash rv; + for (int i = 0; i < roles.size(); ++i) { + int role = roles.at(i); + int roleIndex = d->roles.indexOf(role); + rv.insert(role, roleIndex == -1 ? QVariant() : d->data.value(roleIndex).value(index)); + } + return rv; +} + +QVariant QQuickXmlListModel::data(int index, int role) const +{ + Q_D(const QQuickXmlListModel); + int roleIndex = d->roles.indexOf(role); + return (roleIndex == -1) ? QVariant() : d->data.value(roleIndex).value(index); +} + +/*! + \qmlproperty int QtQuick2::XmlListModel::count + The number of data entries in the model. +*/ +int QQuickXmlListModel::count() const +{ + Q_D(const QQuickXmlListModel); + return d->size; +} + +QList QQuickXmlListModel::roles() const +{ + Q_D(const QQuickXmlListModel); + return d->roles; +} + +QString QQuickXmlListModel::toString(int role) const +{ + Q_D(const QQuickXmlListModel); + int index = d->roles.indexOf(role); + if (index == -1) + return QString(); + return d->roleNames.at(index); +} + +/*! + \qmlproperty url QtQuick2::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 QtQuick2::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 QtQuick2::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('/'))) { + qmlInfo(this) << QCoreApplication::translate("QQuickXmlRoleList", "An XmlListModel query must start with '/' or \"//\""); + return; + } + + if (d->query != query) { + d->query = query; + reload(); + emit queryChanged(); + } +} + +/*! + \qmlproperty string QtQuick2::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 QtQuick2::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 +*/ +QQmlV8Handle QQuickXmlListModel::get(int index) const +{ + // Must be called with a context and handle scope + Q_D(const QQuickXmlListModel); + + if (index < 0 || index >= count()) + return QQmlV8Handle::fromHandle(v8::Undefined()); + + QQmlEngine *engine = qmlContext(this)->engine(); + QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); + v8::Local rv = v8::Object::New(); + for (int ii = 0; ii < d->roleObjects.count(); ++ii) + rv->Set(v8engine->toString(d->roleObjects[ii]->name()), + v8engine->fromVariant(d->data.value(ii).value(index))); + + return QQmlV8Handle::fromHandle(rv); +} + +/*! + \qmlproperty enumeration QtQuick2::XmlListModel::status + Specifies the model loading status, which can be one of the following: + + \list + \o XmlListModel.Null - No XML data has been set for this model. + \o XmlListModel.Ready - The XML data has been loaded into the model. + \o XmlListModel.Loading - The model is in the process of reading and loading XML data. + \o 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 QtQuick2::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 void QtQuick2::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 QtQuick2::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 (d->reply) { + d->reply->abort(); + d->deleteReply(); + } + + 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 { + 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))); + } +} + +#define XMLLISTMODEL_MAX_REDIRECT 16 + +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(); + + int count = this->count(); + d->data.clear(); + d->size = 0; + if (count > 0) { + emit itemsRemoved(0, count); + 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); + } +} + +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; iroleObjects.count(); i++) { + if (d->roleObjects.at(i) == static_cast(object)) { + qmlInfo(d->roleObjects.at(i)) << QObject::tr("invalid query: \"%1\"").arg(error); + return; + } + } + qmlInfo(this) << QObject::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->size = result.size; + d->data = result.data; + 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; iroleObjects.count(); i++) { + if (d->roleObjects[i]->isKey()) { + hasKeys = true; + break; + } + } + if (!hasKeys) { + if (!(origCount == 0 && d->size == 0)) { + emit itemsRemoved(0, origCount); + emit itemsInserted(0, d->size); + emit countChanged(); + } + + } else { + for (int i=0; istatus); +} + +QT_END_NAMESPACE + +#include diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h new file mode 100644 index 0000000000..5bc4c7b494 --- /dev/null +++ b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKXMLLISTMODEL_H +#define QQUICKXMLLISTMODEL_H + +#include +#include + +#include +#include + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class QQmlContext; +class QQuickXmlListModelRole; +class QQuickXmlListModelPrivate; + +struct QQuickXmlQueryResult { + int queryId; + int size; + QList > data; + QList > inserted; + QList > removed; + QStringList keyRoleResultsCache; +}; + +class QQuickXmlListModel : public QListModelInterface, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_ENUMS(Status) + + 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 roles READ roleObjects) + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_CLASSINFO("DefaultProperty", "roles") + +public: + QQuickXmlListModel(QObject *parent = 0); + ~QQuickXmlListModel(); + + virtual QHash data(int index, const QList &roles = (QList())) const; + virtual QVariant data(int index, int role) const; + virtual int count() const; + virtual QList roles() const; + virtual QString toString(int role) const; + + QQmlListProperty 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 QQmlV8Handle get(int index) const; + + enum Status { Null, Ready, Loading, Error }; + Status status() const; + qreal progress() const; + + Q_INVOKABLE QString errorString() const; + + virtual void classBegin(); + virtual void componentComplete(); + +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: + void requestFinished(); + 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; + emit nameChanged(); + } + + QString query() const { return m_query; } + void setQuery(const QString &query) + { + if (query.startsWith(QLatin1Char('/'))) { + qmlInfo(this) << tr("An XmlRole query must not start with '/'"); + return; + } + if (m_query == query) + return; + m_query = query; + emit queryChanged(); + } + + bool isKey() const { return m_isKey; } + void setIsKey(bool b) { + if (m_isKey == b) + return; + m_isKey = b; + emit isKeyChanged(); + } + + bool isValid() { + 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) + +QT_END_HEADER + +#endif // QQUICKXMLLISTMODEL_H diff --git a/src/imports/xmllistmodel/xmllistmodel.pro b/src/imports/xmllistmodel/xmllistmodel.pro index d8121e8db8..8c056e8448 100644 --- a/src/imports/xmllistmodel/xmllistmodel.pro +++ b/src/imports/xmllistmodel/xmllistmodel.pro @@ -2,12 +2,12 @@ TARGET = qmlxmllistmodelplugin TARGETPATH = QtQuick/XmlListModel include(../qimportbase.pri) -QT += network declarative xmlpatterns declarative-private v8-private core-private +QT += network qml xmlpatterns qml-private v8-private core-private -SOURCES += qdeclarativexmllistmodel.cpp plugin.cpp -HEADERS += qdeclarativexmllistmodel_p.h +SOURCES += qqmlxmllistmodel.cpp plugin.cpp +HEADERS += qqmlxmllistmodel_p.h -DESTDIR = $$QT.declarative.imports/$$TARGETPATH +DESTDIR = $$QT.qml.imports/$$TARGETPATH target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH qmldir.files += $$PWD/qmldir -- cgit v1.2.3