#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)
erasure(typeName, isList, isPointer);
}
- *typeName = convertToQmlType(*typeName);
+ *typeName = convertToId(*typeName);
}
void processMetaObject(const QMetaObject *meta, QSet<const QMetaObject *> *metas)
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));
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);
}
}
- 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);
{
QXmlStreamAttributes attributes;
attributes.append(QXmlStreamAttribute("name", "QEasingCurve"));
- attributes.append(QXmlStreamAttribute("extends", "Qt.Easing"));
+ attributes.append(QXmlStreamAttribute("extends", "QDeclarativeEasingValueType"));
xml->writeAttributes(attributes);
}
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";
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
// __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()) {
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();
};
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;
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; }
{ 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); }
FakeMetaMethod method(int index) const
{ return m_methods.at(index); }
- ComponentVersion version() const
- { return m_version; }
-
QString defaultPropertyName() const
{ return m_defaultPropertyName; }
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")) {
}
}
- 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())
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) {
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;
} // 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()
}
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(); }
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
{
// 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;
+ }
}
}