diff --git a/share/qtcreator/qml/qmldump/main.cpp b/share/qtcreator/qml/qmldump/main.cpp index 61211ee07d9df17fb0eb33788fbe48bd7f10acb9..93f349c98be11ed4a23b6392a2c5752f8726fd25 100644 --- a/share/qtcreator/qml/qmldump/main.cpp +++ b/share/qtcreator/qml/qmldump/main.cpp @@ -15,15 +15,15 @@ #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(); diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 302a6df599bb10c11d3f58a80affa637eb0840d6..b293127c34e2547fdd17d490a46e39c96682695b 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -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; + } } } diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 96df1ebbc153cf49c1461803c975c54d1121b38a..74858486b5d37f32d62a6ce00bd4c68e5484df5f 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -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; };