diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri index aaa9cacbb3823b6230a29cefbb28b940437fe5f7..d63d85bc21bff8f39c2ed75b286ee108acb30212 100644 --- a/src/libs/qmljs/qmljs-lib.pri +++ b/src/libs/qmljs/qmljs-lib.pri @@ -39,13 +39,13 @@ SOURCES += \ contains(QT_CONFIG, declarative) { QT += declarative - DEFINES += BUILD_DECLARATIVE_BACKEND - HEADERS += \ $$PWD/qtdeclarativemetatypebackend.h SOURCES += \ $$PWD/qtdeclarativemetatypebackend.cpp +} else { + DEFINES += NO_DECLARATIVE_BACKEND } contains(QT, gui) { diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 6985b221915858d84c907e6f1b815edacd5099ca..aab501ce0e88f45e56c88103aedce879f79053c1 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -30,10 +30,93 @@ #include "qmljsinterpreter.h" #include <QtCore/QDebug> +#ifndef NO_DECLARATIVE_BACKEND +# include <QtDeclarative/QmlType> +# include <QtDeclarative/QmlMetaType> +# include <QtDeclarative/private/qmlgraphicsanchors_p.h> // ### remove me +# include <QtCore/QMetaObject> +# include <QtCore/QMetaProperty> +#endif + using namespace QmlJS::Interpreter; namespace { +#ifndef NO_DECLARATIVE_BACKEND + +class QmlObjectValue: public ObjectValue +{ +public: + QmlObjectValue(const QMetaObject *metaObject, Engine *engine) + : ObjectValue(engine), _metaObject(metaObject) {} + + virtual ~QmlObjectValue() {} + + virtual const Value *lookupMember(const QString &name) const + { + for (int index = 0; index < _metaObject->propertyCount(); ++index) { + QMetaProperty prop = _metaObject->property(index); + + if (name == QString::fromUtf8(prop.name())) + return propertyValue(prop); + } + + return ObjectValue::lookupMember(name); + } + + virtual void processMembers(MemberProcessor *processor) const + { + for (int index = 0; index < _metaObject->propertyCount(); ++index) { + QMetaProperty prop = _metaObject->property(index); + + processor->process(prop.name(), propertyValue(prop)); + } + } + + const Value *propertyValue(const QMetaProperty &prop) const { + const Value *value = engine()->undefinedValue(); + + if (QmlMetaType::isObject(prop.userType())) { + QString typeName = QString::fromUtf8(prop.typeName()); + + if (typeName.endsWith(QLatin1Char('*'))) + typeName.truncate(typeName.length() - 1); + + typeName.replace(QLatin1Char('.'), QLatin1Char('/')); + + if (const ObjectValue *objectValue = engine()->newQmlObject(typeName)) + return objectValue; + } + + switch (prop.type()) { + case QMetaType::QByteArray: + case QMetaType::QString: + value = engine()->stringValue(); + break; + + case QMetaType::Bool: + value = engine()->booleanValue(); + break; + + case QMetaType::Int: + case QMetaType::Float: + case QMetaType::Double: + value = engine()->numberValue(); + break; + + default: + break; + } // end of switch + + return value; + } + +private: + const QMetaObject *_metaObject; +}; + +#endif + //////////////////////////////////////////////////////////////////////////////// // constructors //////////////////////////////////////////////////////////////////////////////// @@ -511,21 +594,11 @@ void ObjectValue::processMembers(MemberProcessor *processor) const while (it.hasNext()) { it.next(); - if (! processor->processMember(it.key(), it.value())) + if (! processor->process(it.key(), it.value())) break; } } -const Value *ObjectValue::member(const QString &name) const -{ - QHash<QString, const Value *>::const_iterator it = _members.find(name); - - if (it != _members.end()) - return it.value(); - else - return 0; -} - const Environment *ObjectValue::parent() const { return _scope; @@ -533,7 +606,7 @@ const Environment *ObjectValue::parent() const const Value *ObjectValue::lookupMember(const QString &name) const { - if (const Value *m = member(name)) + if (const Value *m = _members.value(name)) return m; if (_prototype) { @@ -1325,6 +1398,38 @@ void Engine::initializePrototypes() _globalObject->setProperty("RegExp", regexpCtor()); } +const ObjectValue *Engine::newQmlObject(const QString &name) +{ + if (const ObjectValue *object = _qmlObjects.value(name)) + return object; + +#ifndef NO_DECLARATIVE_BACKEND + if (name == QLatin1String("QmlGraphicsAnchors")) { + QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsAnchors::staticMetaObject, this); + _objects.append(object); + return object; + } + + // ### TODO: add support for QML packages + QString componentName; + componentName += QLatin1String("Qt/"); + componentName += name; + componentName.replace(QLatin1Char('.'), QLatin1Char('/')); + + if (QmlType *qmlType = QmlMetaType::qmlType(componentName.toUtf8(), 4, 6)) { + QmlObjectValue *object = new QmlObjectValue(qmlType->metaObject(), this); + _qmlObjects.insert(name, object); + _objects.append(object); + return object; + } +#endif + + //qDebug() << name; + + return 0; +} + + const Value *FunctionValue::invoke(const Activation *activation) const { return activation->thisObject(); // ### FIXME: it should return undefined diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h index 4b4bed6755e86346d1346bdb2d48f60f1562c5bd..c303602279045ba118eb352cce598d1ff7c734e3 100644 --- a/src/libs/qmljs/qmljsinterpreter.h +++ b/src/libs/qmljs/qmljsinterpreter.h @@ -202,7 +202,7 @@ public: virtual ~MemberProcessor() {} // Returns false to stop the processor. - virtual bool processMember(const QString &name, const Value *value) = 0; + virtual bool process(const QString &name, const Value *value) = 0; }; class QMLJS_EXPORT ObjectValue: public Value, public Environment @@ -224,7 +224,6 @@ public: virtual void processMembers(MemberProcessor *processor) const; - virtual const Value *member(const QString &name) const; virtual const Value *property(const QString &name) const; virtual void setProperty(const QString &name, const Value *value); virtual void removeProperty(const QString &name); @@ -435,6 +434,9 @@ public: Function *newFunction(); const Value *newArray(); // ### remove me + // QML objects + const ObjectValue *newQmlObject(const QString &name); + // global object ObjectValue *globalObject() const; const ObjectValue *mathObject() const; @@ -500,6 +502,7 @@ private: BooleanValue _booleanValue; StringValue _stringValue; QList<ObjectValue *> _objects; + QHash<QString, const ObjectValue *> _qmlObjects; ConvertToNumber _convertToNumber; ConvertToString _convertToString; diff --git a/src/libs/qmljs/qmljstypesystem.cpp b/src/libs/qmljs/qmljstypesystem.cpp index b4add55970dab203c9cb373716d698aaedca7d23..2a8ca0e68e4163d5ec7995b25225fad82e5cbc08 100644 --- a/src/libs/qmljs/qmljstypesystem.cpp +++ b/src/libs/qmljs/qmljstypesystem.cpp @@ -30,9 +30,9 @@ #include "qmljsmetatypebackend.h" #include "qmljstypesystem.h" -#ifdef BUILD_DECLARATIVE_BACKEND +#ifndef NO_DECLARATIVE_BACKEND # include "qtdeclarativemetatypebackend.h" -#endif // BUILD_DECLARATIVE_BACKEND +#endif // NO_DECLARATIVE_BACKEND #include <QDebug> @@ -40,9 +40,9 @@ using namespace QmlJS; TypeSystem::TypeSystem() { -#ifdef BUILD_DECLARATIVE_BACKEND +#ifndef NO_DECLARATIVE_BACKEND backends.append(new Internal::QtDeclarativeMetaTypeBackend(this)); -#endif // BUILD_DECLARATIVE_BACKEND +#endif // NO_DECLARATIVE_BACKEND } TypeSystem::~TypeSystem() diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp index eff8925820ba044911c52a22df427c4f3d75521b..3f240f6af00556f06fabccbddce32b5ef255d066 100644 --- a/src/plugins/qmljseditor/qmlcodecompletion.cpp +++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp @@ -315,7 +315,7 @@ public: } private: - virtual bool processMember(const QString &name, const Interpreter::Value *value) + virtual bool process(const QString &name, const Interpreter::Value *value) { _properties.insert(name, value); return true; @@ -703,6 +703,35 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) if (exprDoc->ast()) { Interpreter::Engine interp; + + foreach (Document::Ptr doc, snapshot) { + const QFileInfo fileInfo(doc->fileName()); + + if (fileInfo.suffix() != QLatin1String("qml")) + continue; + else if (fileInfo.absolutePath() != currentFilePath) // ### FIXME includ `imported' components + continue; + + const QString typeName = fileInfo.baseName(); + if (typeName.isEmpty()) + continue; + + QMapIterator<QString, IdSymbol *> it(doc->ids()); + while (it.hasNext()) { + it.next(); + + if (IdSymbol *symbol = it.value()) { + const QString id = it.key(); + + if (symbol->parentNode()) { + const QString component = symbol->parentNode()->name(); + if (const Interpreter::ObjectValue *object = interp.newQmlObject(component)) + interp.globalObject()->setProperty(id, object); + } + } + } + } + Evaluate evaluate(&interp); SearchPropertyDefinitions searchPropertyDefinitions;