From b2869013fdfb76d60ce8750e24614111f78fef5c Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Tue, 24 Jan 2012 16:07:24 +1000 Subject: Move sqldatabase into a module API plugin Change-Id: Icd0bbfe16804abf1bbadbabddf3a30b5b18df30c Reviewed-by: Martin Jones --- src/imports/imports.pro | 4 +- src/imports/localstorage/localstorage.pro | 15 + src/imports/localstorage/plugin.cpp | 668 ++++++++++++++++++++++++++++++ src/imports/localstorage/qmldir | 1 + 4 files changed, 686 insertions(+), 2 deletions(-) create mode 100644 src/imports/localstorage/localstorage.pro create mode 100644 src/imports/localstorage/plugin.cpp create mode 100644 src/imports/localstorage/qmldir (limited to 'src/imports') diff --git a/src/imports/imports.pro b/src/imports/imports.pro index 18400f86f2..ea8e78d01e 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -1,5 +1,5 @@ TEMPLATE = subdirs -SUBDIRS += qtquick2 qtquick1 qt47 folderlistmodel particles gestures etcprovider +SUBDIRS += qtquick2 qtquick1 qt47 folderlistmodel particles gestures etcprovider localstorage contains(QT_CONFIG, qmltest): SUBDIRS += testlib -contains(QT_CONFIG, xmlpatterns) : SUBDIRS += xmllistmodel +contains(QT_CONFIG, xmlpatterns) : SUBDIRS += xmllistmodel \ No newline at end of file diff --git a/src/imports/localstorage/localstorage.pro b/src/imports/localstorage/localstorage.pro new file mode 100644 index 0000000000..51a69aac4f --- /dev/null +++ b/src/imports/localstorage/localstorage.pro @@ -0,0 +1,15 @@ +TARGET = qmllocalstorageplugin +TARGETPATH = QtQuick/LocalStorage +include(../qimportbase.pri) + +QT += sql declarative declarative-private v8-private core-private + +SOURCES += plugin.cpp + +DESTDIR = $$QT.declarative.imports/$$TARGETPATH +target.path = $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +qmldir.files += $$PWD/qmldir +qmldir.path += $$[QT_INSTALL_IMPORTS]/$$TARGETPATH + +INSTALLS += target qmldir \ No newline at end of file diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp new file mode 100644 index 0000000000..dba7340fa3 --- /dev/null +++ b/src/imports/localstorage/plugin.cpp @@ -0,0 +1,668 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define V8THROW_SQL(error, desc) \ +{ \ + v8::Local v = v8::Exception::Error(engine->toString(desc)); \ + v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \ + v8::ThrowException(v); \ + return v8::Handle(); \ +} + +#define V8THROW_SQL_VOID(error, desc) \ +{ \ + v8::Local v = v8::Exception::Error(engine->toString(desc)); \ + v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \ + v8::ThrowException(v); \ + return; \ +} + +#define V8THROW_REFERENCE(string) { \ + v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \ + return v8::Handle(); \ +} + +#define V8THROW_REFERENCE_VOID(string) { \ + v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \ + return; \ +} + +class QDeclarativeSqlDatabaseData : public QV8Engine::Deletable +{ +public: + QDeclarativeSqlDatabaseData(QV8Engine *engine); + ~QDeclarativeSqlDatabaseData(); + + v8::Persistent constructor; + v8::Persistent queryConstructor; + v8::Persistent rowsConstructor; +}; + +V8_DEFINE_EXTENSION(QDeclarativeSqlDatabaseData, databaseData) + +class QV8SqlDatabaseResource : public QV8ObjectResource +{ + V8_RESOURCE_TYPE(SQLDatabaseType) + +public: + enum Type { Database, Query, Rows }; + QV8SqlDatabaseResource(QV8Engine *e) + : QV8ObjectResource(e), type(Database), inTransaction(false), readonly(false), forwardOnly(false) {} + + ~QV8SqlDatabaseResource() { + } + + Type type; + QSqlDatabase database; + + QString version; // type == Database + + bool inTransaction; // type == Query + bool readonly; // type == Query + + QSqlQuery query; // type == Rows + bool forwardOnly; // type == Rows +}; + +static v8::Handle qmlsqldatabase_version(v8::Local /* property */, const v8::AccessorInfo& info) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(info.This()); + if (!r || r->type != QV8SqlDatabaseResource::Database) + V8THROW_REFERENCE("Not a SQLDatabase object"); + + return r->engine->toString(r->version); +} + +static v8::Handle qmlsqldatabase_rows_length(v8::Local /* property */, const v8::AccessorInfo& info) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(info.This()); + if (!r || r->type != QV8SqlDatabaseResource::Rows) + V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + + int s = r->query.size(); + if (s < 0) { + // Inefficient + if (r->query.last()) { + s = r->query.at() + 1; + } else { + s = 0; + } + } + return v8::Integer::New(s); +} + +static v8::Handle qmlsqldatabase_rows_forwardOnly(v8::Local /* property */, + const v8::AccessorInfo& info) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(info.This()); + if (!r || r->type != QV8SqlDatabaseResource::Rows) + V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + return v8::Boolean::New(r->query.isForwardOnly()); +} + +static void qmlsqldatabase_rows_setForwardOnly(v8::Local /* property */, + v8::Local value, + const v8::AccessorInfo& info) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(info.This()); + if (!r || r->type != QV8SqlDatabaseResource::Rows) + V8THROW_REFERENCE_VOID("Not a SQLDatabase::Rows object"); + + r->query.setForwardOnly(value->BooleanValue()); +} + +QDeclarativeSqlDatabaseData::~QDeclarativeSqlDatabaseData() +{ + qPersistentDispose(constructor); + qPersistentDispose(queryConstructor); + qPersistentDispose(rowsConstructor); +} + +static QString qmlsqldatabase_databasesPath(QV8Engine *engine) +{ + return engine->engine()->offlineStoragePath() + + QDir::separator() + QLatin1String("Databases"); +} + +static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine) +{ + QDir().mkpath(qmlsqldatabase_databasesPath(engine)); +} + +static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine) +{ + return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName; +} + +static v8::Handle qmlsqldatabase_rows_index(QV8SqlDatabaseResource *r, uint32_t index) +{ + if (r->query.at() == (int)index || r->query.seek(index)) { + + QSqlRecord record = r->query.record(); + // XXX optimize + v8::Local row = v8::Object::New(); + 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()); + } else { + row->Set(r->engine->toString(record.fieldName(ii)), + r->engine->fromVariant(v)); + } + } + return row; + } else { + return v8::Undefined(); + } +} + +static v8::Handle qmlsqldatabase_rows_index(uint32_t index, const v8::AccessorInfo& info) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(info.This()); + if (!r || r->type != QV8SqlDatabaseResource::Rows) + V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + + return qmlsqldatabase_rows_index(r, index); +} + +static v8::Handle qmlsqldatabase_rows_item(const v8::Arguments& args) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(args.This()); + if (!r || r->type != QV8SqlDatabaseResource::Rows) + V8THROW_REFERENCE("Not a SQLDatabase::Rows object"); + + return qmlsqldatabase_rows_index(r, args.Length()?args[0]->Uint32Value():0); +} + +static v8::Handle qmlsqldatabase_executeSql(const v8::Arguments& args) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(args.This()); + if (!r || r->type != QV8SqlDatabaseResource::Query) + V8THROW_REFERENCE("Not a SQLDatabase::Query object"); + + QV8Engine *engine = r->engine; + + if (!r->inTransaction) + V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QDeclarativeEngine::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")); + } + + QSqlQuery query(db); + bool err = false; + + v8::Handle result = v8::Undefined(); + + if (query.prepare(sql)) { + if (args.Length() > 1) { + v8::Local values = args[1]; + if (values->IsArray()) { + v8::Local array = v8::Local::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 object = values->ToObject(); + v8::Local 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)); + } else { + query.bindValue(0, engine->toVariant(values, -1)); + } + } + if (query.exec()) { + v8::Handle 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 resultObject = v8::Object::New(); + result = 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); + } else { + err = true; + } + } else { + err = true; + } + if (err) + V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text()); + + return result; +} + +static v8::Handle qmlsqldatabase_changeVersion(const v8::Arguments& args) +{ + if (args.Length() < 2) + return v8::Undefined(); + + QV8SqlDatabaseResource *r = v8_resource_cast(args.This()); + if (!r || r->type != QV8SqlDatabaseResource::Database) + V8THROW_REFERENCE("Not a SQLDatabase object"); + + QV8Engine *engine = r->engine; + + QSqlDatabase db = r->database; + QString from_version = engine->toString(args[0]); + QString to_version = engine->toString(args[1]); + 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)); + + v8::Local 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); + + bool ok = true; + if (callback->IsFunction()) { + ok = false; + db.transaction(); + + v8::TryCatch tc; + v8::Handle callbackArgs[] = { instance }; + v8::Handle::Cast(callback)->Call(engine->global(), 1, callbackArgs); + + if (tc.HasCaught()) { + db.rollback(); + tc.ReThrow(); + return v8::Handle(); + } else if (!db.commit()) { + db.rollback(); + V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QDeclarativeEngine::tr("SQL transaction failed")); + } else { + ok = true; + } + } + + r2->inTransaction = false; + + if (ok) { + r2->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(); +} + +static v8::Handle qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly) +{ + QV8SqlDatabaseResource *r = v8_resource_cast(args.This()); + if (!r || r->type != QV8SqlDatabaseResource::Database) + V8THROW_REFERENCE("Not a SQLDatabase object"); + + QV8Engine *engine = r->engine; + + if (args.Length() == 0 || !args[0]->IsFunction()) + V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QDeclarativeEngine::tr("transaction: missing callback")); + + QSqlDatabase db = r->database; + v8::Handle callback = v8::Handle::Cast(args[0]); + + v8::Local 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); + + db.transaction(); + v8::TryCatch tc; + v8::Handle callbackArgs[] = { instance }; + callback->Call(engine->global(), 1, callbackArgs); + + q->inTransaction = false; + + if (tc.HasCaught()) { + db.rollback(); + tc.ReThrow(); + return v8::Handle(); + } else if (!db.commit()) { + db.rollback(); + } + + return v8::Undefined(); +} + +static v8::Handle qmlsqldatabase_transaction(const v8::Arguments& args) +{ + return qmlsqldatabase_transaction_shared(args, false); +} + +static v8::Handle qmlsqldatabase_read_transaction(const v8::Arguments& args) +{ + return qmlsqldatabase_transaction_shared(args, true); +} + +QDeclarativeSqlDatabaseData::QDeclarativeSqlDatabaseData(QV8Engine *engine) +{ + { + v8::Local 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(ft->GetFunction()); + } + + { + v8::Local ft = v8::FunctionTemplate::New(); + ft->InstanceTemplate()->SetHasExternalResource(true); + ft->PrototypeTemplate()->Set(v8::String::New("executeSql"), + V8FUNCTION(qmlsqldatabase_executeSql, engine)); + queryConstructor = qPersistentNew(ft->GetFunction()); + } + { + v8::Local 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(ft->GetFunction()); + } +} + +/* +HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator). +We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward +through the data. +*/ + + +/*! + \qmlclass LocalStorage QQuickLocalStorage + \inqmlmodule QtQuick.LocalStorage 2 + \since QtQuick 2.0 + + \brief The LocalStorage module API provides the ability to access local offline storage in an SQL database. + +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. + +Database connections are automatically closed during Javascript garbage collection. + +The API can be used from JavaScript functions in your QML: + +\snippet declarative/sqllocalstorage/hello.qml 0 + +The API conforms to the Synchronous API of the HTML5 Web Database API, +\link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink. + +The \l{declarative/sqllocalstorage}{SQL Local Storage example} demonstrates the basics of +using the Offline Storage API. + +\section3 Open or create a databaseData +\code +import QtQuick.LocalStorage 2.0 as LS + +db = LS.openDatabaseSync(identifier, version, description, estimated_size, callback(db)) +\endcode +The above code returns the database identified by \i identifier. If the database does not already exist, it +is created, and the function \i callback is called with the database as a parameter. \i description +and \i estimated_size are written to the INI file (described below), but are otherwise currently +unused. + +May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR. + +When a database is first created, an INI file is also created specifying its characteristics: + +\table +\header \o \bold {Key} \o \bold {Value} +\row \o Name \o The name of the database passed to \c openDatabase() +\row \o Version \o The version of the database passed to \c openDatabase() +\row \o Description \o The description of the database passed to \c openDatabase() +\row \o EstimatedSize \o The estimated size (in bytes) of the database passed to \c openDatabase() +\row \o Driver \o Currently "QSQLITE" +\endtable + +This data can be used by application tools. + +\section3 db.changeVersion(from, to, callback(tx)) + +This method allows you to perform a \i{Scheme Upgrade}. + +If the current version of \i db is not \i from, then an exception is thrown. + +Otherwise, a database transaction is created and passed to \i callback. In this function, +you can call \i executeSql on \i tx to upgrade the database. + +May throw exception with code property SQLException.DATABASE_ERR or SQLException.UNKNOWN_ERR. + +\section3 db.transaction(callback(tx)) + +This method creates a read/write transaction and passed to \i callback. In this function, +you can call \i executeSql on \i tx to read and modify the database. + +If the callback throws exceptions, the transaction is rolled back. + +\section3 db.readTransaction(callback(tx)) + +This method creates a read-only transaction and passed to \i callback. In this function, +you can call \i executeSql on \i tx to read the database (with SELECT statements). + +\section3 results = tx.executeSql(statement, values) + +This method executes a SQL \i statement, binding the list of \i values to SQL positional parameters ("?"). + +It returns a results object, with the following properties: + +\table +\header \o \bold {Type} \o \bold {Property} \o \bold {Value} \o \bold {Applicability} +\row \o int \o rows.length \o The number of rows in the result \o SELECT +\row \o var \o rows.item(i) \o Function that returns row \i i of the result \o SELECT +\row \o int \o rowsAffected \o The number of rows affected by a modification \o UPDATE, DELETE +\row \o string \o insertId \o The id of the row inserted \o INSERT +\endtable + +May throw exception with code property SQLException.DATABASE_ERR, SQLException.SYNTAX_ERR, or SQLException.UNKNOWN_ERR. + */ +class QQuickLocalStorage : public QObject +{ + Q_OBJECT +public: + QQuickLocalStorage(QObject *parent=0) : QObject(parent) + { + } + ~QQuickLocalStorage() { + } + + Q_INVOKABLE void openDatabaseSync(QDeclarativeV8Function* args); +}; + +/*! + * \qmlmethod object LocalStorage::openDatabaseSync(string name, string version, string description, int estimated_size, jsobject callback(db)) + * \brief Open or create a local storage sql database by given parameters. + * + * \c name is the database name + * \c version is the database version + * \c description is the database display name + * \c estimated_size is the database's estimated size, in bytes + * \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) +{ +#ifndef QT_NO_SETTINGS + QV8Engine *engine = args->engine(); + 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 dbcreationCallback = (*args)[4]; + + QCryptographicHash md5(QCryptographicHash::Md5); + md5.addData(dbname.toUtf8()); + QString dbid(QLatin1String(md5.result().toHex())); + + QString basename = qmlsqldatabase_databaseFile(dbid, engine); + bool created = false; + QString version = dbversion; + + { + QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat); + + if (QSqlDatabase::connectionNames().contains(dbid)) { + 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")); + } else { + created = !QFile::exists(basename+QLatin1String(".sqlite")); + database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid); + if (created) { + ini.setValue(QLatin1String("Name"), dbname); + if (dbcreationCallback->IsFunction()) + version = QString(); + ini.setValue(QLatin1String("Version"), version); + ini.setValue(QLatin1String("Description"), dbdescription); + ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize); + ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE")); + } else { + if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) { + // Incompatible + V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QDeclarativeEngine::tr("SQL: database version mismatch")); + } + version = ini.value(QLatin1String("Version")).toString(); + } + database.setDatabaseName(basename+QLatin1String(".sqlite")); + } + if (!database.isOpen()) + database.open(); + } + + v8::Local 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 callback = v8::Handle::Cast(dbcreationCallback); + v8::Handle args[] = { instance }; + callback->Call(engine->global(), 1, args); + if (tc.HasCaught()) { + tc.ReThrow(); + return; + } + } + + args->returnValue(instance); +#endif // QT_NO_SETTINGS +} + +static QObject *module_api_factory(QDeclarativeEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine) + Q_UNUSED(scriptEngine) + QQuickLocalStorage *api = new QQuickLocalStorage(); + + return api; +} + +class QDeclarativeLocalStoragePlugin : public QDeclarativeExtensionPlugin +{ + Q_OBJECT +public: + QDeclarativeLocalStoragePlugin() + { + } + + void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage"); + qmlRegisterModuleApi(uri, 2, 0, module_api_factory); + } +}; + +#include "plugin.moc" + +Q_EXPORT_PLUGIN2(plugin, QDeclarativeLocalStoragePlugin); diff --git a/src/imports/localstorage/qmldir b/src/imports/localstorage/qmldir new file mode 100644 index 0000000000..33288a1afa --- /dev/null +++ b/src/imports/localstorage/qmldir @@ -0,0 +1 @@ +plugin qmllocalstorageplugin \ No newline at end of file -- cgit v1.2.3