1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
41 #include <QStringList>
42 #include <QtQml/qqmlextensionplugin.h>
43 #include <QtQml/qqml.h>
44 #include <private/qqmlengine_p.h>
46 #include <private/qv8engine_p.h>
47 #include <QtSql/qsqldatabase.h>
48 #include <QtSql/qsqlquery.h>
49 #include <QtSql/qsqlerror.h>
50 #include <QtSql/qsqlrecord.h>
51 #include <QtSql/qsqlfield.h>
52 #include <QtCore/qstandardpaths.h>
53 #include <QtCore/qstack.h>
54 #include <QtCore/qcryptographichash.h>
55 #include <QtCore/qsettings.h>
56 #include <QtCore/qdir.h>
57 #include <private/qv8sqlerrors_p.h>
60 #define V8THROW_SQL(error, desc) \
62 v8::Local<v8::Value> v = v8::Exception::Error(engine->toString(desc)); \
63 v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
64 v8::ThrowException(v); \
65 return v8::Handle<v8::Value>(); \
68 #define V8THROW_SQL_VOID(error, desc) \
70 v8::Local<v8::Value> v = v8::Exception::Error(engine->toString(desc)); \
71 v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
72 v8::ThrowException(v); \
76 #define V8THROW_REFERENCE(string) { \
77 v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
78 return v8::Handle<v8::Value>(); \
81 #define V8THROW_REFERENCE_VOID(string) { \
82 v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
86 class QQmlSqlDatabaseData : public QV8Engine::Deletable
89 QQmlSqlDatabaseData(QV8Engine *engine);
90 ~QQmlSqlDatabaseData();
92 v8::Persistent<v8::Function> constructor;
93 v8::Persistent<v8::Function> queryConstructor;
94 v8::Persistent<v8::Function> rowsConstructor;
97 V8_DEFINE_EXTENSION(QQmlSqlDatabaseData, databaseData)
99 class QV8SqlDatabaseResource : public QV8ObjectResource
101 V8_RESOURCE_TYPE(SQLDatabaseType)
104 enum Type { Database, Query, Rows };
105 QV8SqlDatabaseResource(QV8Engine *e)
106 : QV8ObjectResource(e), type(Database), inTransaction(false), readonly(false), forwardOnly(false) {}
108 ~QV8SqlDatabaseResource() {
112 QSqlDatabase database;
114 QString version; // type == Database
116 bool inTransaction; // type == Query
117 bool readonly; // type == Query
119 QSqlQuery query; // type == Rows
120 bool forwardOnly; // type == Rows
123 static v8::Handle<v8::Value> qmlsqldatabase_version(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info)
125 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
126 if (!r || r->type != QV8SqlDatabaseResource::Database)
127 V8THROW_REFERENCE("Not a SQLDatabase object");
129 return r->engine->toString(r->version);
132 static v8::Handle<v8::Value> qmlsqldatabase_rows_length(v8::Local<v8::String> /* property */, const v8::AccessorInfo& info)
134 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
135 if (!r || r->type != QV8SqlDatabaseResource::Rows)
136 V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
138 int s = r->query.size();
141 if (r->query.last()) {
142 s = r->query.at() + 1;
147 return v8::Integer::New(s);
150 static v8::Handle<v8::Value> qmlsqldatabase_rows_forwardOnly(v8::Local<v8::String> /* property */,
151 const v8::AccessorInfo& info)
153 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
154 if (!r || r->type != QV8SqlDatabaseResource::Rows)
155 V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
156 return v8::Boolean::New(r->query.isForwardOnly());
159 static void qmlsqldatabase_rows_setForwardOnly(v8::Local<v8::String> /* property */,
160 v8::Local<v8::Value> value,
161 const v8::AccessorInfo& info)
163 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
164 if (!r || r->type != QV8SqlDatabaseResource::Rows)
165 V8THROW_REFERENCE_VOID("Not a SQLDatabase::Rows object");
167 r->query.setForwardOnly(value->BooleanValue());
170 QQmlSqlDatabaseData::~QQmlSqlDatabaseData()
172 qPersistentDispose(constructor);
173 qPersistentDispose(queryConstructor);
174 qPersistentDispose(rowsConstructor);
177 static QString qmlsqldatabase_databasesPath(QV8Engine *engine)
179 return engine->engine()->offlineStoragePath() +
180 QDir::separator() + QLatin1String("Databases");
183 static void qmlsqldatabase_initDatabasesPath(QV8Engine *engine)
185 QDir().mkpath(qmlsqldatabase_databasesPath(engine));
188 static QString qmlsqldatabase_databaseFile(const QString& connectionName, QV8Engine *engine)
190 return qmlsqldatabase_databasesPath(engine) + QDir::separator() + connectionName;
193 static v8::Handle<v8::Value> qmlsqldatabase_rows_index(QV8SqlDatabaseResource *r, uint32_t index)
195 if (r->query.at() == (int)index || r->query.seek(index)) {
197 QSqlRecord record = r->query.record();
199 v8::Local<v8::Object> row = v8::Object::New();
200 for (int ii = 0; ii < record.count(); ++ii) {
201 QVariant v = record.value(ii);
203 row->Set(r->engine->toString(record.fieldName(ii)), v8::Null());
205 row->Set(r->engine->toString(record.fieldName(ii)),
206 r->engine->fromVariant(v));
211 return v8::Undefined();
215 static v8::Handle<v8::Value> qmlsqldatabase_rows_index(uint32_t index, const v8::AccessorInfo& info)
217 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(info.This());
218 if (!r || r->type != QV8SqlDatabaseResource::Rows)
219 V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
221 return qmlsqldatabase_rows_index(r, index);
224 static v8::Handle<v8::Value> qmlsqldatabase_rows_item(const v8::Arguments& args)
226 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
227 if (!r || r->type != QV8SqlDatabaseResource::Rows)
228 V8THROW_REFERENCE("Not a SQLDatabase::Rows object");
230 return qmlsqldatabase_rows_index(r, args.Length()?args[0]->Uint32Value():0);
233 static v8::Handle<v8::Value> qmlsqldatabase_executeSql(const v8::Arguments& args)
235 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
236 if (!r || r->type != QV8SqlDatabaseResource::Query)
237 V8THROW_REFERENCE("Not a SQLDatabase::Query object");
239 QV8Engine *engine = r->engine;
241 if (!r->inTransaction)
242 V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,QQmlEngine::tr("executeSql called outside transaction()"));
244 QSqlDatabase db = r->database;
246 QString sql = engine->toString(args[0]);
248 if (r->readonly && !sql.startsWith(QLatin1String("SELECT"),Qt::CaseInsensitive)) {
249 V8THROW_SQL(SQLEXCEPTION_SYNTAX_ERR, QQmlEngine::tr("Read-only Transaction"));
255 v8::Handle<v8::Value> result = v8::Undefined();
257 if (query.prepare(sql)) {
258 if (args.Length() > 1) {
259 v8::Local<v8::Value> values = args[1];
260 if (values->IsArray()) {
261 v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(values);
262 uint32_t size = array->Length();
263 for (uint32_t ii = 0; ii < size; ++ii)
264 query.bindValue(ii, engine->toVariant(array->Get(ii), -1));
265 } else if (values->IsObject() && !values->ToObject()->GetExternalResource()) {
266 v8::Local<v8::Object> object = values->ToObject();
267 v8::Local<v8::Array> names = object->GetPropertyNames();
268 uint32_t size = names->Length();
269 for (uint32_t ii = 0; ii < size; ++ii)
270 query.bindValue(engine->toString(names->Get(ii)),
271 engine->toVariant(object->Get(names->Get(ii)), -1));
273 query.bindValue(0, engine->toVariant(values, -1));
277 v8::Handle<v8::Object> rows = databaseData(engine)->rowsConstructor->NewInstance();
278 QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
279 r->type = QV8SqlDatabaseResource::Rows;
282 rows->SetExternalResource(r);
284 v8::Local<v8::Object> resultObject = v8::Object::New();
285 result = resultObject;
287 resultObject->Set(v8::String::New("rowsAffected"), v8::Integer::New(query.numRowsAffected()));
288 resultObject->Set(v8::String::New("insertId"), engine->toString(query.lastInsertId().toString()));
289 resultObject->Set(v8::String::New("rows"), rows);
297 V8THROW_SQL(SQLEXCEPTION_DATABASE_ERR,query.lastError().text());
302 static v8::Handle<v8::Value> qmlsqldatabase_changeVersion(const v8::Arguments& args)
304 if (args.Length() < 2)
305 return v8::Undefined();
307 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
308 if (!r || r->type != QV8SqlDatabaseResource::Database)
309 V8THROW_REFERENCE("Not a SQLDatabase object");
311 QV8Engine *engine = r->engine;
313 QSqlDatabase db = r->database;
314 QString from_version = engine->toString(args[0]);
315 QString to_version = engine->toString(args[1]);
316 v8::Handle<v8::Value> callback = args[2];
318 if (from_version != r->version)
319 V8THROW_SQL(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("Version mismatch: expected %1, found %2").arg(from_version).arg(r->version));
321 v8::Local<v8::Object> instance = databaseData(engine)->queryConstructor->NewInstance();
322 QV8SqlDatabaseResource *r2 = new QV8SqlDatabaseResource(engine);
323 r2->type = QV8SqlDatabaseResource::Query;
325 r2->version = r->version;
326 r2->inTransaction = true;
327 instance->SetExternalResource(r2);
330 if (callback->IsFunction()) {
335 v8::Handle<v8::Value> callbackArgs[] = { instance };
336 v8::Handle<v8::Function>::Cast(callback)->Call(engine->global(), 1, callbackArgs);
338 if (tc.HasCaught()) {
341 return v8::Handle<v8::Value>();
342 } else if (!db.commit()) {
344 V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("SQL transaction failed"));
350 r2->inTransaction = false;
353 r2->version = to_version;
354 #ifndef QT_NO_SETTINGS
355 QSettings ini(qmlsqldatabase_databaseFile(db.connectionName(),engine) + QLatin1String(".ini"), QSettings::IniFormat);
356 ini.setValue(QLatin1String("Version"), to_version);
360 return v8::Undefined();
363 static v8::Handle<v8::Value> qmlsqldatabase_transaction_shared(const v8::Arguments& args, bool readOnly)
365 QV8SqlDatabaseResource *r = v8_resource_cast<QV8SqlDatabaseResource>(args.This());
366 if (!r || r->type != QV8SqlDatabaseResource::Database)
367 V8THROW_REFERENCE("Not a SQLDatabase object");
369 QV8Engine *engine = r->engine;
371 if (args.Length() == 0 || !args[0]->IsFunction())
372 V8THROW_SQL(SQLEXCEPTION_UNKNOWN_ERR,QQmlEngine::tr("transaction: missing callback"));
374 QSqlDatabase db = r->database;
375 v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(args[0]);
377 v8::Local<v8::Object> instance = databaseData(engine)->queryConstructor->NewInstance();
378 QV8SqlDatabaseResource *q = new QV8SqlDatabaseResource(engine);
379 q->type = QV8SqlDatabaseResource::Query;
381 q->readonly = readOnly;
382 q->inTransaction = true;
383 instance->SetExternalResource(q);
387 v8::Handle<v8::Value> callbackArgs[] = { instance };
388 callback->Call(engine->global(), 1, callbackArgs);
390 q->inTransaction = false;
392 if (tc.HasCaught()) {
395 return v8::Handle<v8::Value>();
396 } else if (!db.commit()) {
400 return v8::Undefined();
403 static v8::Handle<v8::Value> qmlsqldatabase_transaction(const v8::Arguments& args)
405 return qmlsqldatabase_transaction_shared(args, false);
408 static v8::Handle<v8::Value> qmlsqldatabase_read_transaction(const v8::Arguments& args)
410 return qmlsqldatabase_transaction_shared(args, true);
413 QQmlSqlDatabaseData::QQmlSqlDatabaseData(QV8Engine *engine)
416 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
417 ft->InstanceTemplate()->SetHasExternalResource(true);
418 ft->PrototypeTemplate()->Set(v8::String::New("transaction"),
419 V8FUNCTION(qmlsqldatabase_transaction, engine));
420 ft->PrototypeTemplate()->Set(v8::String::New("readTransaction"),
421 V8FUNCTION(qmlsqldatabase_read_transaction, engine));
422 ft->PrototypeTemplate()->SetAccessor(v8::String::New("version"), qmlsqldatabase_version);
423 ft->PrototypeTemplate()->Set(v8::String::New("changeVersion"),
424 V8FUNCTION(qmlsqldatabase_changeVersion, engine));
425 constructor = qPersistentNew<v8::Function>(ft->GetFunction());
429 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
430 ft->InstanceTemplate()->SetHasExternalResource(true);
431 ft->PrototypeTemplate()->Set(v8::String::New("executeSql"),
432 V8FUNCTION(qmlsqldatabase_executeSql, engine));
433 queryConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
436 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
437 ft->InstanceTemplate()->SetHasExternalResource(true);
438 ft->PrototypeTemplate()->Set(v8::String::New("item"), V8FUNCTION(qmlsqldatabase_rows_item, engine));
439 ft->PrototypeTemplate()->SetAccessor(v8::String::New("length"), qmlsqldatabase_rows_length);
440 ft->InstanceTemplate()->SetAccessor(v8::String::New("forwardOnly"), qmlsqldatabase_rows_forwardOnly,
441 qmlsqldatabase_rows_setForwardOnly);
442 ft->InstanceTemplate()->SetIndexedPropertyHandler(qmlsqldatabase_rows_index);
443 rowsConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
448 HTML5 "spec" says "rs.rows[n]", but WebKit only impelments "rs.rows.item(n)". We do both (and property iterator).
449 We add a "forwardOnly" property that stops Qt caching results (code promises to only go forward
455 \qmlmodule QtQuick.LocalStorage 2
456 \title QML Module QtQuick.LocalStorage 2.0
457 \brief Provides a JavaScript object singleton type for accessing a local SQLite database
459 This is a singleton type for reading and writing to SQLite databases.
465 \li object \b{\l{#openDatabaseSync}{openDatabaseSync}}(string name, string version, string description, int estimated_size, jsobject callback(db))
469 \section1 Detailed Description
471 To use the types in this module, import the module and call the
472 relevant functions using the \c LocalStorage type:
475 import QtQuick.LocalStorage 2.0
479 Component.onCompleted: {
480 var db = LocalStorage.openDatabaseSync(...)
486 These databases are user-specific and QML-specific, but accessible to all QML applications.
487 They are stored in the \c Databases subdirectory
488 of QQmlEngine::offlineStoragePath(), currently as SQLite databases.
490 Database connections are automatically closed during Javascript garbage collection.
492 The API can be used from JavaScript functions in your QML:
494 \snippet localstorage/localstorage/hello.qml 0
496 The API conforms to the Synchronous API of the HTML5 Web Database API,
497 \link http://www.w3.org/TR/2009/WD-webdatabase-20091029/ W3C Working Draft 29 October 2009\endlink.
499 The \l{localstorage/localstorage}{SQL Local Storage example} demonstrates the basics of
500 using the Offline Storage API.
502 \section3 Open or create a databaseData
504 import QtQuick.LocalStorage 2.0 as LS
506 db = Sql.openDatabaseSync(identifier, version, description, estimated_size, callback(db))
508 The above code returns the database identified by \e identifier. If the database does not already exist, it
509 is created, and the function \e callback is called with the database as a parameter. \e description
510 and \e estimated_size are written to the INI file (described below), but are otherwise currently
513 May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR.
515 When a database is first created, an INI file is also created specifying its characteristics:
518 \header \li \b {Key} \li \b {Value}
519 \row \li Name \li The name of the database passed to \c openDatabase()
520 \row \li Version \li The version of the database passed to \c openDatabase()
521 \row \li Description \li The description of the database passed to \c openDatabase()
522 \row \li EstimatedSize \li The estimated size (in bytes) of the database passed to \c openDatabase()
523 \row \li Driver \li Currently "QSQLITE"
526 This data can be used by application tools.
528 \section3 db.changeVersion(from, to, callback(tx))
530 This method allows you to perform a \e{Scheme Upgrade}.
532 If the current version of \e db is not \e from, then an exception is thrown.
534 Otherwise, a database transaction is created and passed to \e callback. In this function,
535 you can call \e executeSql on \e tx to upgrade the database.
537 May throw exception with code property SQLException.DATABASE_ERR or SQLException.UNKNOWN_ERR.
539 \section3 db.transaction(callback(tx))
541 This method creates a read/write transaction and passed to \e callback. In this function,
542 you can call \e executeSql on \e tx to read and modify the database.
544 If the callback throws exceptions, the transaction is rolled back.
546 \section3 db.readTransaction(callback(tx))
548 This method creates a read-only transaction and passed to \e callback. In this function,
549 you can call \e executeSql on \e tx to read the database (with SELECT statements).
551 \section3 results = tx.executeSql(statement, values)
553 This method executes a SQL \e statement, binding the list of \e values to SQL positional parameters ("?").
555 It returns a results object, with the following properties:
558 \header \li \b {Type} \li \b {Property} \li \b {Value} \li \b {Applicability}
559 \row \li int \li rows.length \li The number of rows in the result \li SELECT
560 \row \li var \li rows.item(i) \li Function that returns row \e i of the result \li SELECT
561 \row \li int \li rowsAffected \li The number of rows affected by a modification \li UPDATE, DELETE
562 \row \li string \li insertId \li The id of the row inserted \li INSERT
565 May throw exception with code property SQLException.DATABASE_ERR, SQLException.SYNTAX_ERR, or SQLException.UNKNOWN_ERR.
568 \section1 Method Documentation
570 \target openDatabaseSync
572 object openDatabaseSync(string name, string version, string description, int estimated_size, jsobject callback(db))
575 Opens or creates a local storage sql database by the given parameters.
578 \li \c name is the database name
579 \li \c version is the database version
580 \li \c description is the database display name
581 \li \c estimated_size is the database's estimated size, in bytes
582 \li \c callback is an optional parameter, which is invoked if the database has not yet been created.
585 Returns the created database object.
588 class QQuickLocalStorage : public QObject
592 QQuickLocalStorage(QObject *parent=0) : QObject(parent)
595 ~QQuickLocalStorage() {
598 Q_INVOKABLE void openDatabaseSync(QQmlV8Function* args);
601 void QQuickLocalStorage::openDatabaseSync(QQmlV8Function *args)
603 #ifndef QT_NO_SETTINGS
604 QV8Engine *engine = args->engine();
605 if (engine->engine()->offlineStoragePath().isEmpty())
606 V8THROW_SQL_VOID(SQLEXCEPTION_DATABASE_ERR, QQmlEngine::tr("SQL: can't create database, offline storage is disabled."));
608 qmlsqldatabase_initDatabasesPath(engine);
610 QSqlDatabase database;
612 QString dbname = engine->toString((*args)[0]);
613 QString dbversion = engine->toString((*args)[1]);
614 QString dbdescription = engine->toString((*args)[2]);
615 int dbestimatedsize = (*args)[3]->Int32Value();
616 v8::Handle<v8::Value> dbcreationCallback = (*args)[4];
618 QCryptographicHash md5(QCryptographicHash::Md5);
619 md5.addData(dbname.toUtf8());
620 QString dbid(QLatin1String(md5.result().toHex()));
622 QString basename = qmlsqldatabase_databaseFile(dbid, engine);
623 bool created = false;
624 QString version = dbversion;
627 QSettings ini(basename+QLatin1String(".ini"),QSettings::IniFormat);
629 if (QSqlDatabase::connectionNames().contains(dbid)) {
630 database = QSqlDatabase::database(dbid);
631 version = ini.value(QLatin1String("Version")).toString();
632 if (version != dbversion && !dbversion.isEmpty() && !version.isEmpty())
633 V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR, QQmlEngine::tr("SQL: database version mismatch"));
635 created = !QFile::exists(basename+QLatin1String(".sqlite"));
636 database = QSqlDatabase::addDatabase(QLatin1String("QSQLITE"), dbid);
638 ini.setValue(QLatin1String("Name"), dbname);
639 if (dbcreationCallback->IsFunction())
641 ini.setValue(QLatin1String("Version"), version);
642 ini.setValue(QLatin1String("Description"), dbdescription);
643 ini.setValue(QLatin1String("EstimatedSize"), dbestimatedsize);
644 ini.setValue(QLatin1String("Driver"), QLatin1String("QSQLITE"));
646 if (!dbversion.isEmpty() && ini.value(QLatin1String("Version")) != dbversion) {
648 V8THROW_SQL_VOID(SQLEXCEPTION_VERSION_ERR,QQmlEngine::tr("SQL: database version mismatch"));
650 version = ini.value(QLatin1String("Version")).toString();
652 database.setDatabaseName(basename+QLatin1String(".sqlite"));
654 if (!database.isOpen())
658 v8::Local<v8::Object> instance = databaseData(engine)->constructor->NewInstance();
660 QV8SqlDatabaseResource *r = new QV8SqlDatabaseResource(engine);
661 r->database = database;
662 r->version = version;
663 instance->SetExternalResource(r);
665 if (created && dbcreationCallback->IsFunction()) {
667 v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(dbcreationCallback);
668 v8::Handle<v8::Value> args[] = { instance };
669 callback->Call(engine->global(), 1, args);
670 if (tc.HasCaught()) {
676 args->returnValue(instance);
677 #endif // QT_NO_SETTINGS
680 static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
683 Q_UNUSED(scriptEngine)
684 QQuickLocalStorage *api = new QQuickLocalStorage();
689 class QQmlLocalStoragePlugin : public QQmlExtensionPlugin
692 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
695 QQmlLocalStoragePlugin()
699 void registerTypes(const char *uri)
701 Q_ASSERT(QLatin1String(uri) == "QtQuick.LocalStorage");
702 qmlRegisterSingletonType<QQuickLocalStorage>(uri, 2, 0, "LocalStorage", module_api_factory);
706 #include "plugin.moc"