diff options
Diffstat (limited to 'src/imports')
34 files changed, 1096 insertions, 386 deletions
diff --git a/src/imports/dialogs/DefaultFileDialog.qml b/src/imports/dialogs/DefaultFileDialog.qml index 2cdb34cc03..fb6996b80c 100644 --- a/src/imports/dialogs/DefaultFileDialog.qml +++ b/src/imports/dialogs/DefaultFileDialog.qml @@ -107,11 +107,10 @@ AbstractFileDialog { selectedIndices.map(function(idx) { if (view.model.isFolder(idx)) { if (selectFolder) - // TODO after QTBUG-32039: should not need to convert pathToUrl here - addSelection(pathToUrl(view.model.get(idx, "filePath"))) + addSelection(view.model.get(idx, "fileURL")) } else { if (!selectFolder) - addSelection(pathToUrl(view.model.get(idx, "filePath"))) + addSelection(view.model.get(idx, "fileURL")) } }) } diff --git a/src/imports/dialogs/doc/qtquickdialogs.qdocconf b/src/imports/dialogs/doc/qtquickdialogs.qdocconf index 34f19b5ff3..be4fd5e9ec 100644 --- a/src/imports/dialogs/doc/qtquickdialogs.qdocconf +++ b/src/imports/dialogs/doc/qtquickdialogs.qdocconf @@ -34,3 +34,6 @@ headerdirs += .. sourcedirs += .. imagedirs += images + +navigation.landingpage = "Qt Quick Dialogs" +navigation.qmltypespage = "Qt Quick Dialogs QML Types" diff --git a/src/imports/dialogs/plugin.cpp b/src/imports/dialogs/plugin.cpp index faa15b84bb..249152c48c 100644 --- a/src/imports/dialogs/plugin.cpp +++ b/src/imports/dialogs/plugin.cpp @@ -52,8 +52,6 @@ //#define PURE_QML_ONLY -#define DIALOGS_MAJOR_MINOR 1, 0 - QT_BEGIN_NAMESPACE /*! @@ -103,24 +101,24 @@ public: // FileDialog #ifndef PURE_QML_ONLY if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(QPlatformTheme::FileDialog)) - qmlRegisterType<QQuickPlatformFileDialog>(uri, DIALOGS_MAJOR_MINOR, "FileDialog"); + qmlRegisterType<QQuickPlatformFileDialog>(uri, 1, 0, "FileDialog"); else #endif - registerWidgetOrQmlImplementation<QQuickFileDialog>(widgetsDir, qmlDir, "FileDialog", uri, hasTopLevelWindows); + registerWidgetOrQmlImplementation<QQuickFileDialog>(widgetsDir, qmlDir, "FileDialog", uri, hasTopLevelWindows, 1, 0); // ColorDialog #ifndef PURE_QML_ONLY if (QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(QPlatformTheme::ColorDialog)) - qmlRegisterType<QQuickPlatformColorDialog>(uri, DIALOGS_MAJOR_MINOR, "ColorDialog"); + qmlRegisterType<QQuickPlatformColorDialog>(uri, 1, 0, "ColorDialog"); else #endif - registerWidgetOrQmlImplementation<QQuickColorDialog>(widgetsDir, qmlDir, "ColorDialog", uri, hasTopLevelWindows); + registerWidgetOrQmlImplementation<QQuickColorDialog>(widgetsDir, qmlDir, "ColorDialog", uri, hasTopLevelWindows, 1, 0); } protected: template <class WrapperType> void registerWidgetOrQmlImplementation(QDir widgetsDir, QDir qmlDir, - const char *qmlName, const char *uri, bool hasTopLevelWindows) { + const char *qmlName, const char *uri, bool hasTopLevelWindows, int versionMajor, int versionMinor) { //qDebug() << Q_FUNC_INFO << qmlDir << qmlName << uri; bool needQml = true; @@ -130,17 +128,17 @@ protected: if (hasTopLevelWindows && widgetsDir.exists("qmldir") && !qstrcmp(QCoreApplication::instance()->metaObject()->className(), "QApplication")) { QString dialogQmlPath = qmlDir.filePath(QString("Widget%1.qml").arg(qmlName)); - if (qmlRegisterType(QUrl::fromLocalFile(dialogQmlPath), uri, DIALOGS_MAJOR_MINOR, qmlName) >= 0) + if (qmlRegisterType(QUrl::fromLocalFile(dialogQmlPath), uri, versionMajor, versionMinor, qmlName) >= 0) needQml = false; // qDebug() << "registering" << qmlName << " as " << dialogQmlPath << "success?" << !needQml; } #endif if (needQml) { QByteArray abstractTypeName = QByteArray("Abstract") + qmlName; - qmlRegisterType<WrapperType>(uri, DIALOGS_MAJOR_MINOR, abstractTypeName); // implementation wrapper + qmlRegisterType<WrapperType>(uri, versionMajor, versionMinor, abstractTypeName); // implementation wrapper QString dialogQmlPath = qmlDir.filePath(QString("Default%1.qml").arg(qmlName)); // qDebug() << "registering" << qmlName << " as " << dialogQmlPath << "success?" << - qmlRegisterType(QUrl::fromLocalFile(dialogQmlPath), uri, DIALOGS_MAJOR_MINOR, qmlName); + qmlRegisterType(QUrl::fromLocalFile(dialogQmlPath), uri, versionMajor, versionMinor, qmlName); } } diff --git a/src/imports/dialogs/qquickabstractfiledialog.cpp b/src/imports/dialogs/qquickabstractfiledialog.cpp index d8a75feb53..3a0d5baa83 100644 --- a/src/imports/dialogs/qquickabstractfiledialog.cpp +++ b/src/imports/dialogs/qquickabstractfiledialog.cpp @@ -109,16 +109,15 @@ void QQuickAbstractFileDialog::setSelectFolder(bool selectFolder) QUrl QQuickAbstractFileDialog::folder() { if (m_dlgHelper && !m_dlgHelper->directory().isEmpty()) - return QUrl::fromLocalFile(m_dlgHelper->directory()); - return QUrl::fromLocalFile(m_options->initialDirectory()); + return m_dlgHelper->directory(); + return m_options->initialDirectory(); } void QQuickAbstractFileDialog::setFolder(const QUrl &f) { - QString dir = f.path(); if (m_dlgHelper) - m_dlgHelper->setDirectory(dir); - m_options->setInitialDirectory(dir); + m_dlgHelper->setDirectory(f); + m_options->setInitialDirectory(f); emit folderChanged(); } @@ -159,11 +158,9 @@ QUrl QQuickAbstractFileDialog::fileUrl() QList<QUrl> QQuickAbstractFileDialog::fileUrls() { - QList<QUrl> ret; if (m_dlgHelper) - foreach (QString path, m_dlgHelper->selectedFiles()) - ret << QUrl::fromLocalFile(path); - return ret; + return m_dlgHelper->selectedFiles(); + return QList<QUrl>(); } void QQuickAbstractFileDialog::updateModes() diff --git a/src/imports/dialogs/qquickplatformfiledialog.cpp b/src/imports/dialogs/qquickplatformfiledialog.cpp index 3da9f6c3b2..8c024e3c70 100644 --- a/src/imports/dialogs/qquickplatformfiledialog.cpp +++ b/src/imports/dialogs/qquickplatformfiledialog.cpp @@ -166,7 +166,7 @@ QPlatformFileDialogHelper *QQuickPlatformFileDialog::helper() ->createPlatformDialogHelper(QPlatformTheme::FileDialog)); if (!m_dlgHelper) return m_dlgHelper; - connect(m_dlgHelper, SIGNAL(directoryEntered(QString)), this, SIGNAL(folderChanged())); + connect(m_dlgHelper, SIGNAL(directoryEntered(QUrl)), this, SIGNAL(folderChanged())); connect(m_dlgHelper, SIGNAL(filterSelected(QString)), this, SIGNAL(filterSelected())); connect(m_dlgHelper, SIGNAL(accept()), this, SLOT(accept())); connect(m_dlgHelper, SIGNAL(reject()), this, SLOT(reject())); diff --git a/src/imports/folderlistmodel/fileinfothread.cpp b/src/imports/folderlistmodel/fileinfothread.cpp index 64a4b02e91..4aa43b2d3f 100644 --- a/src/imports/folderlistmodel/fileinfothread.cpp +++ b/src/imports/folderlistmodel/fileinfothread.cpp @@ -55,9 +55,10 @@ FileInfoThread::FileInfoThread(QObject *parent) needUpdate(true), folderUpdate(false), sortUpdate(false), + showFiles(true), showDirs(true), showDirsFirst(false), - showDotDot(false), + showDotAndDotDot(false), showOnlyReadable(false) { #ifndef QT_NO_FILESYSTEMWATCHER @@ -142,6 +143,14 @@ void FileInfoThread::setNameFilters(const QStringList & filters) condition.wakeAll(); } +void FileInfoThread::setShowFiles(bool show) +{ + QMutexLocker locker(&mutex); + showFiles = show; + folderUpdate = true; + condition.wakeAll(); +} + void FileInfoThread::setShowDirs(bool showFolders) { QMutexLocker locker(&mutex); @@ -158,11 +167,12 @@ void FileInfoThread::setShowDirsFirst(bool show) condition.wakeAll(); } -void FileInfoThread::setShowDotDot(bool on) +void FileInfoThread::setShowDotAndDotDot(bool on) { QMutexLocker locker(&mutex); - showDotDot = on; + showDotAndDotDot = on; folderUpdate = true; + needUpdate = true; condition.wakeAll(); } @@ -212,10 +222,14 @@ void FileInfoThread::run() void FileInfoThread::getFileInfos(const QString &path) { QDir::Filters filter; - filter = QDir::Files | QDir::NoDot | QDir::CaseSensitive; + filter = QDir::CaseSensitive; + if (showFiles) + filter = filter | QDir::Files; if (showDirs) filter = filter | QDir::AllDirs | QDir::Drives; - if ((path == rootPath) || !showDotDot) + if (!showDotAndDotDot) + filter = filter | QDir::NoDot | QDir::NoDotDot; + else if (path == rootPath) filter = filter | QDir::NoDotDot; if (showOnlyReadable) filter = filter | QDir::Readable; diff --git a/src/imports/folderlistmodel/fileinfothread_p.h b/src/imports/folderlistmodel/fileinfothread_p.h index f9340ca75d..d50361de3a 100644 --- a/src/imports/folderlistmodel/fileinfothread_p.h +++ b/src/imports/folderlistmodel/fileinfothread_p.h @@ -70,9 +70,10 @@ public: void setRootPath(const QString &path); void setSortFlags(QDir::SortFlags flags); void setNameFilters(const QStringList & nameFilters); + void setShowFiles(bool show); void setShowDirs(bool showFolders); void setShowDirsFirst(bool show); - void setShowDotDot(bool on); + void setShowDotAndDotDot(bool on); void setShowOnlyReadable(bool on); public Q_SLOTS: @@ -102,9 +103,10 @@ private: bool needUpdate; bool folderUpdate; bool sortUpdate; + bool showFiles; bool showDirs; bool showDirsFirst; - bool showDotDot; + bool showDotAndDotDot; bool showOnlyReadable; }; diff --git a/src/imports/folderlistmodel/folderlistmodel.pro b/src/imports/folderlistmodel/folderlistmodel.pro index c29f1f8ca5..c8c805adb6 100644 --- a/src/imports/folderlistmodel/folderlistmodel.pro +++ b/src/imports/folderlistmodel/folderlistmodel.pro @@ -3,7 +3,7 @@ TARGET = qmlfolderlistmodelplugin TARGETPATH = Qt/labs/folderlistmodel IMPORT_VERSION = 2.0 -QT = core-private qml-private v8-private +QT = core-private qml-private SOURCES += qquickfolderlistmodel.cpp plugin.cpp \ fileinfothread.cpp diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp index 2f61a9abe7..032c32a241 100644 --- a/src/imports/folderlistmodel/qquickfolderlistmodel.cpp +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.cpp @@ -55,7 +55,8 @@ class QQuickFolderListModelPrivate public: QQuickFolderListModelPrivate(QQuickFolderListModel *q) : q_ptr(q), - sortField(QQuickFolderListModel::Name), sortReversed(false), showDirs(true), showDirsFirst(false), showDots(false), showOnlyReadable(false) + sortField(QQuickFolderListModel::Name), sortReversed(false), showFiles(true), + showDirs(true), showDirsFirst(false), showDotAndDotDot(false), showOnlyReadable(false) { nameFilters << QLatin1String("*"); } @@ -70,9 +71,10 @@ public: QQuickFolderListModel::SortField sortField; QStringList nameFilters; bool sortReversed; + bool showFiles; bool showDirs; bool showDirsFirst; - bool showDots; + bool showDotAndDotDot; bool showOnlyReadable; ~QQuickFolderListModelPrivate() {} @@ -98,6 +100,7 @@ void QQuickFolderListModelPrivate::init() q, SLOT(_q_directoryUpdated(QString, QList<FileProperty>, int, int))); q->connect(&fileInfoThread, SIGNAL(sortFinished(QList<FileProperty>)), q, SLOT(_q_sortFinished(QList<FileProperty>))); + q->connect(q, SIGNAL(rowCountChanged()), q, SIGNAL(countChanged())); } @@ -323,6 +326,7 @@ QQuickFolderListModel::QQuickFolderListModel(QObject *parent) d->roleNames[FileLastModifiedRole] = "fileModified"; d->roleNames[FileLastReadRole] = "fileAccessed"; d->roleNames[FileIsDirRole] = "fileIsDir"; + d->roleNames[FileUrlRole] = "fileURL"; d->init(); } @@ -364,6 +368,9 @@ QVariant QQuickFolderListModel::data(const QModelIndex &index, int role) const case FileIsDirRole: rv = d->data.at(index.row()).isDir(); break; + case FileUrlRole: + rv = QUrl::fromLocalFile(d->data.at(index.row()).filePath()); + break; default: break; } @@ -400,8 +407,7 @@ QModelIndex QQuickFolderListModel::index(int row, int , const QModelIndex &) con 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. + The value must be a \c file: or \c qrc: URL, or a relative URL. By default, the value is an invalid URL. */ @@ -441,7 +447,7 @@ void QQuickFolderListModel::setFolder(const QUrl &folder) /*! - \qmlproperty string QQuickFolderListModel::rootFolder + \qmlproperty url QQuickFolderListModel::rootFolder When the rootFolder is set, then this folder will be threated as the root in the file system, so that @@ -615,6 +621,30 @@ bool QQuickFolderListModel::isFolder(int index) const } /*! + \qmlproperty bool FolderListModel::showFiles + + If true, files are included in the model; otherwise only directories + are included. + + By default, this property is true. + + \sa showDirs +*/ +bool QQuickFolderListModel::showFiles() const +{ + Q_D(const QQuickFolderListModel); + return d->showFiles; +} + +void QQuickFolderListModel::setShowFiles(bool on) +{ + Q_D(QQuickFolderListModel); + + d->fileInfoThread.setShowFiles(on); + d->showFiles = on; +} + +/*! \qmlproperty bool FolderListModel::showDirs If true, directories are included in the model; otherwise only files @@ -677,15 +707,15 @@ void QQuickFolderListModel::setShowDirsFirst(bool on) bool QQuickFolderListModel::showDotAndDotDot() const { Q_D(const QQuickFolderListModel); - return d->showDots; + return d->showDotAndDotDot; } void QQuickFolderListModel::setShowDotAndDotDot(bool on) { Q_D(QQuickFolderListModel); - if (on != d->showDots) { - d->fileInfoThread.setShowDotDot(on); + if (on != d->showDotAndDotDot) { + d->fileInfoThread.setShowDotAndDotDot(on); } } @@ -723,6 +753,7 @@ void QQuickFolderListModel::setShowOnlyReadable(bool on) \list \li \c fileName \li \c filePath + \li \c fileURL \li \c fileBaseName \li \c fileSuffix \li \c fileSize diff --git a/src/imports/folderlistmodel/qquickfolderlistmodel.h b/src/imports/folderlistmodel/qquickfolderlistmodel.h index 03cb24d368..3bf9a21d49 100644 --- a/src/imports/folderlistmodel/qquickfolderlistmodel.h +++ b/src/imports/folderlistmodel/qquickfolderlistmodel.h @@ -69,11 +69,12 @@ class QQuickFolderListModel : public QAbstractListModel, public QQmlParserStatus 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 showFiles READ showFiles WRITE setShowFiles) Q_PROPERTY(bool showDirs READ showDirs WRITE setShowDirs) Q_PROPERTY(bool showDirsFirst READ showDirsFirst WRITE setShowDirsFirst) Q_PROPERTY(bool showDotAndDotDot READ showDotAndDotDot WRITE setShowDotAndDotDot) Q_PROPERTY(bool showOnlyReadable READ showOnlyReadable WRITE setShowOnlyReadable) - Q_PROPERTY(int count READ count NOTIFY rowCountChanged) + Q_PROPERTY(int count READ count NOTIFY countChanged) //![class props] //![abslistmodel] @@ -89,7 +90,8 @@ public: FileSizeRole = Qt::UserRole + 5, FileLastModifiedRole = Qt::UserRole + 6, FileLastReadRole = Qt::UserRole +7, - FileIsDirRole = Qt::UserRole + 8 + FileIsDirRole = Qt::UserRole + 8, + FileUrlRole = Qt::UserRole + 9 }; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; @@ -121,6 +123,8 @@ public: bool sortReversed() const; void setSortReversed(bool rev); + bool showFiles() const; + void setShowFiles(bool showFiles); bool showDirs() const; void setShowDirs(bool showDirs); bool showDirsFirst() const; @@ -145,6 +149,7 @@ public: Q_SIGNALS: void folderChanged(); void rowCountChanged() const; + void countChanged() const; //![notifier] //![class end] diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 7a922a832e..5bc5d61eb7 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -3,7 +3,8 @@ TEMPLATE = subdirs SUBDIRS += \ folderlistmodel \ localstorage \ - models + models \ + settings qtHaveModule(quick) { SUBDIRS += \ diff --git a/src/imports/localstorage/localstorage.pro b/src/imports/localstorage/localstorage.pro index c783404d0a..15753263b8 100644 --- a/src/imports/localstorage/localstorage.pro +++ b/src/imports/localstorage/localstorage.pro @@ -3,7 +3,7 @@ TARGET = qmllocalstorageplugin TARGETPATH = QtQuick/LocalStorage IMPORT_VERSION = 2.0 -QT = sql qml-private v8-private core-private +QT = sql qml-private core-private SOURCES += plugin.cpp diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 4877c4cfca..578c388b44 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -54,34 +54,27 @@ #include <QtCore/qcryptographichash.h> #include <QtCore/qsettings.h> #include <QtCore/qdir.h> -#include <private/qv8sqlerrors_p.h> - - -#define V8THROW_SQL(error, desc) \ -{ \ - v8::Local<v8::Value> v = v8::Exception::Error(engine->toString(desc)); \ - v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \ - v8::ThrowException(v); \ - return v8::Handle<v8::Value>(); \ -} - -#define V8THROW_SQL_VOID(error, desc) \ -{ \ - v8::Local<v8::Value> v = v8::Exception::Error(engine->toString(desc)); \ - v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \ - v8::ThrowException(v); \ - return; \ +#include <private/qv4sqlerrors_p.h> +#include <private/qv4engine_p.h> +#include <private/qv4object_p.h> +#include <private/qv4functionobject_p.h> +#include <private/qv4objectproto_p.h> +#include <private/qv4exception_p.h> + +using namespace QV4; + +#define V4THROW_SQL(error, desc) { \ + Value v = Value::fromString(ctx, desc); \ + Object *ex = ctx->engine->newErrorObject(v); \ + ex->put(ctx->engine->newIdentifier(QStringLiteral("code")), Value::fromInt32(error)); \ + ctx->throwError(Value::fromObject(ex)); \ } -#define V8THROW_REFERENCE(string) { \ - v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \ - return v8::Handle<v8::Value>(); \ +#define V4THROW_REFERENCE(string) { \ + Value v = Value::fromString(ctx, string); \ + ctx->throwReferenceError(v); \ } -#define V8THROW_REFERENCE_VOID(string) { \ - v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \ - return; \ -} class QQmlSqlDatabaseData : public QV8Engine::Deletable { @@ -89,23 +82,31 @@ public: QQmlSqlDatabaseData(QV8Engine *engine); ~QQmlSqlDatabaseData(); - v8::Persistent<v8::Function> constructor; - v8::Persistent<v8::Function> queryConstructor; - v8::Persistent<v8::Function> rowsConstructor; + PersistentValue databaseProto; + PersistentValue queryProto; + PersistentValue rowsProto; }; V8_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData) -class QV8SqlDatabaseResource : public QV8ObjectResource +class QQmlSqlDatabaseWrapper : public Object { - V8_RESOURCE_TYPE(SQLDatabaseType) + Q_MANAGED public: enum Type { Database, Query, Rows }; - QV8SqlDatabaseResource(QV8Engine *e) - : QV8ObjectResource(e), type(Database), inTransaction(false), readonly(false), forwardOnly(false) {} + QQmlSqlDatabaseWrapper(QV8Engine *e) + : Object(QV8Engine::getV4(e)), type(Database), inTransaction(false), readonly(false), forwardOnly(false) + { + vtbl = &static_vtbl; + } + + ~QQmlSqlDatabaseWrapper() { + } - ~QV8SqlDatabaseResource() { + static Value getIndexed(Managed *m, uint index, bool *hasProperty); + static void destroy(Managed *that) { + static_cast<QQmlSqlDatabaseWrapper *>(that)->~QQmlSqlDatabaseWrapper(); } Type type; @@ -116,62 +117,61 @@ public: bool inTransaction; // type == Query bool readonly; // type == Query - QSqlQuery query; // type == Rows + QSqlQuery sqlQuery; // type == Rows bool forwardOnly; // type == Rows }; -static v8::Handle<v8::Value> qmlsqldatabase_version(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) +DEFINE_MANAGED_VTABLE(QQmlSqlDatabaseWrapper); + +static Value qmlsqldatabase_version(SimpleCallContext *ctx) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This()); - if (!r || r->type != QV8SqlDatabaseResource::Database) - V8THROW_REFERENCE("Not a SQLDatabase object"); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Database) + V4THROW_REFERENCE("Not a SQLDatabase object"); - return r->engine->toString(r->version); + return Value::fromString(ctx->engine->newString(r->version)); } -static v8::Handle<v8::Value> qmlsqldatabase_rows_length(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info) +static Value qmlsqldatabase_rows_length(SimpleCallContext *ctx) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This()); - if (!r || r->type != QV8SqlDatabaseResource::Rows) - V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Rows) + V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); - int s = r->query.size(); + int s = r->sqlQuery.size(); if (s < 0) { // Inefficient - if (r->query.last()) { - s = r->query.at() + 1; + if (r->sqlQuery.last()) { + s = r->sqlQuery.at() + 1; } else { s = 0; } } - return v8::Integer::New(s); + return Value::fromInt32(s); } -static v8::Handle<v8::Value> qmlsqldatabase_rows_forwardOnly(v8::Local<v8::String> /* property */, - const v8::AccessorInfo& info) +static Value qmlsqldatabase_rows_forwardOnly(SimpleCallContext *ctx) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This()); - if (!r || r->type != QV8SqlDatabaseResource::Rows) - V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); - return v8::Boolean::New(r->query.isForwardOnly()); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Rows) + V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); + return Value::fromBoolean(r->sqlQuery.isForwardOnly()); } -static void qmlsqldatabase_rows_setForwardOnly(v8::Local<v8::String> /* property */, - v8::Local<v8::Value> value, - const v8::AccessorInfo& info) +static Value qmlsqldatabase_rows_setForwardOnly(SimpleCallContext *ctx) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This()); - if (!r || r->type != QV8SqlDatabaseResource::Rows) - V8THROW_REFERENCE_VOID("Not a SQLDatabase::Rows object"); - - r->query.setForwardOnly(value->BooleanValue()); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Rows) + V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); + if (ctx->argumentCount < 1) + ctx->throwTypeError(); + + r->sqlQuery.setForwardOnly(ctx->arguments[0].toBoolean()); + return Value::undefinedValue(); } QQmlSqlDatabaseData::~QQmlSqlDatabaseData() { - qPersistentDispose(constructor); - qPersistentDispose(queryConstructor); - qPersistentDispose(rowsConstructor); } static QString qmlsqldatabase_databasesPath(QV8Engine *engine) @@ -190,103 +190,113 @@ static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Eng return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName; } -static v8::Handle<v8::Value> qmlsqldatabase_rows_index(QV8SqlDatabaseResource *r, uint32_t index) +static Value qmlsqldatabase_rows_index(QQmlSqlDatabaseWrapper *r, ExecutionEngine *v4, quint32 index, bool *hasProperty = 0) { - if (r->query.at() == (int)index || r->query.seek(index)) { + QV8Engine *v8 = v4->v8Engine; - QSqlRecord record = r->query.record(); + if (r->sqlQuery.at() == (int)index || r->sqlQuery.seek(index)) { + QSqlRecord record = r->sqlQuery.record(); // XXX optimize - v8::Local<v8::Object> row = v8::Object::New(); + Object *row = v4->newObject(); for (int ii = 0; ii < record.count(); ++ii) { QVariant v = record.value(ii); if (v.isNull()) { - row->Set(r->engine->toString(record.fieldName(ii)), v8::Null()); + row->put(v4->newIdentifier(record.fieldName(ii)), Value::nullValue()); } else { - row->Set(r->engine->toString(record.fieldName(ii)), - r->engine->fromVariant(v)); + row->put(v4->newIdentifier(record.fieldName(ii)), v8->fromVariant(v)); } } - return row; + if (hasProperty) + *hasProperty = true; + return Value::fromObject(row); } else { - return v8::Undefined(); + if (hasProperty) + *hasProperty = false; + return Value::undefinedValue(); } } -static v8::Handle<v8::Value> qmlsqldatabase_rows_index(uint32_t index, const v8::AccessorInfo& info) +Value QQmlSqlDatabaseWrapper::getIndexed(Managed *m, uint index, bool *hasProperty) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This()); - if (!r || r->type != QV8SqlDatabaseResource::Rows) - V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + QQmlSqlDatabaseWrapper *r = m->as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Rows) + return Object::getIndexed(m, index, hasProperty); - return qmlsqldatabase_rows_index(r, index); + return qmlsqldatabase_rows_index(r, m->engine(), index, hasProperty); } -static v8::Handle<v8::Value> qmlsqldatabase_rows_item(const v8::Arguments& args) +static Value qmlsqldatabase_rows_item(SimpleCallContext *ctx) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This()); - if (!r || r->type != QV8SqlDatabaseResource::Rows) - V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Rows) + V4THROW_REFERENCE("Not a SQLDatabase::Rows object"); - return qmlsqldatabase_rows_index(r, args.Length()?args[0]->Uint32Value():0); + return qmlsqldatabase_rows_index(r, ctx->engine, ctx->argumentCount ? ctx->arguments[0].toUInt32() : 0); } -static v8::Handle<v8::Value> qmlsqldatabase_executeSql(const v8::Arguments& args) +static Value qmlsqldatabase_executeSql(SimpleCallContext *ctx) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This()); - if (!r || r->type != QV8SqlDatabaseResource::Query) - V8THROW_REFERENCE("Not a SQLDatabase::Query object"); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Query) + V4THROW_REFERENCE("Not a SQLDatabase::Query object"); - QV8Engine *engine = r->engine; + QV8Engine *engine = ctx->engine->v8Engine; if (!r->inTransaction) - V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()")); + V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()")); QSqlDatabase db = r->database; - QString sql = engine->toString(args[0]); + QString sql = ctx->argument(0).toQString(); if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) { - V8THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction")); + V4THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction")); } QSqlQuery query(db); bool err = false; - v8::Handle<v8::Value> result = v8::Undefined(); + Value result = Value::undefinedValue(); if (query.prepare(sql)) { - if (args.Length() > 1) { - v8::Local<v8::Value> values = args[1]; - if (values->IsArray()) { - v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(values); - uint32_t size = array->Length(); - for (uint32_t ii = 0; ii < size; ++ii) - query.bindValue(ii, engine->toVariant(array->Get(ii), -1)); - } else if (values->IsObject() && !values->ToObject()->GetExternalResource()) { - v8::Local<v8::Object> object = values->ToObject(); - v8::Local<v8::Array> names = object->GetPropertyNames(); - uint32_t size = names->Length(); - for (uint32_t ii = 0; ii < size; ++ii) - query.bindValue(engine->toString(names->Get(ii)), - engine->toVariant(object->Get(names->Get(ii)), -1)); + if (ctx->argumentCount > 1) { + Value values = ctx->arguments[1]; + if (ArrayObject *array = values.asArrayObject()) { + quint32 size = array->arrayLength(); + for (quint32 ii = 0; ii < size; ++ii) + query.bindValue(ii, engine->toVariant(array->getIndexed(ii), -1)); + } else if (Object *object = values.asObject()) { + ObjectIterator it(object, ObjectIterator::WithProtoChain|ObjectIterator::EnumerableOnly); + while (1) { + Value value; + Value key = it.nextPropertyName(&value); + if (key.isNull()) + break; + QVariant v = engine->toVariant(value, -1); + if (key.isString()) { + query.bindValue(key.stringValue()->toQString(), v); + } else { + assert(key.isInteger()); + query.bindValue(key.integerValue(), v); + } + } } else { query.bindValue(0, engine->toVariant(values, -1)); } } if (query.exec()) { - v8::Handle<v8::Object> rows = databaseData(engine)->rowsConstructor->NewInstance(); - QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine); - r->type = QV8SqlDatabaseResource::Rows; - r->database = db; - r->query = query; - rows->SetExternalResource(r); - - v8::Local<v8::Object> resultObject = v8::Object::New(); - result = resultObject; + QQmlSqlDatabaseWrapper *rows = new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine); + rows->setPrototype(databaseData(engine)->rowsProto.value().asObject()); + rows->type = QQmlSqlDatabaseWrapper::Rows; + rows->database = db; + rows->sqlQuery = query; + + Object *resultObject = ctx->engine->newObject(); + result = Value::fromObject(resultObject); // XXX optimize - resultObject->Set(v8::String::New("rowsAffected"), v8::Integer::New(query.numRowsAffected())); - resultObject->Set(v8::String::New("insertId"), engine->toString(query.lastInsertId().toString())); - resultObject->Set(v8::String::New("rows"), rows); + resultObject->put(ctx->engine->newIdentifier("rowsAffected"), Value::fromInt32(query.numRowsAffected())); + resultObject->put(ctx->engine->newIdentifier("insertId"), engine->toString(query.lastInsertId().toString())); + resultObject->put(ctx->engine->newIdentifier("rows"), Value::fromObject(rows)); } else { err = true; } @@ -294,153 +304,156 @@ static v8::Handle<v8::Value> qmlsqldatabase_executeSql(const v8::Arguments& args err = true; } if (err) - V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text()); + V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text()); return result; } -static v8::Handle<v8::Value> qmlsqldatabase_changeVersion(const v8::Arguments& args) +static Value qmlsqldatabase_changeVersion(SimpleCallContext *ctx) { - if (args.Length() < 2) - return v8::Undefined(); + if (ctx->argumentCount < 2) + return Value::undefinedValue(); - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This()); - if (!r || r->type != QV8SqlDatabaseResource::Database) - V8THROW_REFERENCE("Not a SQLDatabase object"); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Database) + V4THROW_REFERENCE("Not a SQLDatabase object"); - QV8Engine *engine = r->engine; + QV8Engine *engine = ctx->engine->v8Engine; QSqlDatabase db = r->database; - QString from_version = engine->toString(args[0]); - QString to_version = engine->toString(args[1]); - v8::Handle<v8::Value> callback = args[2]; + QString from_version = ctx->arguments[0].toQString(); + QString to_version = ctx->arguments[1].toQString(); + Value callback = ctx->argument(2); if (from_version != r->version) - V8THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version)); + V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version)); - v8::Local<v8::Object> instance = databaseData(engine)->queryConstructor->NewInstance(); - QV8SqlDatabaseResource *r2 = new QV8SqlDatabaseResource(engine); - r2->type = QV8SqlDatabaseResource::Query; - r2->database = db; - r2->version = r->version; - r2->inTransaction = true; - instance->SetExternalResource(r2); + QQmlSqlDatabaseWrapper *w = new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine); + w->setPrototype(databaseData(engine)->queryProto.value().asObject()); + w->type = QQmlSqlDatabaseWrapper::Query; + w->database = db; + w->version = r->version; + w->inTransaction = true; bool ok = true; - if (callback->IsFunction()) { + if (FunctionObject *f = callback.asFunctionObject()) { ok = false; db.transaction(); - v8::TryCatch tc; - v8::Handle<v8::Value> callbackArgs[] = { instance }; - v8::Handle<v8::Function>::Cast(callback)->Call(engine->global(), 1, callbackArgs); - - if (tc.HasCaught()) { + CALLDATA(1); + d.thisObject = engine->global(); + d.args[0] = Value::fromObject(w); + try { + f->call(d); + } catch (Exception &) { db.rollback(); - tc.ReThrow(); - return v8::Handle<v8::Value>(); - } else if (!db.commit()) { + throw; + } + if (!db.commit()) { db.rollback(); - V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed")); + V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed")); } else { ok = true; } } - r2->inTransaction = false; + w->inTransaction = false; if (ok) { - r2->version = to_version; + w->version = to_version; #ifndef QT_NO_SETTINGS QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat); ini.setValue(QLatin1String("Version"), to_version); #endif } - return v8::Undefined(); + return Value::undefinedValue(); } -static v8::Handle<v8::Value> qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly) +static Value qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, bool readOnly) { - QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This()); - if (!r || r->type != QV8SqlDatabaseResource::Database) - V8THROW_REFERENCE("Not a SQLDatabase object"); + QQmlSqlDatabaseWrapper *r = ctx->thisObject.as<QQmlSqlDatabaseWrapper>(); + if (!r || r->type != QQmlSqlDatabaseWrapper::Database) + V4THROW_REFERENCE("Not a SQLDatabase object"); - QV8Engine *engine = r->engine; + QV8Engine *engine = ctx->engine->v8Engine; - if (args.Length() == 0 || !args[0]->IsFunction()) - V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("transaction: missing callback")); + FunctionObject *callback = ctx->argumentCount ? ctx->arguments[0].asFunctionObject() : 0; + if (!callback) + V4THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR, QQmlEngine::tr("transaction: missing callback")); QSqlDatabase db = r->database; - v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[0]); - v8::Local<v8::Object> instance = databaseData(engine)->queryConstructor->NewInstance(); - QV8SqlDatabaseResource *q = new QV8SqlDatabaseResource(engine); - q->type = QV8SqlDatabaseResource::Query; - q->database = db; - q->readonly = readOnly; - q->inTransaction = true; - instance->SetExternalResource(q); + QQmlSqlDatabaseWrapper *w = new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine); + w->setPrototype(databaseData(engine)->queryProto.value().asObject()); + w->type = QQmlSqlDatabaseWrapper::Query; + w->database = db; + w->version = r->version; + w->readonly = readOnly; + w->inTransaction = true; db.transaction(); - v8::TryCatch tc; - v8::Handle<v8::Value> callbackArgs[] = { instance }; - callback->Call(engine->global(), 1, callbackArgs); - - q->inTransaction = false; - - if (tc.HasCaught()) { - db.rollback(); - tc.ReThrow(); - return v8::Handle<v8::Value>(); - } else if (!db.commit()) { - db.rollback(); + if (callback) { + CALLDATA(1); + d.thisObject = engine->global(); + d.args[0] = Value::fromObject(w); + try { + callback->call(d); + } catch (Exception &) { + w->inTransaction = false; + db.rollback(); + throw; + } + + w->inTransaction = false; + + if (!db.commit()) + db.rollback(); } - return v8::Undefined(); + return Value::undefinedValue(); } -static v8::Handle<v8::Value> qmlsqldatabase_transaction(const v8::Arguments& args) +static Value qmlsqldatabase_transaction(SimpleCallContext *ctx) { - return qmlsqldatabase_transaction_shared(args, false); + return qmlsqldatabase_transaction_shared(ctx, false); } -static v8::Handle<v8::Value> qmlsqldatabase_read_transaction(const v8::Arguments& args) +static Value qmlsqldatabase_read_transaction(SimpleCallContext *ctx) { - return qmlsqldatabase_transaction_shared(args, true); + return qmlsqldatabase_transaction_shared(ctx, true); } QQmlSqlDatabaseData::QQmlSqlDatabaseData(QV8Engine *engine) { + ExecutionEngine *v4 = QV8Engine::getV4(engine); { - v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetHasExternalResource(true); - ft->PrototypeTemplate()->Set(v8::String::New("transaction"), - V8FUNCTION(qmlsqldatabase_transaction, engine)); - ft->PrototypeTemplate()->Set(v8::String::New("readTransaction"), - V8FUNCTION(qmlsqldatabase_read_transaction, engine)); - ft->PrototypeTemplate()->SetAccessor(v8::String::New("version"), qmlsqldatabase_version); - ft->PrototypeTemplate()->Set(v8::String::New("changeVersion"), - V8FUNCTION(qmlsqldatabase_changeVersion, engine)); - constructor = qPersistentNew<v8::Function>(ft->GetFunction()); + Object *proto = v4->newObject(); + proto->defineDefaultProperty(v4, QStringLiteral("transaction"), qmlsqldatabase_transaction); + proto->defineDefaultProperty(v4, QStringLiteral("readTransaction"), qmlsqldatabase_read_transaction); + Property *p = proto->insertMember(v4->newString(QStringLiteral("version")), + Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->newString(QStringLiteral("version")), qmlsqldatabase_version)); + proto->defineDefaultProperty(v4, QStringLiteral("changeVersion"), qmlsqldatabase_changeVersion); + databaseProto = Value::fromObject(proto); } { - v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetHasExternalResource(true); - ft->PrototypeTemplate()->Set(v8::String::New("executeSql"), - V8FUNCTION(qmlsqldatabase_executeSql, engine)); - queryConstructor = qPersistentNew<v8::Function>(ft->GetFunction()); + Object *proto = v4->newObject(); + proto->defineDefaultProperty(v4, QStringLiteral("executeSql"), qmlsqldatabase_executeSql); + queryProto = Value::fromObject(proto); } { - v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New(); - ft->InstanceTemplate()->SetHasExternalResource(true); - ft->PrototypeTemplate()->Set(v8::String::New("item"), V8FUNCTION(qmlsqldatabase_rows_item, engine)); - ft->PrototypeTemplate()->SetAccessor(v8::String::New("length"), qmlsqldatabase_rows_length); - ft->InstanceTemplate()->SetAccessor(v8::String::New("forwardOnly"), qmlsqldatabase_rows_forwardOnly, - qmlsqldatabase_rows_setForwardOnly); - ft->InstanceTemplate()->SetIndexedPropertyHandler(qmlsqldatabase_rows_index); - rowsConstructor = qPersistentNew<v8::Function>(ft->GetFunction()); + Object *proto = v4->newObject(); + proto->defineDefaultProperty(v4, QStringLiteral("item"), qmlsqldatabase_rows_item); + Property *p = proto->insertMember(v4->newString(QStringLiteral("length")), + Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->newString(QStringLiteral("length")), qmlsqldatabase_rows_length)); + p = proto->insertMember(v4->newString(QStringLiteral("forwardOnly")), + Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); + p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->newString(QStringLiteral("forwardOnly")), qmlsqldatabase_rows_forwardOnly)); + p->setSetter(v4->newBuiltinFunction(v4->rootContext, v4->newString(QStringLiteral("setForwardOnly")), qmlsqldatabase_rows_setForwardOnly)); + rowsProto = Value::fromObject(proto); } } @@ -597,25 +610,26 @@ public: ~QQuickLocalStorage() { } - Q_INVOKABLE void openDatabaseSync(QQmlV8Function* args); + Q_INVOKABLE void openDatabaseSync(QQmlV4Function* args); }; -void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args) +void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) { #ifndef QT_NO_SETTINGS QV8Engine *engine = args->engine(); + ExecutionContext *ctx = QV8Engine::getV4(engine)->current; if (engine->engine()->offlineStoragePath().isEmpty()) - V8THROW_SQL_VOID(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled.")); + V4THROW_SQL(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled.")); qmlsqldatabase_initDatabasesPath(engine); QSqlDatabase database; - QString dbname = engine->toString((*args)[0]); - QString dbversion = engine->toString((*args)[1]); - QString dbdescription = engine->toString((*args)[2]); - int dbestimatedsize = (*args)[3]->Int32Value(); - v8::Handle<v8::Value> dbcreationCallback = (*args)[4]; + QString dbname = (*args)[0].toQString(); + QString dbversion = (*args)[1].toQString(); + QString dbdescription = (*args)[2].toQString(); + int dbestimatedsize = (*args)[3].toInt32(); + FunctionObject *dbcreationCallback = (*args)[4].asFunctionObject(); QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(dbname.toUtf8()); @@ -632,13 +646,13 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args) database = QSqlDatabase::database(dbid); version = ini.value(QLatin1String("Version")).toString(); if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty()) - V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch")); + V4THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch")); } else { created = !QFile::exists(basename+QLatin1String(".sqlite")); database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); if (created) { ini.setValue(QLatin1String("Name"), dbname); - if (dbcreationCallback->IsFunction()) + if (dbcreationCallback) version = QString(); ini.setValue(QLatin1String("Version"), version); ini.setValue(QLatin1String("Description"), dbdescription); @@ -647,7 +661,7 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args) } else { if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) { // Incompatible - V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch")); + V4THROW_SQL(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch")); } version = ini.value(QLatin1String("Version")).toString(); } @@ -657,25 +671,19 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args) database.open(); } - v8::Local<v8::Object> instance = databaseData(engine)->constructor->NewInstance(); - - QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine); - r->database = database; - r->version = version; - instance->SetExternalResource(r); - - if (created && dbcreationCallback->IsFunction()) { - v8::TryCatch tc; - v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(dbcreationCallback); - v8::Handle<v8::Value> args[] = { instance }; - callback->Call(engine->global(), 1, args); - if (tc.HasCaught()) { - tc.ReThrow(); - return; - } + QQmlSqlDatabaseWrapper *db = new (ctx->engine->memoryManager) QQmlSqlDatabaseWrapper(engine); + db->setPrototype(databaseData(engine)->databaseProto.value().asObject()); + db->database = database; + db->version = version; + + if (created && dbcreationCallback) { + CALLDATA(1); + d.thisObject = engine->global(); + d.args[0] = Value::fromObject(db); + dbcreationCallback->call(d); } - args->returnValue(instance); + args->setReturnValue(Value::fromObject(db)); #endif // QT_NO_SETTINGS } diff --git a/src/imports/localstorage/plugins.qmltypes b/src/imports/localstorage/plugins.qmltypes index ec60a142d4..bcd516c25e 100644 --- a/src/imports/localstorage/plugins.qmltypes +++ b/src/imports/localstorage/plugins.qmltypes @@ -13,7 +13,7 @@ Module { exportMetaObjectRevisions: [0] Method { name: "openDatabaseSync" - Parameter { name: "args"; type: "QQmlV8Function"; isPointer: true } + Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true } } } } diff --git a/src/imports/particles/plugins.qmltypes b/src/imports/particles/plugins.qmltypes index ee948ad7b0..495c072a41 100644 --- a/src/imports/particles/plugins.qmltypes +++ b/src/imports/particles/plugins.qmltypes @@ -163,7 +163,7 @@ Module { Property { name: "acceleration"; type: "QQuickDirection"; isPointer: true } Signal { name: "affectParticles" - Parameter { name: "particles"; type: "QQmlV8Handle" } + Parameter { name: "particles"; type: "QQmlV4Handle" } Parameter { name: "dt"; type: "double" } } Signal { @@ -664,7 +664,7 @@ Module { Property { name: "velocityFromMovement"; type: "double" } Signal { name: "emitParticles" - Parameter { name: "particles"; type: "QQmlV8Handle" } + Parameter { name: "particles"; type: "QQmlV4Handle" } } Signal { name: "particlesPerSecondChanged" @@ -1078,8 +1078,8 @@ Module { Property { name: "emitWidth"; type: "double" } Signal { name: "emitFollowParticles" - Parameter { name: "particles"; type: "QQmlV8Handle" } - Parameter { name: "followed"; type: "QQmlV8Handle" } + Parameter { name: "particles"; type: "QQmlV4Handle" } + Parameter { name: "followed"; type: "QQmlV4Handle" } } Signal { name: "particlesPerParticlePerSecondChanged" diff --git a/src/imports/qtquick2/plugins.qmltypes b/src/imports/qtquick2/plugins.qmltypes index cc619dc4ff..02c7d61536 100644 --- a/src/imports/qtquick2/plugins.qmltypes +++ b/src/imports/qtquick2/plugins.qmltypes @@ -1029,7 +1029,7 @@ Module { } Property { name: "available"; type: "bool"; isReadonly: true } Property { name: "contextType"; type: "string" } - Property { name: "context"; type: "QQmlV8Handle"; isReadonly: true } + Property { name: "context"; type: "QQmlV4Handle"; isReadonly: true } Property { name: "canvasSize"; type: "QSizeF" } Property { name: "tileSize"; type: "QSize" } Property { name: "canvasWindow"; type: "QRectF" } @@ -3929,7 +3929,7 @@ Module { Property { name: "source"; type: "QUrl" } Signal { name: "message" - Parameter { name: "messageObject"; type: "QQmlV8Handle" } + Parameter { name: "messageObject"; type: "QQmlV4Handle" } } Method { name: "sendMessage" diff --git a/src/imports/settings/plugin.cpp b/src/imports/settings/plugin.cpp new file mode 100644 index 0000000000..ce955a9e36 --- /dev/null +++ b/src/imports/settings/plugin.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQml/qqmlextensionplugin.h> +#include <QtQml/qqml.h> + +#include "qqmlsettings_p.h" + +QT_BEGIN_NAMESPACE + +class QmlSettingsPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QByteArray(uri) == QByteArray("Qt.labs.settings")); + qmlRegisterType<QQmlSettings>(uri, 1, 0, "Settings"); + } +}; + +QT_END_NAMESPACE + +#include "plugin.moc" diff --git a/src/imports/settings/plugins.qmltypes b/src/imports/settings/plugins.qmltypes new file mode 100644 index 0000000000..290c4c5570 --- /dev/null +++ b/src/imports/settings/plugins.qmltypes @@ -0,0 +1,16 @@ +import QtQuick.tooling 1.1 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated with the command 'qmlplugindump -notrelocatable Qt.labs.settings 1.0'. + +Module { + Component { + name: "QQmlSettings" + prototype: "QObject" + exports: ["Qt.labs.settings/Settings 1.0"] + exportMetaObjectRevisions: [0] + Property { name: "category"; type: "string" } + } +} diff --git a/src/imports/settings/qmldir b/src/imports/settings/qmldir new file mode 100644 index 0000000000..0d68a0742c --- /dev/null +++ b/src/imports/settings/qmldir @@ -0,0 +1,3 @@ +module Qt.labs.settings +plugin qmlsettingsplugin +typeinfo plugins.qmltypes diff --git a/src/imports/settings/qqmlsettings.cpp b/src/imports/settings/qqmlsettings.cpp new file mode 100644 index 0000000000..f73ab08cf3 --- /dev/null +++ b/src/imports/settings/qqmlsettings.cpp @@ -0,0 +1,415 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlsettings_p.h" +#include <qcoreevent.h> +#include <qsettings.h> +#include <qpointer.h> +#include <qdebug.h> +#include <qhash.h> + +QT_BEGIN_NAMESPACE + +/*! + \qmlmodule Qt.labs.settings 1.0 + \title Qt Labs Settings QML Types + \ingroup qmlmodules + \brief Provides persistent platform-independent application settings. + + To use this module, import the module with the following line: + + \code + import Qt.labs.settings 1.0 + \endcode +*/ + +/*! + \qmltype Settings + \instantiates QQmlSettings + \inqmlmodule Qt.labs.settings 1.0 + \ingroup settings + \brief Provides persistent platform-independent application settings. + + The Settings type provides persistent platform-independent application settings. + + \note This type is made available by importing the \b Qt.labs.settings module. + \e {Types in the Qt.labs module are not guaranteed to remain compatible + in future versions.} + + Users normally expect an application to remember its settings (window sizes + and positions, options, etc.) across sessions. The Settings type enables you + to save and restore such application settings with the minimum of effort. + + Individual setting values are specified by declaring properties within a + Settings element. All \l {QML Basic Types}{basic type} properties are + supported. The recommended approach is to use property aliases in order + to get automatic property updates both ways. The following example shows + how to use Settings to store and restore the geometry of a window. + + \qml + import QtQuick.Window 2.1 + import Qt.labs.settings 1.0 + + Window { + id: window + + width: 800 + height: 600 + + Settings { + property alias x: window.x + property alias y: window.y + property alias width: window.width + property alias height: window.height + } + } + \endqml + + At first application startup, the window gets default dimensions specified + as 800x600. Notice that no default position is specified - we let the window + manager handle that. Later when the window geometry changes, new values will + be automatically stored to the persistent settings. The second application + run will get initial values from the persistent settings, bringing the window + back to the previous position and size. + + A fully declarative syntax, achieved by using property aliases, comes at the + cost of storing persistent settings whenever the values of aliased properties + change. Normal properties can be used to gain more fine-grained control over + storing the persistent settings. The following example illustrates how to save + a setting on component destruction. + + \qml + import QtQuick 2.1 + import Qt.labs.settings 1.0 + + Item { + id: page + + state: settings.state + + states: [ + State { + name: "active" + // ... + }, + State { + name: "inactive" + // ... + } + ] + + Settings { + id: settings + property string state: "active" + } + + Component.onDestruction: { + settings.state = page.state + } + } + \endqml + + Notice how the default value is now specified in the persistent setting property, + and the actual property is bound to the setting in order to get the initial value + from the persistent settings. + + \section1 Application Identifiers + + Application specific settings are identified by providing application + \l {QCoreApplication::applicationName}{name}, + \l {QCoreApplication::organizationName}{organization} and + \l {QCoreApplication::organizationDomain}{domain}. + + \code + #include <QGuiApplication> + #include <QQmlApplicationEngine> + + int main(int argc, char *argv[]) + { + QGuiApplication app(argc, argv); + app.setOrganizationName("Some Company"); + app.setOrganizationDomain("somecompany.com"); + app.setApplicationName("Amazing Application"); + + QQmlApplicationEngine engine("main.qml"); + return app.exec(); + } + \endcode + + These are typically specified in C++ in the beginning of \c main(), + but can also be controlled in QML via the following properties: + \list + \li \l {Qt::application}{Qt.application.name}, + \li \l {Qt::application}{Qt.application.organization} and + \li \l {Qt::application}{Qt.application.domain}. + \endlist + + \section1 Categories + + Application settings may be divided into logical categories by specifying + a category name via the \l category property. Using logical categories not + only provides a cleaner settings structure, but also prevents possible + conflicts between setting keys. + + \qml + Item { + id: panel + + visible: true + + Settings { + category: "OutputPanel" + property alias visible: panel.visible + // ... + } + } + \endqml + + Instead of ensuring that all settings in the application have unique names, + the settings can be divided into unique categories that may then contain + settings using the same names that are used in other categories - without + a conflict. + + \section1 Notes + + The current implementation is based on \l QSettings. This imposes certain + limitations, such as missing change notifications. Writing a setting value + using one instance of Settings does not update the value in another Settings + instance, even if they are referring to the same setting in the same category. + + The information is stored in the system registry on Windows, and in XML + preferences files on OS X. On other Unix systems, in the absence of a + standard, INI text files are used. See \l QSettings documentation for + more details. + + \sa QSettings +*/ + +// #define SETTINGS_DEBUG + +static const int settingsWriteDelay = 500; + +class QQmlSettingsPrivate +{ + Q_DECLARE_PUBLIC(QQmlSettings) + +public: + QQmlSettingsPrivate(); + + QSettings *instance() const; + + void init(); + void reset(); + + void load(); + void store(); + + void _q_propertyChanged(); + + QQmlSettings *q_ptr; + int timerId; + bool initialized; + QString category; + mutable QPointer<QSettings> settings; + QHash<const char *, QVariant> changedProperties; +}; + +QQmlSettingsPrivate::QQmlSettingsPrivate() + : q_ptr(0), timerId(0), initialized(false) +{ +} + +QSettings *QQmlSettingsPrivate::instance() const +{ + if (!settings) { + QQmlSettings *q = const_cast<QQmlSettings*>(q_func()); + settings = new QSettings(q); + if (!category.isEmpty()) + settings->beginGroup(category); + if (initialized) + q->d_func()->load(); + } + return settings; +} + +void QQmlSettingsPrivate::init() +{ + if (!initialized) { + load(); + initialized = true; + } +} + +void QQmlSettingsPrivate::reset() +{ + if (initialized && settings && !changedProperties.isEmpty()) + store(); + delete settings; +} + +void QQmlSettingsPrivate::load() +{ + Q_Q(QQmlSettings); + const QMetaObject *mo = q->metaObject(); + const int offset = mo->propertyOffset(); + const int count = mo->propertyCount(); + for (int i = offset; i < count; ++i) { + QMetaProperty property = mo->property(i); + + const QVariant previousValue = property.read(q); + const QVariant currentValue = instance()->value(property.name(), previousValue); + + if (!currentValue.isNull() + && currentValue.canConvert(previousValue.type()) + && previousValue != currentValue) { + property.write(q, currentValue); +#ifdef SETTINGS_DEBUG + qDebug() << "QQmlSettings: load" << property.name() << "setting:" << currentValue << "default:" << previousValue; +#endif + } + + // ensure that a non-existent setting gets written + // even if the property wouldn't change later + if (!instance()->contains(property.name())) + _q_propertyChanged(); + + // setup change notifications on first load + if (!initialized && property.hasNotifySignal()) { + static const int propertyChangedIndex = mo->indexOfSlot("_q_propertyChanged()"); + QMetaObject::connect(q, property.notifySignalIndex(), q, propertyChangedIndex); + } + } +} + +void QQmlSettingsPrivate::store() +{ + QHash<const char *, QVariant>::iterator it = changedProperties.begin(); + while (it != changedProperties.end()) { + instance()->setValue(it.key(), it.value()); +#ifdef SETTINGS_DEBUG + qDebug() << "QQmlSettings: store" << it.key() << ":" << it.value(); +#endif + it = changedProperties.erase(it); + } +} + +void QQmlSettingsPrivate::_q_propertyChanged() +{ + Q_Q(QQmlSettings); + const QMetaObject *mo = q->metaObject(); + const int offset = mo->propertyOffset(); + const int count = mo->propertyCount(); + for (int i = offset; i < count; ++i) { + const QMetaProperty &property = mo->property(i); + changedProperties.insert(property.name(), property.read(q)); + #ifdef SETTINGS_DEBUG + qDebug() << "QQmlSettings: cache" << property.name() << ":" << property.read(q); + #endif + } + if (timerId != 0) + q->killTimer(timerId); + timerId = q->startTimer(settingsWriteDelay); +} + +QQmlSettings::QQmlSettings(QObject *parent) + : QObject(parent), d_ptr(new QQmlSettingsPrivate) +{ + Q_D(QQmlSettings); + d->q_ptr = this; +} + +QQmlSettings::~QQmlSettings() +{ + Q_D(QQmlSettings); + d->reset(); // flush pending changes +} + +/*! + \qmlproperty string Settings::category + + This property holds the name of the settings category. + + Categories can be used to group related settings together. +*/ +QString QQmlSettings::category() const +{ + Q_D(const QQmlSettings); + return d->category; +} + +void QQmlSettings::setCategory(const QString &category) +{ + Q_D(QQmlSettings); + if (d->category != category) { + d->reset(); + d->category = category; + if (d->initialized) + d->load(); + } +} + +void QQmlSettings::classBegin() +{ +} + +void QQmlSettings::componentComplete() +{ + Q_D(QQmlSettings); + d->init(); +} + +void QQmlSettings::timerEvent(QTimerEvent *event) +{ + Q_D(QQmlSettings); + if (event->timerId() == d->timerId) { + if (d->changedProperties.isEmpty()) { + killTimer(d->timerId); + d->timerId = 0; + } else { + d->store(); + } + } + QObject::timerEvent(event); +} + +QT_END_NAMESPACE + +#include "moc_qqmlsettings_p.cpp" diff --git a/src/imports/settings/qqmlsettings_p.h b/src/imports/settings/qqmlsettings_p.h new file mode 100644 index 0000000000..b5e25469dc --- /dev/null +++ b/src/imports/settings/qqmlsettings_p.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 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, Digia gives you certain additional +** rights. These rights are described in the Digia 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. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLSETTINGS_P_H +#define QQMLSETTINGS_P_H + +#include <QtQml/qqml.h> +#include <QtCore/qobject.h> +#include <QtCore/qscopedpointer.h> +#include <QtQml/qqmlparserstatus.h> + +QT_BEGIN_NAMESPACE + +class QQmlSettingsPrivate; + +class QQmlSettings : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) + Q_PROPERTY(QString category READ category WRITE setCategory FINAL) + +public: + explicit QQmlSettings(QObject *parent = 0); + ~QQmlSettings(); + + QString category() const; + void setCategory(const QString &category); + +protected: + void timerEvent(QTimerEvent *event); + + void classBegin(); + void componentComplete(); + +private: + Q_DISABLE_COPY(QQmlSettings) + Q_DECLARE_PRIVATE(QQmlSettings) + QScopedPointer<QQmlSettingsPrivate> d_ptr; + Q_PRIVATE_SLOT(d_func(), void _q_propertyChanged()) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQmlSettings) + +#endif // QQMLSETTINGS_P_H diff --git a/src/imports/settings/settings.pro b/src/imports/settings/settings.pro new file mode 100644 index 0000000000..29229f59cb --- /dev/null +++ b/src/imports/settings/settings.pro @@ -0,0 +1,15 @@ +CXX_MODULE = qml +TARGET = qmlsettingsplugin +TARGETPATH = Qt/labs/settings +IMPORT_VERSION = 1.0 + +QT = core qml + +HEADERS += \ + qqmlsettings_p.h + +SOURCES += \ + plugin.cpp \ + qqmlsettings.cpp + +load(qml_plugin) diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 0bec4cddf2..1544bb2799 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -42,6 +42,7 @@ import QtQuick 2.0 import QtTest 1.0 import "testlogger.js" as TestLogger +import Qt.test.qtestroot 1.0 Item { id: testCase @@ -66,7 +67,7 @@ Item { // other test failed which this one depends on). property bool optional: false - property bool windowShown: qtest.windowShown + property bool windowShown: QTestRootObject.windowShown // Internal private state. Identifiers prefixed with qtest are reserved. property bool qtest_prevWhen: true @@ -290,14 +291,21 @@ Item { return qtest_results.grabImage(item); } - function tryCompare(obj, prop, value, timeout) { + function tryCompare(obj, prop, value, timeout, msg) { if (arguments.length == 2) { qtest_results.fail("A value is required for tryCompare", util.callerFile(), util.callerLine()) throw new Error("QtQuickTest::fail") } + if (timeout !== undefined && typeof(timeout) != "number") { + qtest_results.fail("timeout should be a number", + util.callerFile(), util.callerLine()) + throw new Error("QtQuickTest::fail") + } if (!timeout) timeout = 5000 + if (msg === undefined) + msg = "property " + prop if (!qtest_compareInternal(obj[prop], value)) wait(0) var i = 0 @@ -309,7 +317,7 @@ Item { var act = qtest_results.stringify(actual) var exp = qtest_results.stringify(value) var success = qtest_compareInternal(actual, value) - if (!qtest_results.compare(success, "property " + prop, act, exp, util.callerFile(), util.callerLine())) + if (!qtest_results.compare(success, msg, act, exp, util.callerFile(), util.callerLine())) throw new Error("QtQuickTest::fail") } @@ -737,7 +745,7 @@ Item { Component.onCompleted: { - qtest.hasTestCase = true; + QTestRootObject.hasTestCase = true; qtest_componentCompleted = true; if (util.printAvailableFunctions) { diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp index 2ddb9deddc..6e4a397f4a 100644 --- a/src/imports/testlib/main.cpp +++ b/src/imports/testlib/main.cpp @@ -82,7 +82,7 @@ Q_SIGNALS: public Q_SLOTS: - QQmlV8Handle typeName(const QVariant& v) const + QQmlV4Handle typeName(const QVariant& v) const { QString name(v.typeName()); if (v.canConvert<QObject*>()) { @@ -97,31 +97,33 @@ public Q_SLOTS: } } - return QQmlV8Handle::fromHandle(v8::String::New(name.toUtf8())); + QQmlEngine *engine = qmlEngine(this); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle()); + return QQmlV4Handle(QV4::Value::fromString(v4->newString(name))); } bool compare(const QVariant& act, const QVariant& exp) const { return act == exp; } - QQmlV8Handle callerFile(int frameIndex = 0) const + QQmlV4Handle callerFile(int frameIndex = 0) const { - v8::Local<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); - int count = stacks->GetFrameCount(); - if (count >= frameIndex + 1) { - v8::Local<v8::StackFrame> frame = stacks->GetFrame(frameIndex + 1); - return QQmlV8Handle::fromHandle(frame->GetScriptNameOrSourceURL()); - } - return QQmlV8Handle(); + QQmlEngine *engine = qmlEngine(this); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle()); + + QVector<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 2); + if (stack.size() > frameIndex + 1) + return QQmlV4Handle(QV4::Value::fromString(v4->newString(stack.at(frameIndex + 1).source))); + return QQmlV4Handle(); } int callerLine(int frameIndex = 0) const { - v8::Local<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); - int count = stacks->GetFrameCount(); - if (count >= frameIndex + 1) { - v8::Local<v8::StackFrame> frame = stacks->GetFrame(frameIndex + 1); - return frame->GetLineNumber(); - } + QQmlEngine *engine = qmlEngine(this); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle()); + + QVector<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 2); + if (stack.size() > frameIndex + 1) + return stack.at(frameIndex + 1).line; return -1; } }; diff --git a/src/imports/testlib/plugins.qmltypes b/src/imports/testlib/plugins.qmltypes index 7530e490f3..2865812eb2 100644 --- a/src/imports/testlib/plugins.qmltypes +++ b/src/imports/testlib/plugins.qmltypes @@ -259,7 +259,7 @@ Module { Property { name: "dragThreshold"; type: "int"; isReadonly: true } Method { name: "typeName" - type: "QQmlV8Handle" + type: "QQmlV4Handle" Parameter { name: "v"; type: "QVariant" } } Method { @@ -270,10 +270,10 @@ Module { } Method { name: "callerFile" - type: "QQmlV8Handle" + type: "QQmlV4Handle" Parameter { name: "frameIndex"; type: "int" } } - Method { name: "callerFile"; type: "QQmlV8Handle" } + Method { name: "callerFile"; type: "QQmlV4Handle" } Method { name: "callerLine" type: "int" diff --git a/src/imports/testlib/testcase.qdoc b/src/imports/testlib/testcase.qdoc index 56fcb24beb..dd1d9e5ad3 100644 --- a/src/imports/testlib/testcase.qdoc +++ b/src/imports/testlib/testcase.qdoc @@ -367,11 +367,12 @@ */ /*! - \qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000) + \qmlmethod TestCase::tryCompare(obj, property, expected, timeout = 5000, message = "") Fails the current test case if the specified \a property on \a obj - is not the same as \a expected. The test will be retried multiple - times until the \a timeout (in milliseconds) is reached. + is not the same as \a expected, and displays the optional \a message. + The test will be retried multiple times until the + \a timeout (in milliseconds) is reached. This function is intended for testing applications where a property changes value based on asynchronous events. Use compare() for testing diff --git a/src/imports/testlib/testlib.pro b/src/imports/testlib/testlib.pro index 56f0ea4806..6e8a6aee72 100644 --- a/src/imports/testlib/testlib.pro +++ b/src/imports/testlib/testlib.pro @@ -3,7 +3,7 @@ TARGET = qmltestplugin TARGETPATH = QtTest IMPORT_VERSION = 1.0 -QT += qml quick qmltest qmltest-private v8-private qml-private core-private testlib +QT += qml quick qmltest qmltest-private qml-private core-private testlib SOURCES += main.cpp diff --git a/src/imports/widgets/qquickqfiledialog.cpp b/src/imports/widgets/qquickqfiledialog.cpp index 498e34a24c..c3991b4f3c 100644 --- a/src/imports/widgets/qquickqfiledialog.cpp +++ b/src/imports/widgets/qquickqfiledialog.cpp @@ -50,68 +50,6 @@ QT_BEGIN_NAMESPACE -class QFileDialogHelper : public QPlatformFileDialogHelper -{ -public: - QFileDialogHelper() : - QPlatformFileDialogHelper() - { - connect(&m_dialog, SIGNAL(currentChanged(const QString&)), this, SIGNAL(currentChanged(const QString&))); - connect(&m_dialog, SIGNAL(directoryEntered(const QString&)), this, SIGNAL(directoryEntered(const QString&))); - connect(&m_dialog, SIGNAL(fileSelected(const QString&)), this, SIGNAL(fileSelected(const QString&))); - connect(&m_dialog, SIGNAL(filesSelected(const QStringList&)), this, SIGNAL(filesSelected(const QStringList&))); - connect(&m_dialog, SIGNAL(filterSelected(const QString&)), this, SIGNAL(filterSelected(const QString&))); - connect(&m_dialog, SIGNAL(accepted()), this, SIGNAL(accept())); - connect(&m_dialog, SIGNAL(rejected()), this, SIGNAL(reject())); - } - - virtual bool defaultNameFilterDisables() const { return true; } - virtual void setDirectory(const QString &dir) { m_dialog.setDirectory(dir); } - virtual QString directory() const { return m_dialog.directory().absolutePath(); } - virtual void selectFile(const QString &f) { m_dialog.selectFile(f); } - virtual QStringList selectedFiles() const { return m_dialog.selectedFiles(); } - - virtual void setFilter() { - m_dialog.setWindowTitle(QPlatformFileDialogHelper::options()->windowTitle()); - if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::LookIn)) - m_dialog.setLabelText(m_dialog.LookIn, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::LookIn)); - if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::FileName)) - m_dialog.setLabelText(m_dialog.FileName, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::FileName)); - if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::FileType)) - m_dialog.setLabelText(m_dialog.FileType, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::FileType)); - if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::Accept)) - m_dialog.setLabelText(m_dialog.Accept, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::Accept)); - if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::Reject)) - m_dialog.setLabelText(m_dialog.Reject, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::Reject)); - m_dialog.setFilter(QPlatformFileDialogHelper::options()->filter()); - m_dialog.setNameFilters(QPlatformFileDialogHelper::options()->nameFilters()); - m_dialog.selectNameFilter(QPlatformFileDialogHelper::options()->initiallySelectedNameFilter()); - m_dialog.setFileMode(QFileDialog::FileMode(QPlatformFileDialogHelper::options()->fileMode())); - m_dialog.setOptions((QFileDialog::Options)((int)(QPlatformFileDialogHelper::options()->options()))); - m_dialog.setAcceptMode(QFileDialog::AcceptMode(QPlatformFileDialogHelper::options()->acceptMode())); - } - - virtual void selectNameFilter(const QString &f) { m_dialog.selectNameFilter(f); } - virtual QString selectedNameFilter() const { return m_dialog.selectedNameFilter(); } - virtual void exec() { m_dialog.exec(); } - - virtual bool show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) { - m_dialog.winId(); - QWindow *window = m_dialog.windowHandle(); - Q_ASSERT(window); - window->setTransientParent(parent); - window->setFlags(f); - m_dialog.setWindowModality(m); - m_dialog.show(); - return m_dialog.isVisible(); - } - - virtual void hide() { m_dialog.hide(); } - -private: - QFileDialog m_dialog; -}; - /*! \qmltype QtFileDialog \instantiates QQuickQFileDialog @@ -190,8 +128,8 @@ QPlatformFileDialogHelper *QQuickQFileDialog::helper() if (!m_dlgHelper) { m_dlgHelper = new QFileDialogHelper(); - connect(m_dlgHelper, SIGNAL(directoryEntered(QString)), this, SIGNAL(folderChanged())); - connect(m_dlgHelper, SIGNAL(filterSelected(QString)), this, SIGNAL(filterSelected())); + connect(m_dlgHelper, SIGNAL(directoryEntered(const QUrl &)), this, SIGNAL(folderChanged())); + connect(m_dlgHelper, SIGNAL(filterSelected(const QString &)), this, SIGNAL(filterSelected())); connect(m_dlgHelper, SIGNAL(accept()), this, SLOT(accept())); connect(m_dlgHelper, SIGNAL(reject()), this, SLOT(reject())); } @@ -199,4 +137,75 @@ QPlatformFileDialogHelper *QQuickQFileDialog::helper() return m_dlgHelper; } +QFileDialogHelper::QFileDialogHelper() : + QPlatformFileDialogHelper() +{ + connect(&m_dialog, SIGNAL(currentChanged(const QString&)), this, SLOT(currentChanged(const QString&))); + connect(&m_dialog, SIGNAL(directoryEntered(const QString&)), this, SLOT(directoryEntered(const QString&))); + connect(&m_dialog, SIGNAL(fileSelected(const QString&)), this, SLOT(fileSelected(const QString&))); + connect(&m_dialog, SIGNAL(filesSelected(const QStringList&)), this, SLOT(filesSelected(const QStringList&))); + connect(&m_dialog, SIGNAL(filterSelected(const QString&)), this, SIGNAL(filterSelected(const QString&))); + connect(&m_dialog, SIGNAL(accepted()), this, SIGNAL(accept())); + connect(&m_dialog, SIGNAL(rejected()), this, SIGNAL(reject())); +} + +QList<QUrl> QFileDialogHelper::selectedFiles() const +{ + return m_dialog.selectedUrls(); +} + +void QFileDialogHelper::setFilter() { + m_dialog.setWindowTitle(QPlatformFileDialogHelper::options()->windowTitle()); + if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::LookIn)) + m_dialog.setLabelText(m_dialog.LookIn, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::LookIn)); + if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::FileName)) + m_dialog.setLabelText(m_dialog.FileName, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::FileName)); + if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::FileType)) + m_dialog.setLabelText(m_dialog.FileType, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::FileType)); + if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::Accept)) + m_dialog.setLabelText(m_dialog.Accept, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::Accept)); + if (QPlatformFileDialogHelper::options()->isLabelExplicitlySet(QFileDialogOptions::Reject)) + m_dialog.setLabelText(m_dialog.Reject, QPlatformFileDialogHelper::options()->labelText(QFileDialogOptions::Reject)); + m_dialog.setFilter(QPlatformFileDialogHelper::options()->filter()); + m_dialog.setNameFilters(QPlatformFileDialogHelper::options()->nameFilters()); + m_dialog.selectNameFilter(QPlatformFileDialogHelper::options()->initiallySelectedNameFilter()); + m_dialog.setFileMode(QFileDialog::FileMode(QPlatformFileDialogHelper::options()->fileMode())); + m_dialog.setOptions((QFileDialog::Options)((int)(QPlatformFileDialogHelper::options()->options()))); + m_dialog.setAcceptMode(QFileDialog::AcceptMode(QPlatformFileDialogHelper::options()->acceptMode())); +} + +bool QFileDialogHelper::show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) { + m_dialog.winId(); + QWindow *window = m_dialog.windowHandle(); + Q_ASSERT(window); + window->setTransientParent(parent); + window->setFlags(f); + m_dialog.setWindowModality(m); + m_dialog.show(); + return m_dialog.isVisible(); +} + +void QFileDialogHelper::currentChanged(const QString& path) +{ + emit QPlatformFileDialogHelper::currentChanged(QUrl::fromLocalFile(path)); +} + +void QFileDialogHelper::directoryEntered(const QString& path) +{ + emit QPlatformFileDialogHelper::directoryEntered(QUrl::fromLocalFile(path)); +} + +void QFileDialogHelper::fileSelected(const QString& path) +{ + emit QPlatformFileDialogHelper::fileSelected(QUrl::fromLocalFile(path)); +} + +void QFileDialogHelper::filesSelected(const QStringList& paths) +{ + QList<QUrl> pathUrls; + foreach (const QString &path, paths) + pathUrls << QUrl::fromLocalFile(path); + emit QPlatformFileDialogHelper::filesSelected(pathUrls); +} + QT_END_NAMESPACE diff --git a/src/imports/widgets/qquickqfiledialog_p.h b/src/imports/widgets/qquickqfiledialog_p.h index 73067f796c..8bf7c73882 100644 --- a/src/imports/widgets/qquickqfiledialog_p.h +++ b/src/imports/widgets/qquickqfiledialog_p.h @@ -53,6 +53,7 @@ // We mean it. // +#include <QFileDialog> #include "../dialogs/qquickabstractfiledialog_p.h" QT_BEGIN_NAMESPACE @@ -71,6 +72,34 @@ protected: Q_DISABLE_COPY(QQuickQFileDialog) }; +class QFileDialogHelper : public QPlatformFileDialogHelper +{ + Q_OBJECT +public: + QFileDialogHelper(); + + bool defaultNameFilterDisables() const Q_DECL_OVERRIDE { return true; } + void setDirectory(const QUrl &dir) Q_DECL_OVERRIDE { m_dialog.setDirectoryUrl(dir); } + QUrl directory() const Q_DECL_OVERRIDE { return m_dialog.directoryUrl(); } + void selectFile(const QUrl &f) Q_DECL_OVERRIDE { m_dialog.selectUrl(f); } + QList<QUrl> selectedFiles() const Q_DECL_OVERRIDE; + void setFilter() Q_DECL_OVERRIDE; + void selectNameFilter(const QString &f) Q_DECL_OVERRIDE { m_dialog.selectNameFilter(f); } + QString selectedNameFilter() const Q_DECL_OVERRIDE { return m_dialog.selectedNameFilter(); } + void exec() Q_DECL_OVERRIDE { m_dialog.exec(); } + bool show(Qt::WindowFlags f, Qt::WindowModality m, QWindow *parent) Q_DECL_OVERRIDE; + void hide() Q_DECL_OVERRIDE { m_dialog.hide(); } + +private slots: + void currentChanged(const QString& path); + void directoryEntered(const QString& path); + void fileSelected(const QString& path); + void filesSelected(const QStringList& paths); + +private: + QFileDialog m_dialog; +}; + QT_END_NAMESPACE QML_DECLARE_TYPE(QQuickQFileDialog *) diff --git a/src/imports/widgets/widgets.pro b/src/imports/widgets/widgets.pro index c444674a75..7e6a04161a 100644 --- a/src/imports/widgets/widgets.pro +++ b/src/imports/widgets/widgets.pro @@ -18,6 +18,6 @@ HEADERS += \ ../dialogs/qquickabstractcolordialog_p.h \ ../dialogs/qquickabstractdialog_p.h -QT += quick-private gui-private core-private qml-private v8-private widgets +QT += quick-private gui-private core-private qml-private widgets load(qml_plugin) diff --git a/src/imports/xmllistmodel/plugins.qmltypes b/src/imports/xmllistmodel/plugins.qmltypes index 2a431ebf81..d951d07719 100644 --- a/src/imports/xmllistmodel/plugins.qmltypes +++ b/src/imports/xmllistmodel/plugins.qmltypes @@ -40,7 +40,7 @@ Module { Method { name: "reload" } Method { name: "get" - type: "QQmlV8Handle" + type: "QQmlV4Handle" Parameter { name: "index"; type: "int" } } Method { name: "errorString"; type: "string" } diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp index 856c063cbb..c12bfee924 100644 --- a/src/imports/xmllistmodel/qqmlxmllistmodel.cpp +++ b/src/imports/xmllistmodel/qqmlxmllistmodel.cpp @@ -43,6 +43,10 @@ #include <qqmlcontext.h> #include <private/qqmlengine_p.h> +#include <private/qv8engine_p.h> +#include <private/qv4value_p.h> +#include <private/qv4engine_p.h> +#include <private/qv4object_p.h> #include <QDebug> #include <QStringList> @@ -63,6 +67,7 @@ Q_DECLARE_METATYPE(QQuickXmlQueryResult) QT_BEGIN_NAMESPACE +using namespace QV4; typedef QPair<int, int> QQuickXmlListRange; @@ -388,8 +393,7 @@ void QQuickXmlQueryEngine::doQueryJob(XmlQueryJob *currentJob, QQuickXmlQueryRes 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('/'))); + QString prefix = QLatin1String("doc($inputDocument)/dummy:items/*"); //figure out how many items we are dealing with int count = -1; @@ -908,22 +912,24 @@ void QQuickXmlListModel::setNamespaceDeclarations(const QString &declarations) var title = model.get(0).title; \endjs */ -QQmlV8Handle QQuickXmlListModel::get(int index) const +QQmlV4Handle QQuickXmlListModel::get(int index) const { // Must be called with a context and handle scope Q_D(const QQuickXmlListModel); if (index < 0 || index >= count()) - return QQmlV8Handle::fromHandle(v8::Undefined()); + return QQmlV4Handle(Value::undefinedValue()); QQmlEngine *engine = qmlContext(this)->engine(); QV8Engine *v8engine = QQmlEnginePrivate::getV8Engine(engine); - v8::Local<v8::Object> 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))); + ExecutionEngine *v4engine = QV8Engine::getV4(v8engine); + Object *o = v4engine->newObject(); + for (int ii = 0; ii < d->roleObjects.count(); ++ii) { + Property *p = o->insertMember(v4engine->newIdentifier(d->roleObjects[ii]->name()), PropertyAttributes()); + p->value = v8engine->fromVariant(d->data.value(ii).value(index)); + } - return QQmlV8Handle::fromHandle(rv); + return QQmlV4Handle(Value::fromObject(o)); } /*! diff --git a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h index 0a11cc6e28..ca4b7cf811 100644 --- a/src/imports/xmllistmodel/qqmlxmllistmodel_p.h +++ b/src/imports/xmllistmodel/qqmlxmllistmodel_p.h @@ -107,7 +107,7 @@ public: QString namespaceDeclarations() const; void setNamespaceDeclarations(const QString&); - Q_INVOKABLE QQmlV8Handle get(int index) const; + Q_INVOKABLE QQmlV4Handle get(int index) const; enum Status { Null, Ready, Loading, Error }; Status status() const; diff --git a/src/imports/xmllistmodel/xmllistmodel.pro b/src/imports/xmllistmodel/xmllistmodel.pro index c2cb4bbd89..2308f26d1b 100644 --- a/src/imports/xmllistmodel/xmllistmodel.pro +++ b/src/imports/xmllistmodel/xmllistmodel.pro @@ -3,7 +3,7 @@ TARGET = qmlxmllistmodelplugin TARGETPATH = QtQuick/XmlListModel IMPORT_VERSION = 2.0 -QT = network xmlpatterns qml-private v8-private core-private +QT = network xmlpatterns qml-private core-private SOURCES += qqmlxmllistmodel.cpp plugin.cpp HEADERS += qqmlxmllistmodel_p.h |