OSDN Git Service

QmlJS: Prepare qmldump for multiply exported C++ objects.
authorChristian Kamm <christian.d.kamm@nokia.com>
Thu, 30 Sep 2010 09:21:23 +0000 (11:21 +0200)
committerChristian Kamm <christian.d.kamm@nokia.com>
Fri, 1 Oct 2010 08:14:29 +0000 (10:14 +0200)
In the future, builtin objects are going to be exported in Qt 4.7 and
QtQuick 1.0.

Reviewed-by: Roberto Raggi
share/qtcreator/qml/qmldump/main.cpp
src/libs/qmljs/qmljsinterpreter.cpp
src/libs/qmljs/qmljsinterpreter.h

index 61211ee..93f349c 100644 (file)
 #include <QtDeclarative/private/qdeclarativeopenmetaobject_p.h>
 #include <QtDeclarative/QDeclarativeView>
 
-static QHash<QByteArray, const QDeclarativeType *> qmlTypeByCppName;
-static QHash<QByteArray, QByteArray> cppToQml;
+static QHash<QByteArray, QList<const QDeclarativeType *> > qmlTypesByCppName;
+static QHash<QByteArray, QByteArray> cppToId;
 
-QByteArray convertToQmlType(const QByteArray &cppName)
+QByteArray convertToId(const QByteArray &cppName)
 {
-    QByteArray qmlName = cppToQml.value(cppName, cppName);
-    qmlName.replace("::", ".");
-    qmlName.replace("/", ".");
-    return qmlName;
+    QByteArray idName = cppToId.value(cppName, cppName);
+    idName.replace("::", ".");
+    idName.replace("/", ".");
+    return idName;
 }
 
 void erasure(QByteArray *typeName, bool *isList, bool *isPointer)
@@ -41,7 +41,7 @@ void erasure(QByteArray *typeName, bool *isList, bool *isPointer)
         erasure(typeName, isList, isPointer);
     }
 
-    *typeName = convertToQmlType(*typeName);
+    *typeName = convertToId(*typeName);
 }
 
 void processMetaObject(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
@@ -132,7 +132,7 @@ void dump(const QMetaMethod &meth, QXmlStreamWriter *xml)
 
     attributes.append(QXmlStreamAttribute("name", name));
 
-    const QString typeName = convertToQmlType(meth.typeName());
+    const QString typeName = convertToId(meth.typeName());
     if (! typeName.isEmpty())
         attributes.append(QXmlStreamAttribute("type", typeName));
 
@@ -187,16 +187,12 @@ public:
 
 void dump(const QMetaObject *meta, QXmlStreamWriter *xml)
 {
-    QByteArray qmlTypeName = convertToQmlType(meta->className());
+    QByteArray id = convertToId(meta->className());
 
     xml->writeStartElement("type");
 
     QXmlStreamAttributes attributes;
-    attributes.append(QXmlStreamAttribute("name", qmlTypeName));
-
-    if (const QDeclarativeType *qmlTy = qmlTypeByCppName.value(meta->className())) {
-        attributes.append(QXmlStreamAttribute("version", QString("%1.%2").arg(qmlTy->majorVersion()).arg(qmlTy->minorVersion())));
-    }
+    attributes.append(QXmlStreamAttribute("name", id));
 
     for (int index = meta->classInfoCount() - 1 ; index >= 0 ; --index) {
         QMetaClassInfo classInfo = meta->classInfo(index);
@@ -206,16 +202,31 @@ void dump(const QMetaObject *meta, QXmlStreamWriter *xml)
         }
     }
 
-    QString version;
-
     if (meta->superClass())
-        attributes.append(QXmlStreamAttribute("extends", convertToQmlType(meta->superClass()->className())));
-
-    if (! version.isEmpty())
-        attributes.append(QXmlStreamAttribute("version", version));
+        attributes.append(QXmlStreamAttribute("extends", convertToId(meta->superClass()->className())));
 
     xml->writeAttributes(attributes);
 
+    QList<const QDeclarativeType *> qmlTypes = qmlTypesByCppName.value(id);
+    if (!qmlTypes.isEmpty()) {
+        xml->writeStartElement("exports");
+        foreach (const QDeclarativeType *qmlTy, qmlTypes) {
+            QXmlStreamAttributes moduleAttributes;
+            const QString qmlTyName = qmlTy->qmlTypeName();
+            int slashIdx = qmlTyName.lastIndexOf(QLatin1Char('/'));
+            if (slashIdx == -1)
+                continue;
+            const QString moduleName = qmlTyName.left(slashIdx);
+            const QString typeName = qmlTyName.mid(slashIdx + 1);
+            moduleAttributes.append(QXmlStreamAttribute("module", moduleName));
+            moduleAttributes.append(QXmlStreamAttribute("version", QString("%1.%2").arg(qmlTy->majorVersion()).arg(qmlTy->minorVersion())));
+            moduleAttributes.append(QXmlStreamAttribute("type", typeName));
+            xml->writeEmptyElement("export");
+            xml->writeAttributes(moduleAttributes);
+        }
+        xml->writeEndElement();
+    }
+
     for (int index = meta->enumeratorOffset(); index < meta->enumeratorCount(); ++index)
         dump(meta->enumerator(index), xml);
 
@@ -234,7 +245,7 @@ void writeEasingCurve(QXmlStreamWriter *xml)
     {
         QXmlStreamAttributes attributes;
         attributes.append(QXmlStreamAttribute("name", "QEasingCurve"));
-        attributes.append(QXmlStreamAttribute("extends", "Qt.Easing"));
+        attributes.append(QXmlStreamAttribute("extends", "QDeclarativeEasingValueType"));
         xml->writeAttributes(attributes);
     }
 
@@ -262,8 +273,22 @@ int main(int argc, char *argv[])
     if (!pluginImportPath.isEmpty())
         engine->addImportPath(pluginImportPath);
 
+    bool hasQtQuickModule = false;
+    {
+        QByteArray code = "import QtQuick 1.0; Item {}";
+        QDeclarativeComponent c(engine);
+        c.setData(code, QUrl("xxx"));
+        c.create();
+        if (c.errors().isEmpty()) {
+            hasQtQuickModule = true;
+        }
+    }
+
     QByteArray importCode;
     importCode += "import Qt 4.7;\n";
+    if (hasQtQuickModule) {
+        importCode += "import QtQuick 1.0;\n";
+    }
     if (pluginImportName.isEmpty()) {
         importCode += "import Qt.labs.particles 4.7;\n";
         importCode += "import Qt.labs.gestures 4.7;\n";
@@ -284,25 +309,25 @@ int main(int argc, char *argv[])
             qDebug() << c.errorString();
     }
 
-    cppToQml.insert("QString", "string");
-    cppToQml.insert("QDeclarativeEasingValueType::Type", "Type");
+    cppToId.insert("QString", "string");
+    cppToId.insert("QDeclarativeEasingValueType::Type", "Type");
 
     QSet<const QMetaObject *> metas;
 
     metas.insert(FriendlyQObject::qtMeta());
 
-    QMultiHash<QByteArray, QByteArray> extensions;
+    QHash<QByteArray, QSet<QByteArray> > extensions;
     foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
-        qmlTypeByCppName.insert(ty->metaObject()->className(), ty);
+        qmlTypesByCppName[ty->metaObject()->className()].append(ty);
         if (ty->isExtendedType()) {
-            extensions.insert(ty->typeName(), ty->metaObject()->className());
+            extensions[ty->typeName()].insert(ty->metaObject()->className());
         } else {
-            cppToQml.insert(ty->metaObject()->className(), ty->qmlTypeName());
+            cppToId.insert(ty->metaObject()->className(), ty->metaObject()->className());
         }
         processDeclarativeType(ty, &metas);
     }
 
-    // Adjust qml names of extended objects.
+    // Adjust ids of extended objects.
     // The chain ends up being:
     // __extended__.originalname - the base object
     // __extension_0_.originalname - first extension
@@ -310,14 +335,19 @@ int main(int argc, char *argv[])
     // __extension_n-2_.originalname - second to last extension
     // originalname - last extension
     foreach (const QByteArray &extendedCpp, extensions.keys()) {
-        const QByteArray extendedQml = cppToQml.value(extendedCpp);
-        cppToQml.insert(extendedCpp, "__extended__." + extendedQml);
-        QList<QByteArray> extensionCppNames = extensions.values(extendedCpp);
-        for (int i = 0; i < extensionCppNames.size() - 1; ++i) {
-            QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(i), QString(extendedQml)).toAscii();
-            cppToQml.insert(extensionCppNames.value(i), adjustedName);
+        const QByteArray extendedId = cppToId.value(extendedCpp);
+        cppToId.insert(extendedCpp, "__extended__." + extendedId);
+        QSet<QByteArray> extensionCppNames = extensions.value(extendedCpp);
+        int c = 0;
+        foreach (const QByteArray &extensionCppName, extensionCppNames) {
+            if (c != extensionCppNames.size() - 1) {
+                QByteArray adjustedName = QString("__extension__%1.%2").arg(QString::number(c), QString(extendedId)).toAscii();
+                cppToId.insert(extensionCppName, adjustedName);
+            } else {
+                cppToId.insert(extensionCppName, extendedId);
+            }
+            ++c;
         }
-        cppToQml.insert(extensionCppNames.last(), extendedQml);
     }
 
     foreach (const QDeclarativeType *ty, QDeclarativeMetaType::qmlTypes()) {
@@ -350,13 +380,13 @@ int main(int argc, char *argv[])
 
     QMap<QString, const QMetaObject *> nameToMeta;
     foreach (const QMetaObject *meta, metas) {
-        nameToMeta.insert(convertToQmlType(meta->className()), meta);
+        nameToMeta.insert(convertToId(meta->className()), meta);
     }
     foreach (const QMetaObject *meta, nameToMeta) {
         dump(meta, &xml);
     }
 
-    // define QEasingCurve as an extension of Qt.Easing
+    // define QEasingCurve as an extension of QDeclarativeEasingValueType
     writeEasingCurve(&xml);
 
     xml.writeEndElement();
index 302a6df..b293127 100644 (file)
@@ -199,13 +199,19 @@ public:
 };
 
 class FakeMetaObject {
-    FakeMetaObject(FakeMetaObject&);
-    FakeMetaObject &operator=(const FakeMetaObject&);
+    Q_DISABLE_COPY(FakeMetaObject)
 
-    QString m_name;
-    QString m_package;
-    QString m_packageNameVersion;
-    ComponentVersion m_version;
+public:
+    class Export {
+    public:
+        QString package;
+        QString type;
+        QmlJS::ComponentVersion version;
+        QString packageNameVersion;
+    };
+
+private:
+    QList<Export> m_exports;
     const FakeMetaObject *m_super;
     QString m_superName;
     QList<FakeMetaEnum> m_enums;
@@ -216,13 +222,25 @@ class FakeMetaObject {
     QString m_defaultPropertyName;
 
 public:
-    FakeMetaObject(const QString &name, const QString &package, ComponentVersion version)
-        : m_name(name), m_package(package), m_version(version), m_super(0)
+    FakeMetaObject()
+        : m_super(0)
     {
-        m_packageNameVersion = QString::fromLatin1("%1.%2 %3.%4").arg(
+    }
+
+    void addExport(const QString &name, const QString &package, QmlJS::ComponentVersion version)
+    {
+        Export exp;
+        exp.type = name;
+        exp.package = package;
+        exp.version = version;
+        exp.packageNameVersion = QString::fromLatin1("%1.%2 %3.%4").arg(
                 package, name,
-                QString::number(version.majorVersion()), QString::number(version.minorVersion()));
+                QString::number(version.majorVersion()),
+                QString::number(version.minorVersion()));
+        m_exports.append(exp);
     }
+    QList<Export> exports() const
+    { return m_exports; }
 
     void setSuperclassName(const QString &superclass)
     { m_superName = superclass; }
@@ -233,12 +251,6 @@ public:
     { m_super = superClass; }
     const FakeMetaObject *superClass() const
     { return m_super; }
-    QString className() const
-    { return m_name; }
-    QString packageName() const
-    { return m_package; }
-    QString packageClassVersionString() const
-    { return m_packageNameVersion; }
 
     void addEnum(const FakeMetaEnum &fakeEnum)
     { m_enumNameToIndex.insert(fakeEnum.name(), m_enums.size()); m_enums.append(fakeEnum); }
@@ -271,9 +283,6 @@ public:
     FakeMetaMethod method(int index) const
     { return m_methods.at(index); }
 
-    ComponentVersion version() const
-    { return m_version; }
-
     QString defaultPropertyName() const
     { return m_defaultPropertyName; }
 
@@ -404,38 +413,14 @@ private:
         QString name, defaultPropertyName;
         QmlJS::ComponentVersion version;
         QString extends;
+        QString id;
         foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
             if (attr.name() == QLatin1String("name")) {
-                name = attr.value().toString();
-                if (name.isEmpty()) {
+                id = attr.value().toString();
+                if (id.isEmpty()) {
                     invalidAttr(name, QLatin1String("name"), tag);
                     return;
                 }
-            } else if (attr.name() == QLatin1String("version")) {
-                QString versionStr = attr.value().toString();
-                int dotIdx = versionStr.indexOf('.');
-                if (dotIdx == -1) {
-                    bool ok = false;
-                    const int major = versionStr.toInt(&ok);
-                    if (!ok) {
-                        invalidAttr(versionStr, QLatin1String("version"), tag);
-                        return;
-                    }
-                    version = QmlJS::ComponentVersion(major, QmlJS::ComponentVersion::NoVersion);
-                } else {
-                    bool ok = false;
-                    const int major = versionStr.left(dotIdx).toInt(&ok);
-                    if (!ok) {
-                        invalidAttr(versionStr, QLatin1String("version"), tag);
-                        return;
-                    }
-                    const int minor = versionStr.mid(dotIdx + 1).toInt(&ok);
-                    if (!ok) {
-                        invalidAttr(versionStr, QLatin1String("version"), tag);
-                        return;
-                    }
-                    version = QmlJS::ComponentVersion(major, minor);
-                }
             } else if (attr.name() == QLatin1String("defaultProperty")) {
                 defaultPropertyName = attr.value().toString();
             } else if (attr.name() == QLatin1String("extends")) {
@@ -451,9 +436,7 @@ private:
             }
         }
 
-        QString className, packageName;
-        split(name, &packageName, &className);
-        FakeMetaObject *metaObject = new FakeMetaObject(className, packageName, version);
+        FakeMetaObject *metaObject = new FakeMetaObject;
         if (! extends.isEmpty())
             metaObject->setSuperclassName(extends);
         if (! defaultPropertyName.isEmpty())
@@ -468,14 +451,21 @@ private:
                 readSignal(metaObject);
             else if (_xml.name() == QLatin1String("method"))
                 readMethod(metaObject);
+            else if (_xml.name() == QLatin1String("exports"))
+                readExports(metaObject);
             else
                 unexpectedElement(_xml.name(), tag);
         }
 
-        if (doInsert)
-            _objects->insert(name, metaObject);
-        else
+        if (metaObject->exports().isEmpty()) {
+            metaObject->addExport(id, QString(), QmlJS::ComponentVersion());
+        }
+
+        if (doInsert) {
+            _objects->insert(id, metaObject);
+        } else {
             delete metaObject;
+        }
     }
 
     bool split(const QString &name, QString *packageName, QString *className) {
@@ -706,6 +696,60 @@ private:
         metaObject->addMethod(method);
     }
 
+    void readExports(FakeMetaObject *metaObject)
+    {
+        Q_ASSERT(metaObject);
+        QLatin1String tag("exports");
+        QLatin1String childTag("export");
+        Q_ASSERT(_xml.isStartElement() && _xml.name() == tag);
+
+        while (_xml.readNextStartElement()) {
+            if (_xml.name() == childTag) {
+                QString type;
+                QString package;
+                QmlJS::ComponentVersion version;
+                foreach (const QXmlStreamAttribute &attr, _xml.attributes()) {
+                    if (attr.name() == QLatin1String("module")) {
+                        package = attr.value().toString();
+                    } else if (attr.name() == QLatin1String("type")) {
+                        type = attr.value().toString();
+                    } else if (attr.name() == QLatin1String("version")) {
+                        QString versionStr = attr.value().toString();
+                        int dotIdx = versionStr.indexOf('.');
+                        if (dotIdx == -1) {
+                            bool ok = false;
+                            const int major = versionStr.toInt(&ok);
+                            if (!ok) {
+                                invalidAttr(versionStr, QLatin1String("version"), childTag);
+                                continue;
+                            }
+                            version = QmlJS::ComponentVersion(major, QmlJS::ComponentVersion::NoVersion);
+                        } else {
+                            bool ok = false;
+                            const int major = versionStr.left(dotIdx).toInt(&ok);
+                            if (!ok) {
+                                invalidAttr(versionStr, QLatin1String("version"), childTag);
+                                continue;
+                            }
+                            const int minor = versionStr.mid(dotIdx + 1).toInt(&ok);
+                            if (!ok) {
+                                invalidAttr(versionStr, QLatin1String("version"), childTag);
+                                continue;
+                            }
+                            version = QmlJS::ComponentVersion(major, minor);
+                        }
+                    } else {
+                        ignoreAttr(attr);
+                    }
+                }
+                metaObject->addExport(type, package, version);
+            } else {
+                unexpectedElement(_xml.name(), childTag);
+            }
+            _xml.skipCurrentElement(); // the <export> tag should be empty anyhow
+        }
+    }
+
 private:
     QXmlStreamReader _xml;
     QMap<QString, FakeMetaObject *> *_objects;
@@ -713,11 +757,12 @@ private:
 
 } // end of anonymous namespace
 
-QmlObjectValue::QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine)
+QmlObjectValue::QmlObjectValue(const FakeMetaObject *metaObject, int exportIndex, Engine *engine)
     : ObjectValue(engine),
-      _metaObject(metaObject)
+      _metaObject(metaObject),
+      _exportIndex(exportIndex)
 {
-    setClassName(metaObject->className()); // ### TODO: we probably need to do more than just this...
+    setClassName(metaObject->exports().at(exportIndex).type); // ### TODO: we probably need to do more than just this...
 }
 
 QmlObjectValue::~QmlObjectValue()
@@ -834,10 +879,10 @@ const Value *QmlObjectValue::propertyValue(const FakeMetaProperty &prop) const
 }
 
 QString QmlObjectValue::packageName() const
-{ return _metaObject->packageName(); }
+{ return _metaObject->exports().at(_exportIndex).package; }
 
 QmlJS::ComponentVersion QmlObjectValue::version() const
-{ return _metaObject->version(); }
+{ return _metaObject->exports().at(_exportIndex).version; }
 
 QString QmlObjectValue::defaultPropertyName() const
 { return _metaObject->defaultPropertyName(); }
@@ -890,7 +935,7 @@ bool QmlObjectValue::hasChildInPackage() const
     while (it.hasNext()) {
         it.next();
         const FakeMetaObject *other = it.value()->_metaObject;
-        if (other->packageName().isEmpty())
+        if (other->exports().isEmpty())
             continue;
         for (const FakeMetaObject *iter = other; iter; iter = iter->superClass()) {
             if (iter == _metaObject) // this object is a parent of other
@@ -1981,21 +2026,42 @@ void CppQmlTypes::load(Engine *engine, const QList<const FakeMetaObject *> &obje
 {
     // load
     foreach (const FakeMetaObject *metaObject, objects) {
-        // make sure we're not loading duplicate objects
-        if (_typesByFullyQualifiedName.contains(metaObject->packageClassVersionString()))
-            continue;
-
-        QmlObjectValue *objectValue = new QmlObjectValue(metaObject, engine);
-        _typesByPackage[metaObject->packageName()].append(objectValue);
-        _typesByFullyQualifiedName[metaObject->packageClassVersionString()] = objectValue;
+        for (int i = 0; i < metaObject->exports().size(); ++i) {
+            const FakeMetaObject::Export &exp = metaObject->exports().at(i);
+            // make sure we're not loading duplicate objects
+            if (_typesByFullyQualifiedName.contains(exp.packageNameVersion))
+                continue;
+
+            QmlObjectValue *objectValue = new QmlObjectValue(metaObject, i, engine);
+            _typesByPackage[exp.package].append(objectValue);
+            _typesByFullyQualifiedName[exp.packageNameVersion] = objectValue;
+        }
     }
 
     // set prototype correctly
     foreach (const FakeMetaObject *metaObject, objects) {
-        QmlObjectValue *objectValue = _typesByFullyQualifiedName.value(metaObject->packageClassVersionString());
-        if (!objectValue || !metaObject->superClass())
-            continue;
-        objectValue->setPrototype(_typesByFullyQualifiedName.value(metaObject->superClass()->packageClassVersionString()));
+        foreach (const FakeMetaObject::Export &exp, metaObject->exports()) {
+            QmlObjectValue *objectValue = _typesByFullyQualifiedName.value(exp.packageNameVersion);
+            if (!objectValue || !metaObject->superClass())
+                continue;
+            bool found = false;
+            // try to get a prototype from the library first
+            foreach (const FakeMetaObject::Export &superExports, metaObject->superClass()->exports()) {
+                if (superExports.package == exp.package) {
+                    objectValue->setPrototype(_typesByFullyQualifiedName.value(superExports.packageNameVersion));
+                    found = true;
+                    break;
+                }
+            }
+            if (found)
+                continue;
+            // otherwise, just use the first available
+            if (!metaObject->superClass()->exports().isEmpty()) {
+                objectValue->setPrototype(_typesByFullyQualifiedName.value(metaObject->superClass()->exports().first().packageNameVersion));
+                continue;
+            }
+            //qWarning() << "Could not find super class for " << exp.packageNameVersion;
+        }
     }
 }
 
index 96df1eb..7485848 100644 (file)
@@ -383,7 +383,7 @@ private:
 class QMLJS_EXPORT QmlObjectValue: public ObjectValue
 {
 public:
-    QmlObjectValue(const FakeMetaObject *metaObject, Engine *engine);
+    QmlObjectValue(const FakeMetaObject *metaObject, int exportIndex, Engine *engine);
     virtual ~QmlObjectValue();
 
     virtual void processMembers(MemberProcessor *processor) const;
@@ -404,6 +404,7 @@ protected:
 
 private:
     const FakeMetaObject *_metaObject;
+    const int _exportIndex;
     mutable QHash<int, const Value *> _metaSignature;
 };