Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8typewrapper.cpp
index 9aac7a3..9c362db 100644 (file)
@@ -1,34 +1,34 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the QtDeclarative module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** 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.
+** 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
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
+** 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.
 **
 **
 **
@@ -45,6 +45,9 @@
 #include <private/qdeclarativeengine_p.h>
 #include <private/qdeclarativecontext_p.h>
 
+#include <private/qjsvalue_p.h>
+#include <private/qscript_impl_p.h>
+
 QT_BEGIN_NAMESPACE
 
 class QV8TypeResource : public QV8ObjectResource
@@ -58,12 +61,14 @@ public:
     QV8TypeWrapper::TypeNameMode mode;
 
     QDeclarativeGuard<QObject> object;
+
     QDeclarativeType *type;
     QDeclarativeTypeNameCache *typeNamespace;
+    const void *importNamespace;
 };
 
 QV8TypeResource::QV8TypeResource(QV8Engine *engine)
-: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0)
+: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
 {
 }
 
@@ -95,6 +100,7 @@ void QV8TypeWrapper::init(QV8Engine *engine)
     m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
 }
 
+// Returns a type wrapper for type t on o.  This allows access of enums, and attached properties.
 v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeType *t, TypeNameMode mode)
 {
     Q_ASSERT(t);
@@ -106,22 +112,53 @@ v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeType *t,
     return rv;
 }
 
-v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeTypeNameCache *t, TypeNameMode mode)
+// Returns a type wrapper for importNamespace (of t) on o.  This allows nested resolution of a type in a 
+// namespace.
+v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QDeclarativeTypeNameCache *t, 
+                                                const void *importNamespace, TypeNameMode mode)
 {
     Q_ASSERT(t);
+    Q_ASSERT(importNamespace);
     // XXX NewInstance() should be optimized
     v8::Local<v8::Object> rv = m_constructor->NewInstance(); 
     QV8TypeResource *r = new QV8TypeResource(m_engine);
     t->addref();
-    r->mode = mode; r->object = o; r->typeNamespace = t;
+    r->mode = mode; r->object = o; r->typeNamespace = t; r->importNamespace = importNamespace;
     rv->SetExternalResource(r);
     return rv;
 }
 
+QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r)
+{
+    Q_ASSERT(r->resourceType() == QV8ObjectResource::TypeType);
+    QV8TypeResource *resource = static_cast<QV8TypeResource *>(r);
+    QV8Engine *v8engine = resource->engine;
+
+    if (resource->typeNamespace) {
+        if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) {
+            if (moduleApi->scriptCallback) {
+                moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+                moduleApi->scriptCallback = 0;
+                moduleApi->qobjectCallback = 0;
+            } else if (moduleApi->qobjectCallback) {
+                moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
+                moduleApi->scriptCallback = 0;
+                moduleApi->qobjectCallback = 0;
+            }
+
+            if (moduleApi->qobjectApi) {
+                return QVariant::fromValue<QObject*>(moduleApi->qobjectApi);
+            }
+        }
+    }
+
+    // only QObject Module API can be converted to a variant.
+    return QVariant();
+}
+
 v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property, 
                                              const v8::AccessorInfo &info)
 {
-    v8::Object::ExternalResource *r = info.This()->GetExternalResource();
     QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
 
     if (!resource) 
@@ -136,21 +173,11 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
         QDeclarativeType *type = resource->type;
 
         if (QV8Engine::startsWithUpper(property)) {
-            if (resource->mode == IncludeEnums) {
-                QString name = v8engine->toString(property);
-
-                // ### Optimize
-                QByteArray enumName = name.toUtf8();
-                const QMetaObject *metaObject = type->baseMetaObject();
-                for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
-                    QMetaEnum e = metaObject->enumerator(ii);
-                    int value = e.keyToValue(enumName.constData());
-                    if (value != -1) 
-                        return v8::Integer::New(value);
-                }
-            } 
+            int value = type->enumValue(propertystring);
+            if (-1 != value)
+                return v8::Integer::New(value);
 
-            // Fall through to undefined
+            // Fall through to return empty handle
 
         } else if (resource->object) {
             QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
@@ -158,39 +185,84 @@ v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
                 return v8engine->qobjectWrapper()->getProperty(ao, propertystring, 
                                                                QV8QObjectWrapper::IgnoreRevision);
 
-            // Fall through to undefined
+            // Fall through to return empty handle
         }
 
-        // Fall through to undefined
+        // Fall through to return empty handle
 
     } else if (resource->typeNamespace) {
+        Q_ASSERT(resource->importNamespace);
+        QDeclarativeTypeNameCache::Result r = resource->typeNamespace->query(propertystring,
+                                                                             resource->importNamespace);
+
+        if (r.isValid()) {
+            if (r.type) {
+                return v8engine->typeWrapper()->newObject(object, r.type, resource->mode);
+            } else if (r.scriptIndex != -1) {
+                int index = r.scriptIndex;
+                QDeclarativeContextData *context = v8engine->callingContext();
+                if (index < context->importedScripts.count())
+                    return context->importedScripts.at(index);
+            }
 
-        QDeclarativeTypeNameCache *typeNamespace = resource->typeNamespace;
-        QDeclarativeTypeNameCache::Data *d = typeNamespace->data(propertystring);
-        Q_ASSERT(!d || !d->typeNamespace); // Nested namespaces not supported
-
-        if (d && d->type) {
-            return v8engine->typeWrapper()->newObject(object, d->type, resource->mode);
-        } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = typeNamespace->moduleApi()) {
-            // XXX TODO: Currently module APIs are implemented against QScriptValues.  Consequently we
-            // can't do anything here until the QtScript/V8 binding is complete.
             return v8::Undefined();
+        } else if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) {
+
+            if (moduleApi->scriptCallback) {
+                moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+                moduleApi->scriptCallback = 0;
+                moduleApi->qobjectCallback = 0;
+            } else if (moduleApi->qobjectCallback) {
+                moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
+                moduleApi->scriptCallback = 0;
+                moduleApi->qobjectCallback = 0;
+            }
+
+            if (moduleApi->qobjectApi) {
+                // check for enum value
+                if (QV8Engine::startsWithUpper(property)) {
+                    if (resource->mode == IncludeEnums) {
+                        QString name = v8engine->toString(property);
+
+                        // ### Optimize
+                        QByteArray enumName = name.toUtf8();
+                        const QMetaObject *metaObject = moduleApi->qobjectApi->metaObject();
+                        for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+                            QMetaEnum e = metaObject->enumerator(ii);
+                            bool ok;
+                            int value = e.keyToValue(enumName.constData(), &ok);
+                            if (ok)
+                                return v8::Integer::New(value);
+                        }
+                    }
+                }
 
+                // check for property.
+                v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(moduleApi->qobjectApi, propertystring, QV8QObjectWrapper::IgnoreRevision);
+                return rv;
+            } else if (moduleApi->scriptApi.isValid()) {
+                // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+                QJSValuePrivate *apiprivate = QJSValuePrivate::get(moduleApi->scriptApi);
+                QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
+                return propertyValue->asV8Value(v8engine);
+            } else {
+                return v8::Handle<v8::Value>();
+            }
         }
 
-        // Fall through to undefined
+        // Fall through to return empty handle
 
     } else {
         Q_ASSERT(!"Unreachable");
     }
-    return v8::Undefined(); 
+
+    return v8::Handle<v8::Value>();
 }
 
 v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property, 
                                              v8::Local<v8::Value> value,
                                              const v8::AccessorInfo &info)
 {
-    v8::Object::ExternalResource *r = info.This()->GetExternalResource();
     QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
 
     if (!resource) 
@@ -198,8 +270,6 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
 
     QV8Engine *v8engine = resource->engine;
 
-    // XXX TODO: Implement writes to module API objects
-
     QHashedV8String propertystring(property);
 
     if (resource->type && resource->object) {
@@ -209,6 +279,33 @@ v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
         if (ao) 
             v8engine->qobjectWrapper()->setProperty(ao, propertystring, value, 
                                                     QV8QObjectWrapper::IgnoreRevision);
+    } else if (resource->typeNamespace) {
+        if (QDeclarativeMetaType::ModuleApiInstance *moduleApi = resource->typeNamespace->moduleApi(resource->importNamespace)) {
+            if (moduleApi->scriptCallback) {
+                moduleApi->scriptApi = moduleApi->scriptCallback(v8engine->engine(), v8engine->engine());
+                moduleApi->scriptCallback = 0;
+                moduleApi->qobjectCallback = 0;
+            } else if (moduleApi->qobjectCallback) {
+                moduleApi->qobjectApi = moduleApi->qobjectCallback(v8engine->engine(), v8engine->engine());
+                moduleApi->scriptCallback = 0;
+                moduleApi->qobjectCallback = 0;
+            }
+
+            if (moduleApi->qobjectApi) {
+                v8engine->qobjectWrapper()->setProperty(moduleApi->qobjectApi, propertystring, value, 
+                                                        QV8QObjectWrapper::IgnoreRevision);
+            } else if (moduleApi->scriptApi.isValid()) {
+                QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
+                QJSValuePrivate *apiprivate = QJSValuePrivate::get(moduleApi->scriptApi);
+                if (apiprivate->propertyFlags(property) & QJSValue::ReadOnly) {
+                    QString error = QLatin1String("Cannot assign to read-only property \"") +
+                                    v8engine->toString(property) + QLatin1Char('\"');
+                    v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
+                } else {
+                    apiprivate->setProperty(property, setvalp.data());
+                }
+            }
+        }
     }
 
     return value;