From 96e5cae4c83adfd55dad8f5f76cbb97660d91040 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen <erik.verbruggen@nokia.com> Date: Mon, 7 Dec 2009 16:57:31 +0100 Subject: [PATCH] Added metainfo classes from Bauhaus for use in the QML editor. --- src/plugins/qmleditor/qmlcodecompletion.cpp | 12 +- src/plugins/qmleditor/qmlcodecompletion.h | 4 +- src/plugins/qmleditor/qmleditor.cpp | 8 +- src/plugins/qmleditor/qmleditor.h | 7 + src/plugins/qmleditor/qmleditorplugin.cpp | 4 +- .../qmleditor/qmlexpressionundercursor.cpp | 5 +- .../qmleditor/qmlexpressionundercursor.h | 4 +- src/plugins/qmleditor/qmlhoverhandler.cpp | 5 +- src/plugins/qmleditor/qmllookupcontext.cpp | 138 +--- src/plugins/qmleditor/qmllookupcontext.h | 27 +- .../qmleditor/qmlmodelmanagerinterface.h | 1 + .../qmleditor/qmlresolveexpression.cpp | 4 +- src/plugins/qmleditor/qmlresolveexpression.h | 8 +- .../qml/metatype/QmlMetaTypeBackend.cpp | 14 + src/shared/qml/metatype/QmlMetaTypeBackend.h | 33 + .../metatype/QtDeclarativeMetaTypeBackend.cpp | 232 ++++++ .../metatype/QtDeclarativeMetaTypeBackend.h | 47 ++ src/shared/qml/metatype/exception.cpp | 163 ++++ src/shared/qml/metatype/exception.h | 42 ++ .../qml/metatype/invalidmetainfoexception.cpp | 35 + .../qml/metatype/invalidmetainfoexception.h | 21 + src/shared/qml/metatype/metainfo.cpp | 461 ++++++++++++ src/shared/qml/metatype/metainfo.h | 83 +++ src/shared/qml/metatype/nodemetainfo.cpp | 695 ++++++++++++++++++ src/shared/qml/metatype/nodemetainfo.h | 103 +++ src/shared/qml/metatype/propertymetainfo.cpp | 378 ++++++++++ src/shared/qml/metatype/propertymetainfo.h | 84 +++ src/shared/qml/metatype/qmltypesystem.cpp | 42 ++ src/shared/qml/metatype/qmltypesystem.h | 34 + src/shared/qml/qml.pri | 30 +- src/shared/qml/qmldocument.cpp | 3 +- src/shared/qml/qmldocument.h | 8 +- src/shared/qml/qmlidcollector.cpp | 10 +- src/shared/qml/qmlidcollector.h | 14 +- src/shared/qml/qmlpackageinfo.cpp | 10 + src/shared/qml/qmlpackageinfo.h | 32 + src/shared/qml/qmlsymbol.cpp | 11 +- src/shared/qml/qmlsymbol.h | 51 +- 38 files changed, 2687 insertions(+), 176 deletions(-) create mode 100644 src/shared/qml/metatype/QmlMetaTypeBackend.cpp create mode 100644 src/shared/qml/metatype/QmlMetaTypeBackend.h create mode 100644 src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.cpp create mode 100644 src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.h create mode 100644 src/shared/qml/metatype/exception.cpp create mode 100644 src/shared/qml/metatype/exception.h create mode 100644 src/shared/qml/metatype/invalidmetainfoexception.cpp create mode 100644 src/shared/qml/metatype/invalidmetainfoexception.h create mode 100644 src/shared/qml/metatype/metainfo.cpp create mode 100644 src/shared/qml/metatype/metainfo.h create mode 100644 src/shared/qml/metatype/nodemetainfo.cpp create mode 100644 src/shared/qml/metatype/nodemetainfo.h create mode 100644 src/shared/qml/metatype/propertymetainfo.cpp create mode 100644 src/shared/qml/metatype/propertymetainfo.h create mode 100644 src/shared/qml/metatype/qmltypesystem.cpp create mode 100644 src/shared/qml/metatype/qmltypesystem.h create mode 100644 src/shared/qml/qmlpackageinfo.cpp create mode 100644 src/shared/qml/qmlpackageinfo.h diff --git a/src/plugins/qmleditor/qmlcodecompletion.cpp b/src/plugins/qmleditor/qmlcodecompletion.cpp index 6ee377ccb09..49bac438959 100644 --- a/src/plugins/qmleditor/qmlcodecompletion.cpp +++ b/src/plugins/qmleditor/qmlcodecompletion.cpp @@ -42,14 +42,16 @@ using namespace QmlEditor; using namespace QmlEditor::Internal; -QmlCodeCompletion::QmlCodeCompletion(QmlModelManagerInterface *modelManager,QObject *parent) +QmlCodeCompletion::QmlCodeCompletion(QmlModelManagerInterface *modelManager, Qml::MetaType::QmlTypeSystem *typeSystem, QObject *parent) : TextEditor::ICompletionCollector(parent), m_modelManager(modelManager), m_editor(0), m_startPosition(0), - m_caseSensitivity(Qt::CaseSensitive) + m_caseSensitivity(Qt::CaseSensitive), + m_typeSystem(typeSystem) { Q_ASSERT(modelManager); + Q_ASSERT(typeSystem); } QmlCodeCompletion::~QmlCodeCompletion() @@ -119,13 +121,13 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor) cursor.setPosition(pos); expressionUnderCursor(cursor, qmlDocument); - QmlLookupContext context(expressionUnderCursor.expressionScopes(), qmlDocument, m_modelManager->snapshot()); + QmlLookupContext context(expressionUnderCursor.expressionScopes(), qmlDocument, m_modelManager->snapshot(), m_typeSystem); QmlResolveExpression resolver(context); // qDebug()<<"*** expression under cursor:"<<expressionUnderCursor.expressionNode(); - QList<QmlSymbol*> symbols = resolver.visibleSymbols(expressionUnderCursor.expressionNode()); + QList<Qml::QmlSymbol*> symbols = resolver.visibleSymbols(expressionUnderCursor.expressionNode()); // qDebug()<<"***"<<symbols.size()<<"visible symbols"; - foreach (QmlSymbol *symbol, symbols) { + foreach (Qml::QmlSymbol *symbol, symbols) { QString word; if (symbol->isIdSymbol()) { diff --git a/src/plugins/qmleditor/qmlcodecompletion.h b/src/plugins/qmleditor/qmlcodecompletion.h index 8ed9aaf05a2..0b8c8edfa88 100644 --- a/src/plugins/qmleditor/qmlcodecompletion.h +++ b/src/plugins/qmleditor/qmlcodecompletion.h @@ -1,6 +1,7 @@ #ifndef QMLCODECOMPLETION_H #define QMLCODECOMPLETION_H +#include <qml/metatype/qmltypesystem.h> #include <texteditor/icompletioncollector.h> namespace TextEditor { @@ -18,7 +19,7 @@ class QmlCodeCompletion: public TextEditor::ICompletionCollector Q_OBJECT public: - QmlCodeCompletion(QmlModelManagerInterface *modelManager, QObject *parent = 0); + QmlCodeCompletion(QmlModelManagerInterface *modelManager, Qml::MetaType::QmlTypeSystem *typeSystem, QObject *parent = 0); virtual ~QmlCodeCompletion(); Qt::CaseSensitivity caseSensitivity() const; @@ -38,6 +39,7 @@ private: int m_startPosition; QList<TextEditor::CompletionItem> m_completions; Qt::CaseSensitivity m_caseSensitivity; + Qml::MetaType::QmlTypeSystem *m_typeSystem; }; diff --git a/src/plugins/qmleditor/qmleditor.cpp b/src/plugins/qmleditor/qmleditor.cpp index ab312bc2588..6cc759496a2 100644 --- a/src/plugins/qmleditor/qmleditor.cpp +++ b/src/plugins/qmleditor/qmleditor.cpp @@ -37,6 +37,7 @@ #include "qmllookupcontext.h" #include "qmlresolveexpression.h" +#include <qml/metatype/qmltypesystem.h> #include <qml/parser/qmljsastvisitor_p.h> #include <qml/parser/qmljsast_p.h> #include <qml/parser/qmljsengine_p.h> @@ -68,6 +69,7 @@ enum { UPDATE_DOCUMENT_DEFAULT_INTERVAL = 250 }; +using namespace Qml; using namespace QmlJS; using namespace QmlJS::AST; using namespace SharedTools; @@ -378,7 +380,8 @@ ScriptEditorEditable::ScriptEditorEditable(ScriptEditor *editor) ScriptEditor::ScriptEditor(QWidget *parent) : TextEditor::BaseTextEditor(parent), m_methodCombo(0), - m_modelManager(0) + m_modelManager(0), + m_typeSystem(0) { setParenthesesMatchingEnabled(true); setMarksVisible(true); @@ -397,6 +400,7 @@ ScriptEditor::ScriptEditor(QWidget *parent) : baseTextDocument()->setSyntaxHighlighter(new QmlHighlighter); m_modelManager = ExtensionSystem::PluginManager::instance()->getObject<QmlModelManagerInterface>(); + m_typeSystem = ExtensionSystem::PluginManager::instance()->getObject<Qml::MetaType::QmlTypeSystem>(); if (m_modelManager) { connect(m_modelManager, SIGNAL(documentUpdated(QmlEditor::QmlDocument::Ptr)), @@ -768,7 +772,7 @@ TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cur QmlExpressionUnderCursor expressionUnderCursor; expressionUnderCursor(expressionCursor, doc); - QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, snapshot); + QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, snapshot, m_typeSystem); QmlResolveExpression resolver(context); QmlSymbol *symbol = resolver.typeOf(expressionUnderCursor.expressionNode()); diff --git a/src/plugins/qmleditor/qmleditor.h b/src/plugins/qmleditor/qmleditor.h index 90af86fe9c7..6ad1c2c32c5 100644 --- a/src/plugins/qmleditor/qmleditor.h +++ b/src/plugins/qmleditor/qmleditor.h @@ -43,6 +43,12 @@ namespace Core { class ICore; } +namespace Qml { + namespace MetaType { + class QmlTypeSystem; + } +} + namespace QmlEditor { class QmlModelManagerInterface; @@ -146,6 +152,7 @@ private: QList<QmlJS::DiagnosticMessage> m_diagnosticMessages; QmlDocument::Ptr m_document; QmlModelManagerInterface *m_modelManager; + Qml::MetaType::QmlTypeSystem *m_typeSystem; }; } // namespace Internal diff --git a/src/plugins/qmleditor/qmleditorplugin.cpp b/src/plugins/qmleditor/qmleditorplugin.cpp index 8e1441f7c5f..3e1d032ee74 100644 --- a/src/plugins/qmleditor/qmleditorplugin.cpp +++ b/src/plugins/qmleditor/qmleditorplugin.cpp @@ -94,6 +94,8 @@ bool QmlEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err m_modelManager = new QmlModelManager(this); addAutoReleasedObject(m_modelManager); + Qml::MetaType::QmlTypeSystem *typeSystem = new Qml::MetaType::QmlTypeSystem; + addAutoReleasedObject(typeSystem); QList<int> context; context<< core->uniqueIDManager()->uniqueIdentifier(QmlEditor::Constants::C_QMLEDITOR); @@ -122,7 +124,7 @@ bool QmlEditorPlugin::initialize(const QStringList & /*arguments*/, QString *err cmd = am->command(TextEditor::Constants::UN_COMMENT_SELECTION); contextMenu->addAction(cmd); - m_completion = new QmlCodeCompletion(m_modelManager); + m_completion = new QmlCodeCompletion(m_modelManager, typeSystem); addAutoReleasedObject(m_completion); addAutoReleasedObject(new QmlHoverHandler()); diff --git a/src/plugins/qmleditor/qmlexpressionundercursor.cpp b/src/plugins/qmleditor/qmlexpressionundercursor.cpp index 5fd7c5031f3..b664d5d410f 100644 --- a/src/plugins/qmleditor/qmlexpressionundercursor.cpp +++ b/src/plugins/qmleditor/qmlexpressionundercursor.cpp @@ -9,6 +9,7 @@ #include <QDebug> +using namespace Qml; using namespace QmlJS; using namespace QmlJS::AST; @@ -118,7 +119,7 @@ namespace QmlEditor { virtual bool visit(UiObjectBinding *ast) { - if (ast->initializer && ast->initializer->rbraceToken.offset < _pos && _pos <= ast->initializer->lbraceToken.end()) { + if (ast->initializer && ast->initializer->lbraceToken.offset < _pos && _pos <= ast->initializer->rbraceToken.end()) { push(ast); Node::accept(ast->initializer, this); } @@ -128,7 +129,7 @@ namespace QmlEditor { virtual bool visit(UiObjectDefinition *ast) { - if (ast->initializer && ast->initializer->rbraceToken.offset < _pos && _pos <= ast->initializer->lbraceToken.end()) { + if (ast->initializer && ast->initializer->lbraceToken.offset < _pos && _pos <= ast->initializer->rbraceToken.end()) { push(ast); Node::accept(ast->initializer, this); } diff --git a/src/plugins/qmleditor/qmlexpressionundercursor.h b/src/plugins/qmleditor/qmlexpressionundercursor.h index 94681905806..29c9b4b1d7d 100644 --- a/src/plugins/qmleditor/qmlexpressionundercursor.h +++ b/src/plugins/qmleditor/qmlexpressionundercursor.h @@ -26,7 +26,7 @@ public: void operator()(const QTextCursor &cursor, const QmlDocument::Ptr &doc); - QStack<QmlSymbol *> expressionScopes() const + QStack<Qml::QmlSymbol *> expressionScopes() const { return _expressionScopes; } QmlJS::AST::Node *expressionNode() const @@ -45,7 +45,7 @@ private: QmlJS::AST::UiObjectMember *tryBinding(const QString &text); private: - QStack<QmlSymbol *> _expressionScopes; + QStack<Qml::QmlSymbol *> _expressionScopes; QmlJS::AST::Node *_expressionNode; int _expressionOffset; int _expressionLength; diff --git a/src/plugins/qmleditor/qmlhoverhandler.cpp b/src/plugins/qmleditor/qmlhoverhandler.cpp index a23e6607669..4e045539739 100644 --- a/src/plugins/qmleditor/qmlhoverhandler.cpp +++ b/src/plugins/qmleditor/qmlhoverhandler.cpp @@ -52,6 +52,7 @@ #include <QtHelp/QHelpEngineCore> using namespace Core; +using namespace Qml; using namespace QmlEditor; using namespace QmlEditor::Internal; @@ -186,7 +187,9 @@ void QmlHoverHandler::updateHelpIdAndTooltip(TextEditor::ITextEditor *editor, in QmlExpressionUnderCursor expressionUnderCursor; expressionUnderCursor(tc, doc); - QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, m_modelManager->snapshot()); + Qml::MetaType::QmlTypeSystem *typeSystem = ExtensionSystem::PluginManager::instance()->getObject<Qml::MetaType::QmlTypeSystem>(); + + QmlLookupContext context(expressionUnderCursor.expressionScopes(), doc, m_modelManager->snapshot(), typeSystem); QmlResolveExpression resolver(context); QmlSymbol *resolvedSymbol = resolver.typeOf(expressionUnderCursor.expressionNode()); diff --git a/src/plugins/qmleditor/qmllookupcontext.cpp b/src/plugins/qmleditor/qmllookupcontext.cpp index d5869c0bfcb..e4fc0336565 100644 --- a/src/plugins/qmleditor/qmllookupcontext.cpp +++ b/src/plugins/qmleditor/qmllookupcontext.cpp @@ -2,11 +2,14 @@ #include "qmllookupcontext.h" #include "qmlresolveexpression.h" +#include <qml/metatype/qmltypesystem.h> #include <qml/parser/qmljsast_p.h> #include <qml/parser/qmljsengine_p.h> #include <QDebug> +using namespace Qml; +using namespace Qml::MetaType; using namespace QmlEditor; using namespace QmlEditor::Internal; using namespace QmlJS; @@ -14,11 +17,14 @@ using namespace QmlJS::AST; QmlLookupContext::QmlLookupContext(const QStack<QmlSymbol *> &scopes, const QmlDocument::Ptr &doc, - const Snapshot &snapshot): + const Snapshot &snapshot, + QmlTypeSystem *typeSystem): _scopes(scopes), _doc(doc), - _snapshot(snapshot) + _snapshot(snapshot), + m_typeSystem(typeSystem) { + Q_ASSERT(typeSystem != 0); } static inline int findFirstQmlObjectScope(const QStack<QmlSymbol*> &scopes, int startIdx) @@ -114,104 +120,12 @@ QmlSymbol *QmlLookupContext::resolveType(const QString &name, const QString &fil return resolveBuildinType(name); } -// FIXME: use a REAL mete-type system here! -static QSet<QString> qmlMetaTypes = QSet<QString>() - << QLatin1String("AnchorChanges") - << QLatin1String("AnimatedImage") - << QLatin1String("Animation") - << QLatin1String("Behavior") - << QLatin1String("Binding") - << QLatin1String("BorderImage") - << QLatin1String("ColorAnimation") - << QLatin1String("Column") - << QLatin1String("Component") - << QLatin1String("Connection") - << QLatin1String("DateTimeFormatter") - << QLatin1String("EaseFollow") - << QLatin1String("Flickable") - << QLatin1String("Flipable") - << QLatin1String("FocusPanel") - << QLatin1String("FocusScope") - << QLatin1String("FolderListModel") - << QLatin1String("FontLoader") - << QLatin1String("Gradient") - << QLatin1String("GradientStop") - << QLatin1String("GraphicsObjectContainer") - << QLatin1String("Grid") - << QLatin1String("GridView") - << QLatin1String("Image") - << QLatin1String("Item") - << QLatin1String("KeyEvent") - << QLatin1String("Keys") - << QLatin1String("LayoutItem") - << QLatin1String("ListModel") - << QLatin1String("ListView") - << QLatin1String("Loader") - << QLatin1String("MouseEvent") - << QLatin1String("MouseRegion") - << QLatin1String("NumberAnimation") - << QLatin1String("NumberFormatter") - << QLatin1String("ParallelAnimation") - << QLatin1String("ParentAction") - << QLatin1String("ParentChange") - << QLatin1String("ParticleMotionGravity") - << QLatin1String("ParticleMotionLinear") - << QLatin1String("ParticleMotionWander") - << QLatin1String("Particles") - << QLatin1String("Path") - << QLatin1String("PathAttribute") - << QLatin1String("PathCubic") - << QLatin1String("PathElement") - << QLatin1String("PathLine") - << QLatin1String("PathPercent") - << QLatin1String("PathQuad") - << QLatin1String("PathView") - << QLatin1String("PauseAnimation") - << QLatin1String("PropertyAction") - << QLatin1String("PropertyAnimation") - << QLatin1String("PropertyChanges") - << QLatin1String("Rectangle") - << QLatin1String("Repeater") - << QLatin1String("Rotation") - << QLatin1String("Row") - << QLatin1String("Scale") - << QLatin1String("Script") - << QLatin1String("ScriptAction") - << QLatin1String("SequentialAnimation") - << QLatin1String("SpringFollow") - << QLatin1String("SqlBind") - << QLatin1String("SqlConnection") - << QLatin1String("SqlQuery") - << QLatin1String("State") - << QLatin1String("StateChangeScript") - << QLatin1String("SystemPalette") - << QLatin1String("Text") - << QLatin1String("TextEdit") - << QLatin1String("TextInput") - << QLatin1String("Timer") - << QLatin1String("Transform") - << QLatin1String("Transition") - << QLatin1String("VisualItemModel") - << QLatin1String("WebView") - << QLatin1String("XmlListModel") - << QLatin1String("XmlRole"); - QmlSymbol *QmlLookupContext::resolveBuildinType(const QString &name) { - // FIXME: use a REAL mete-type system here! - - if (name == "Rectangle") { - QmlBuildInSymbol *rectSymbol = new QmlBuildInSymbol(name); - rectSymbol->addMember(new QmlBuildInSymbol("x")); - rectSymbol->addMember(new QmlBuildInSymbol("y")); - rectSymbol->addMember(new QmlBuildInSymbol("height")); - rectSymbol->addMember(new QmlBuildInSymbol("width")); - return rectSymbol; - } else if (qmlMetaTypes.contains(name)) { - return new QmlBuildInSymbol(name); - } else { - return 0; - } + QList<Qml::PackageInfo> packages; + // FIXME: + packages.append(PackageInfo("Qt", 4, 6)); + return m_typeSystem->resolve(name, packages); } QmlSymbol *QmlLookupContext::resolveProperty(const QString &name, QmlSymbol *scope, const QString &fileName) @@ -270,7 +184,11 @@ QList<QmlSymbol*> QmlLookupContext::visibleSymbolsInScope() if (!_scopes.isEmpty()) { QmlSymbol *scope = _scopes.top(); + // add members defined in this symbol: result.append(scope->members()); + + // add the members of the type of this scope (= object): + result.append(expandType(scope)); } return result; @@ -301,9 +219,27 @@ QList<QmlSymbol*> QmlLookupContext::visibleTypes() } } - // TODO: handle Qt imports, hack for now: - foreach (const QString &name, qmlMetaTypes) - result.append(resolveBuildinType(name)); + result.append(m_typeSystem->availableTypes("Qt", 4, 6)); return result; } + +QList<QmlSymbol*> QmlLookupContext::expandType(Qml::QmlSymbol *symbol) +{ + if (symbol == 0) { + return QList<QmlSymbol*>(); + } else if (QmlBuildInSymbol *buildInSymbol = symbol->asBuildInSymbol()) { + return buildInSymbol->members(true); + } else if (QmlSymbolFromFile *symbolFromFile = symbol->asSymbolFromFile()){ + QList<QmlSymbol*> result; + + if (QmlSymbol *superTypeSymbol = resolveType(symbolFromFile->name(), symbolFromFile->fileName())) { + result.append(superTypeSymbol->members()); + result.append(expandType(superTypeSymbol)); + } + + return result; + } else { + return QList<QmlSymbol*>(); + } +} diff --git a/src/plugins/qmleditor/qmllookupcontext.h b/src/plugins/qmleditor/qmllookupcontext.h index 32b508a3cc7..e9708dc853e 100644 --- a/src/plugins/qmleditor/qmllookupcontext.h +++ b/src/plugins/qmleditor/qmllookupcontext.h @@ -1,6 +1,7 @@ #ifndef QMLLOOKUPCONTEXT_H #define QMLLOOKUPCONTEXT_H +#include <qml/metatype/qmltypesystem.h> #include <qml/parser/qmljsastvisitor_p.h> #include <qml/qmldocument.h> #include <qml/qmlsymbol.h> @@ -13,33 +14,37 @@ namespace Internal { class QmlLookupContext { public: - QmlLookupContext(const QStack<QmlSymbol *> &scopes, + QmlLookupContext(const QStack<Qml::QmlSymbol *> &scopes, const QmlDocument::Ptr &doc, - const Snapshot &snapshot); + const Snapshot &snapshot, + Qml::MetaType::QmlTypeSystem *typeSystem); - QmlSymbol *resolve(const QString &name); - QmlSymbol *resolveType(const QString &name) + Qml::QmlSymbol *resolve(const QString &name); + Qml::QmlSymbol *resolveType(const QString &name) { return resolveType(name, _doc->fileName()); } - QmlSymbol *resolveType(QmlJS::AST::UiQualifiedId *name) + Qml::QmlSymbol *resolveType(QmlJS::AST::UiQualifiedId *name) { return resolveType(toString(name), _doc->fileName()); } QmlDocument::Ptr document() const { return _doc; } - QList<QmlSymbol*> visibleSymbolsInScope(); - QList<QmlSymbol*> visibleTypes(); + QList<Qml::QmlSymbol*> visibleSymbolsInScope(); + QList<Qml::QmlSymbol*> visibleTypes(); + + QList<Qml::QmlSymbol*> expandType(Qml::QmlSymbol *symbol); private: - QmlSymbol *resolveType(const QString &name, const QString &fileName); - QmlSymbol *resolveProperty(const QString &name, QmlSymbol *scope, const QString &fileName); - QmlSymbol *resolveBuildinType(const QString &name); + Qml::QmlSymbol *resolveType(const QString &name, const QString &fileName); + Qml::QmlSymbol *resolveProperty(const QString &name, Qml::QmlSymbol *scope, const QString &fileName); + Qml::QmlSymbol *resolveBuildinType(const QString &name); static QString toString(QmlJS::AST::UiQualifiedId *id); private: - QStack<QmlSymbol *> _scopes; + QStack<Qml::QmlSymbol *> _scopes; QmlDocument::Ptr _doc; Snapshot _snapshot; + Qml::MetaType::QmlTypeSystem *m_typeSystem; }; } // namespace Internal diff --git a/src/plugins/qmleditor/qmlmodelmanagerinterface.h b/src/plugins/qmleditor/qmlmodelmanagerinterface.h index 3599f44672b..896f76a871d 100644 --- a/src/plugins/qmleditor/qmlmodelmanagerinterface.h +++ b/src/plugins/qmleditor/qmlmodelmanagerinterface.h @@ -37,6 +37,7 @@ #include <QSharedPointer> #include <qml/qmldocument.h> +#include <qml/metatype/qmltypesystem.h> namespace QmlEditor { diff --git a/src/plugins/qmleditor/qmlresolveexpression.cpp b/src/plugins/qmleditor/qmlresolveexpression.cpp index 1c798cd58f9..fa09b07aca8 100644 --- a/src/plugins/qmleditor/qmlresolveexpression.cpp +++ b/src/plugins/qmleditor/qmlresolveexpression.cpp @@ -3,6 +3,7 @@ #include <qml/parser/qmljsast_p.h> #include <qml/parser/qmljsengine_p.h> +using namespace Qml; using namespace QmlEditor; using namespace QmlEditor::Internal; using namespace QmlJS; @@ -16,8 +17,7 @@ QmlResolveExpression::QmlResolveExpression(const QmlLookupContext &context) QmlSymbol *QmlResolveExpression::typeOf(Node *node) { QmlSymbol *previousValue = switchValue(0); - if (node) - node->accept(this); + Node::accept(node, this); return switchValue(previousValue); } diff --git a/src/plugins/qmleditor/qmlresolveexpression.h b/src/plugins/qmleditor/qmlresolveexpression.h index 6030f1c29c7..d876afaf2e7 100644 --- a/src/plugins/qmleditor/qmlresolveexpression.h +++ b/src/plugins/qmleditor/qmlresolveexpression.h @@ -14,13 +14,13 @@ class QmlResolveExpression: protected QmlJS::AST::Visitor public: QmlResolveExpression(const QmlLookupContext &context); - QmlSymbol *typeOf(QmlJS::AST::Node *node); - QList<QmlSymbol*> visibleSymbols(QmlJS::AST::Node *node); + Qml::QmlSymbol *typeOf(QmlJS::AST::Node *node); + QList<Qml::QmlSymbol*> visibleSymbols(QmlJS::AST::Node *node); protected: using QmlJS::AST::Visitor::visit; - QmlSymbol *switchValue(QmlSymbol *symbol); + Qml::QmlSymbol *switchValue(Qml::QmlSymbol *symbol); virtual bool visit(QmlJS::AST::FieldMemberExpression *ast); virtual bool visit(QmlJS::AST::IdentifierExpression *ast); @@ -28,7 +28,7 @@ protected: private: QmlLookupContext _context; - QmlSymbol *_value; + Qml::QmlSymbol *_value; }; } // namespace Internal diff --git a/src/shared/qml/metatype/QmlMetaTypeBackend.cpp b/src/shared/qml/metatype/QmlMetaTypeBackend.cpp new file mode 100644 index 00000000000..ec65714989b --- /dev/null +++ b/src/shared/qml/metatype/QmlMetaTypeBackend.cpp @@ -0,0 +1,14 @@ +#include "QmlMetaTypeBackend.h" +#include "qmltypesystem.h" + +using namespace Qml::MetaType; + +QmlMetaTypeBackend::QmlMetaTypeBackend(QmlTypeSystem *typeSystem): + m_typeSystem(typeSystem) +{ + Q_ASSERT(typeSystem); +} + +QmlMetaTypeBackend::~QmlMetaTypeBackend() +{ +} diff --git a/src/shared/qml/metatype/QmlMetaTypeBackend.h b/src/shared/qml/metatype/QmlMetaTypeBackend.h new file mode 100644 index 00000000000..cd400bfa66a --- /dev/null +++ b/src/shared/qml/metatype/QmlMetaTypeBackend.h @@ -0,0 +1,33 @@ +#ifndef QMLMETATYPEBACKEND_H +#define QMLMETATYPEBACKEND_H + +#include <qml/qml_global.h> +#include <qml/qmlpackageinfo.h> +#include <qml/qmlsymbol.h> + +namespace Qml { +namespace MetaType { + +class QmlTypeSystem; + +class QML_EXPORT QmlMetaTypeBackend +{ +public: + QmlMetaTypeBackend(QmlTypeSystem *typeSystem); + virtual ~QmlMetaTypeBackend() = 0; + + virtual QList<QmlSymbol *> availableTypes(const QString &package, int majorVersion, int minorVersion) = 0; + virtual QmlSymbol *resolve(const QString &typeName, const QList<PackageInfo> &packages) = 0; + +protected: + QmlTypeSystem *typeSystem() const + { return m_typeSystem; } + +private: + QmlTypeSystem *m_typeSystem; +}; + +} // namespace MetaType +} // namespace Qml + +#endif // QMLMETATYPEBACKEND_H diff --git a/src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.cpp b/src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.cpp new file mode 100644 index 00000000000..53c1308b9ae --- /dev/null +++ b/src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.cpp @@ -0,0 +1,232 @@ +#include "metainfo.h" +#include "QtDeclarativeMetaTypeBackend.h" + +#include <QDebug> + +namespace Qml { +namespace MetaType { +namespace Internal { + +class QmlDeclarativeSymbol: public QmlBuildInSymbol +{ +public: + virtual ~QmlDeclarativeSymbol() + {} + +protected: + QmlDeclarativeSymbol(QtDeclarativeMetaTypeBackend* backend): + m_backend(backend) + { Q_ASSERT(backend); } + + QtDeclarativeMetaTypeBackend* backend() const + { return m_backend; } + +private: + QtDeclarativeMetaTypeBackend* m_backend; +}; + +class QmlDeclarativeObjectSymbol: public QmlDeclarativeSymbol +{ + QmlDeclarativeObjectSymbol(const QmlDeclarativeObjectSymbol &); + QmlDeclarativeObjectSymbol &operator=(const QmlDeclarativeObjectSymbol &); + +public: + QmlDeclarativeObjectSymbol(const QKineticDesigner::NodeMetaInfo &metaInfo, QtDeclarativeMetaTypeBackend* backend): + QmlDeclarativeSymbol(backend), + m_metaInfo(metaInfo) + { + Q_ASSERT(metaInfo.isValid()); + + m_name = m_metaInfo.typeName(); + const int slashIdx = m_name.indexOf('/'); + if (slashIdx != -1) + m_name = m_name.mid(slashIdx + 1); + } + + virtual ~QmlDeclarativeObjectSymbol() + { qDeleteAll(m_members); } + + virtual const QString name() const + { return m_name; } + + virtual QmlBuildInSymbol *type() const + { return 0; } + + virtual const List members() + { + if (m_membersToBeDone) + initMembers(); + + return m_members; + } + + virtual List members(bool includeBaseClassMembers) + { + List result = members(); + + if (includeBaseClassMembers) + result.append(backend()->inheritedMembers(m_metaInfo)); + + return result; + } + +public: + static QString key(const QKineticDesigner::NodeMetaInfo &metaInfo) + { + return key(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); + } + + static QString key(const QString &typeNameWithPackage, int majorVersion, int minorVersion) + { + return QString(typeNameWithPackage) + + QLatin1Char('@') + + QString::number(majorVersion) + + QLatin1Char('.') + + QString::number(minorVersion); + } + + static QString key(const QString &packageName, const QString &typeName, int majorVersion, int minorVersion) + { + return packageName + + QLatin1Char('/') + + typeName + + QLatin1Char('@') + + QString::number(majorVersion) + + QLatin1Char('.') + + QString::number(minorVersion); + } + +private: + void initMembers() + { + if (!m_membersToBeDone) + return; + m_membersToBeDone = false; + + m_members = backend()->members(m_metaInfo); + } + +private: + QKineticDesigner::NodeMetaInfo m_metaInfo; + QString m_name; + + bool m_membersToBeDone; + List m_members; +}; + +class QmlDeclarativePropertySymbol: public QmlDeclarativeSymbol +{ + QmlDeclarativePropertySymbol(const QmlDeclarativePropertySymbol &); + QmlDeclarativePropertySymbol &operator=(const QmlDeclarativePropertySymbol &); + +public: + QmlDeclarativePropertySymbol(const QKineticDesigner::PropertyMetaInfo &metaInfo, QtDeclarativeMetaTypeBackend* backend): + QmlDeclarativeSymbol(backend), + m_metaInfo(metaInfo) + { + } + + virtual ~QmlDeclarativePropertySymbol() + {} + + virtual const QString name() const + { return m_metaInfo.name(); } + + virtual QmlBuildInSymbol *type() const + { return backend()->typeOf(m_metaInfo); } + + virtual const List members() + { + return List(); + } + + virtual List members(bool /*includeBaseClassMembers*/) + { + return members(); + } + +private: + QKineticDesigner::PropertyMetaInfo m_metaInfo; +}; + +} // namespace Internal +} // namespace MetaType +} // namespace Qml + +using namespace Qml; +using namespace Qml::MetaType; +using namespace Qml::MetaType::Internal; + +QtDeclarativeMetaTypeBackend::QtDeclarativeMetaTypeBackend(QmlTypeSystem *typeSystem): + QmlMetaTypeBackend(typeSystem) +{ + foreach (const QKineticDesigner::NodeMetaInfo &metaInfo, QKineticDesigner::MetaInfo::global().allTypes()) { + m_symbols.insert(QmlDeclarativeObjectSymbol::key(metaInfo), new QmlDeclarativeObjectSymbol(metaInfo, this)); + } +} + +QtDeclarativeMetaTypeBackend::~QtDeclarativeMetaTypeBackend() +{ + qDeleteAll(m_symbols.values()); +} + +QList<QmlSymbol *> QtDeclarativeMetaTypeBackend::availableTypes(const QString &package, int majorVersion, int minorVersion) +{ + QList<QmlSymbol *> result; + const QString prefix = package + QLatin1Char('/'); + + foreach (const QKineticDesigner::NodeMetaInfo &metaInfo, QKineticDesigner::MetaInfo::global().allTypes()) { + if (metaInfo.typeName().startsWith(prefix) && metaInfo.majorVersion() == majorVersion && metaInfo.minorVersion() == minorVersion) + result.append(getSymbol(metaInfo)); + } + + return result; +} + +QmlSymbol *QtDeclarativeMetaTypeBackend::resolve(const QString &typeName, const QList<PackageInfo> &packages) +{ + QList<QmlSymbol *> result; + + foreach (const PackageInfo &package, packages) { + if (QmlSymbol *symbol = m_symbols.value(QmlDeclarativeObjectSymbol::key(package.name(), typeName, package.majorVersion(), package.minorVersion()), 0)) + return symbol; + } + + return 0; +} + +QList<QmlSymbol *> QtDeclarativeMetaTypeBackend::members(const QKineticDesigner::NodeMetaInfo &metaInfo) +{ + QList<QmlSymbol *> result; + + foreach (const QKineticDesigner::PropertyMetaInfo &propertyInfo, metaInfo.properties(false).values()) { + result.append(new QmlDeclarativePropertySymbol(propertyInfo, this)); + } + + return result; +} + +QList<QmlSymbol *> QtDeclarativeMetaTypeBackend::inheritedMembers(const QKineticDesigner::NodeMetaInfo &metaInfo) +{ + QList<QmlSymbol *> result; + + foreach (const QKineticDesigner::NodeMetaInfo &superNode, metaInfo.directSuperClasses()) { + result.append(getSymbol(superNode)->members(true)); + } + + return result; +} + +QmlDeclarativeSymbol *QtDeclarativeMetaTypeBackend::typeOf(const QKineticDesigner::PropertyMetaInfo &metaInfo) +{ + const QString key = QmlDeclarativeObjectSymbol::key(metaInfo.type(), metaInfo.typeMajorVersion(), metaInfo.typeMinorVersion()); + + return m_symbols.value(key, 0); +} + +QmlDeclarativeSymbol *QtDeclarativeMetaTypeBackend::getSymbol(const QKineticDesigner::NodeMetaInfo &metaInfo) +{ + const QString key = QmlDeclarativeObjectSymbol::key(metaInfo); + + return m_symbols.value(key, 0); +} diff --git a/src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.h b/src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.h new file mode 100644 index 00000000000..e0693c124ce --- /dev/null +++ b/src/shared/qml/metatype/QtDeclarativeMetaTypeBackend.h @@ -0,0 +1,47 @@ +#ifndef QTDECLARATIVEMETATYPEBACKEND_H +#define QTDECLARATIVEMETATYPEBACKEND_H + +#include <qml/metatype/QmlMetaTypeBackend.h> +#include <qml/metatype/nodemetainfo.h> +#include <qml/metatype/propertymetainfo.h> + +#include <QtCore/QList> + +namespace Qml { +namespace MetaType { +namespace Internal { + +class QmlDeclarativeSymbol; +class QmlDeclarativeObjectSymbol; +class QmlDeclarativePropertySymbol; + +class QtDeclarativeMetaTypeBackend: public QmlMetaTypeBackend +{ + friend class QmlDeclarativeSymbol; + friend class QmlDeclarativeObjectSymbol; + friend class QmlDeclarativePropertySymbol; + +public: + QtDeclarativeMetaTypeBackend(QmlTypeSystem *typeSystem); + ~QtDeclarativeMetaTypeBackend(); + + virtual QList<QmlSymbol *> availableTypes(const QString &package, int majorVersion, int minorVersion); + virtual QmlSymbol *resolve(const QString &typeName, const QList<PackageInfo> &packages); + +protected: + QList<QmlSymbol *> members(const QKineticDesigner::NodeMetaInfo &metaInfo); + QList<QmlSymbol *> inheritedMembers(const QKineticDesigner::NodeMetaInfo &metaInfo); + QmlDeclarativeSymbol *typeOf(const QKineticDesigner::PropertyMetaInfo &metaInfo); + +private: + QmlDeclarativeSymbol *getSymbol(const QKineticDesigner::NodeMetaInfo &metaInfo); + +private: + QMap<QString, QmlDeclarativeSymbol*> m_symbols; +}; + +} // namespace Internal +} // namespace MetaType +} // namespace Qml + +#endif // QTDECLARATIVEMETATYPEBACKEND_H diff --git a/src/shared/qml/metatype/exception.cpp b/src/shared/qml/metatype/exception.cpp new file mode 100644 index 00000000000..1d836476e2c --- /dev/null +++ b/src/shared/qml/metatype/exception.cpp @@ -0,0 +1,163 @@ +#include "exception.h" + +#ifdef Q_OS_LINUX +#include <execinfo.h> +#include <cxxabi.h> +#endif + +#include <QRegExp> + +/*! +\defgroup CoreExceptions +*/ +/*! +\class QKineticDesigner::Exception +\ingroup CoreExceptions +\brief This is the abstract base class for all excetions. + Exceptions should be used in cases there is no other way to say something goes wrong. For example + the result would be a inconsistent model or a crash. +*/ + + +namespace QKineticDesigner { + +#ifdef Q_OS_LINUX +const char* demangle(const char* name) +{ + char buf[1024]; + size_t size = 1024; + int status; + char* res; + res = abi::__cxa_demangle(name, + buf, + &size, + &status); + return res; +} +#else +const char* demangle(const char* name) +{ + return name; +} +#endif + + +bool Exception::s_shouldAssert = true; + +void Exception::setShouldAssert(bool assert) +{ + s_shouldAssert = assert; +} + +bool Exception::shouldAssert() +{ + return s_shouldAssert; +} + +/*! +\brief Constructor + +\param line use the __LINE__ macro +\param function use the __FUNCTION__ or the Q_FUNC_INFO macro +\param file use the __FILE__ macro +*/ +Exception::Exception(int line, + const QString &function, + const QString &file) + : m_line(line), + m_function(function), + m_file(file) +{ +#ifdef Q_OS_LINUX + void * array[50]; + int nSize = backtrace(array, 50); + char ** symbols = backtrace_symbols(array, nSize); + + for (int i = 0; i < nSize; i++) + { + m_backTrace.append(QString("%1\n").arg(symbols[i])); + } + + free(symbols); +#endif + +if (s_shouldAssert) + Q_ASSERT_X(false, function.toLatin1(), QString("%1:%2 - %3").arg(file).arg(line).arg(function).toLatin1()); +} + +Exception::~Exception() +{ +} + +/*! +\brief Returns the unmangled backtrace of this exception + +\returns the backtrace as a string +*/ +QString Exception::backTrace() const +{ + return m_backTrace; +} + +/*! +\brief Returns the optional description of this exception + +\returns the description as string +*/ +QString Exception::description() const +{ + return QString(); +} + +/*! +\brief Returns the line number where this exception was thrown + +\returns the line number as integer +*/ +int Exception::line() const +{ + return m_line; +} + +/*! +\brief Returns the function name where this exception was thrown + +\returns the function name as string +*/ +QString Exception::function() const +{ + return m_function; +} + +/*! +\brief Returns the file name where this exception was thrown + +\returns the file name as string +*/ +QString Exception::file() const +{ + return m_file; +} + +QDebug operator<<(QDebug debug, const Exception &exception) +{ + debug.nospace() << "Exception: " << exception.type() << "\n" + "Function: " << exception.function() << "\n" + "File: " << exception.file() << "\n" + "Line: " << exception.line() << "\n"; + if (!exception.description().isEmpty()) + debug.nospace() << exception.description(); + + if (!exception.backTrace().isEmpty()) + debug.nospace() << exception.backTrace(); + + return debug.space(); +} + +/*! +\fn QString Exception::type() const +\brief Returns the type of this exception + +\returns the type as a string +*/ +} diff --git a/src/shared/qml/metatype/exception.h b/src/shared/qml/metatype/exception.h new file mode 100644 index 00000000000..093859db6bf --- /dev/null +++ b/src/shared/qml/metatype/exception.h @@ -0,0 +1,42 @@ +#ifndef EXCEPTION_H +#define EXCEPTION_H + +#include <qml/qml_global.h> + +#include <QString> +#include <QtDebug> + +namespace QKineticDesigner { + +class QML_EXPORT Exception +{ +public: + Exception(int line, + const QString &function, + const QString &file); + virtual ~Exception(); + + virtual QString type() const=0; + virtual QString description() const; + + int line() const; + QString function() const; + QString file() const; + QString backTrace() const; + + static void setShouldAssert(bool assert); + static bool shouldAssert(); + +private: + int m_line; + QString m_function; + QString m_file; + QString m_backTrace; + static bool s_shouldAssert; +}; + +QML_EXPORT QDebug operator<<(QDebug debug, const Exception &exception); + +} + +#endif // EXCEPTION_H diff --git a/src/shared/qml/metatype/invalidmetainfoexception.cpp b/src/shared/qml/metatype/invalidmetainfoexception.cpp new file mode 100644 index 00000000000..a6caa45b5f9 --- /dev/null +++ b/src/shared/qml/metatype/invalidmetainfoexception.cpp @@ -0,0 +1,35 @@ +#include "invalidmetainfoexception.h" + +/*! +\class QKineticDesigner::InvalidMetaInfoException +\ingroup CoreExceptions +\brief Exception for a invalid meta info + +\see NodeMetaInfo PropertyMetaInfo MetaInfo +*/ +namespace QKineticDesigner { +/*! +\brief Constructor + +\param line use the __LINE__ macro +\param function use the __FUNCTION__ or the Q_FUNC_INFO macro +\param file use the __FILE__ macro +*/ +InvalidMetaInfoException::InvalidMetaInfoException(int line, + const QString &function, + const QString &file) + : Exception(line, function, file) +{ +} + +/*! +\brief Returns the type of this exception + +\returns the type as a string +*/ +QString InvalidMetaInfoException::type() const +{ + return "InvalidMetaInfoException"; +} + +} diff --git a/src/shared/qml/metatype/invalidmetainfoexception.h b/src/shared/qml/metatype/invalidmetainfoexception.h new file mode 100644 index 00000000000..883616884a9 --- /dev/null +++ b/src/shared/qml/metatype/invalidmetainfoexception.h @@ -0,0 +1,21 @@ +#ifndef INVALIDMETAINFOEXCEPTION_H +#define INVALIDMETAINFOEXCEPTION_H + +#include "exception.h" + +namespace QKineticDesigner { + +class QML_EXPORT InvalidMetaInfoException : public Exception +{ +public: + InvalidMetaInfoException(int line, + const QString &function, + const QString &file); + + QString type() const; + +}; + +} + +#endif // INVALIDMETAINFOEXCEPTION_H diff --git a/src/shared/qml/metatype/metainfo.cpp b/src/shared/qml/metatype/metainfo.cpp new file mode 100644 index 00000000000..356c6805b44 --- /dev/null +++ b/src/shared/qml/metatype/metainfo.cpp @@ -0,0 +1,461 @@ +#include "invalidmetainfoexception.h" +#include "metainfo.h" +#include "propertymetainfo.h" + +#include <QPair> +#include <QtAlgorithms> +#include <QMetaProperty> +#include <QmlMetaType> + +enum { + debug = false +}; + +namespace QKineticDesigner { +namespace Internal { + +class MetaInfoPrivate +{ + Q_DISABLE_COPY(MetaInfoPrivate) +public: + typedef QSharedPointer<MetaInfoPrivate> Pointer; + typedef QWeakPointer<MetaInfoPrivate> WeakPointer; + + + MetaInfoPrivate(MetaInfo *q); + void clear(); + + void initialize(); + void parseQmlTypes(); + void parseNonQmlTypes(); + void parseValueTypes(); + void parseNonQmlClassRecursively(const QMetaObject *qMetaObject); + void parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const; + void parseClassInfo(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const; + + QString typeName(const QMetaObject *qMetaObject) const; + + void parseXmlFiles(); + + QMultiHash<QString, QString> m_superClassHash; // the list of direct superclasses + QHash<QString, NodeMetaInfo> m_nodeMetaInfoHash; + QHash<QString, QString> m_QtTypesToQmlTypes; + + MetaInfo *m_q; + bool m_isInitialized; +}; + +MetaInfoPrivate::MetaInfoPrivate(MetaInfo *q) : + m_q(q), + m_isInitialized(false) +{ +} + +void MetaInfoPrivate::clear() +{ + m_superClassHash.clear(); + m_nodeMetaInfoHash.clear(); + m_isInitialized = false; +} + +void MetaInfoPrivate::initialize() +{ + parseQmlTypes(); + parseNonQmlTypes(); +// parseValueTypes(); +// parseXmlFiles(); + + m_isInitialized = true; +} + + + +void MetaInfoPrivate::parseProperties(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const +{ + Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject"); + Q_ASSERT_X(nodeMetaInfo.isValid(), Q_FUNC_INFO, "invalid NodeMetaInfo"); + + for (int i = qMetaObject->propertyOffset(); i < qMetaObject->propertyCount(); ++i) { + QMetaProperty qProperty = qMetaObject->property(i); + + PropertyMetaInfo propertyInfo; + + propertyInfo.setName(QLatin1String(qProperty.name())); + + QString typeName(qProperty.typeName()); + QString noStar = typeName; + bool star = false; + while (noStar.contains('*')) {//strip star + noStar.chop(1); + star = true; + } + if (m_QtTypesToQmlTypes.contains(noStar)) { + typeName = star ? m_QtTypesToQmlTypes.value(noStar) + '*' : m_QtTypesToQmlTypes.value(noStar); + //### versions + } + int majorVersion = -1, minorVersion = -1; + if (QmlType *propertyType = QmlMetaType::qmlType(qMetaObject)) { + majorVersion = propertyType->majorVersion(); + minorVersion = propertyType->minorVersion(); + } + + propertyInfo.setType(typeName, majorVersion, minorVersion); + propertyInfo.setValid(true); + propertyInfo.setReadable(qProperty.isReadable()); + propertyInfo.setWritable(qProperty.isWritable()); + propertyInfo.setResettable(qProperty.isResettable()); + propertyInfo.setEnumType(qProperty.isEnumType()); + propertyInfo.setFlagType(qProperty.isFlagType()); + +// if (propertyInfo.isEnumType()) { +// EnumeratorMetaInfo enumerator; +// +// QMetaEnum qEnumerator = qProperty.enumerator(); +// enumerator.setValid(qEnumerator.isValid()); +// enumerator.setIsFlagType(qEnumerator.isFlag()); +// enumerator.setScope(qEnumerator.scope()); +// enumerator.setName(qEnumerator.name()); +// for (int i = 0 ;i < qEnumerator.keyCount(); i++) +// { +// enumerator.addElement(qEnumerator.valueToKey(i), i); +// } +// +// propertyInfo.setEnumerator(enumerator); +// } + + nodeMetaInfo.addProperty(propertyInfo); + } +} + +void MetaInfoPrivate::parseClassInfo(NodeMetaInfo &nodeMetaInfo, const QMetaObject *qMetaObject) const +{ + Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject"); + Q_ASSERT_X(nodeMetaInfo.isValid(), Q_FUNC_INFO, "invalid NodeMetaInfo"); + for (int index = qMetaObject->classInfoCount() - 1 ; index >= 0 ; --index) { + QMetaClassInfo classInfo = qMetaObject->classInfo(index); + if (QLatin1String(classInfo.name()) == QLatin1String("DefaultProperty")) { + nodeMetaInfo.setDefaultProperty(classInfo.value()); + return; + } + } +} + +void MetaInfoPrivate::parseNonQmlClassRecursively(const QMetaObject *qMetaObject) +{ + Q_ASSERT_X(qMetaObject, Q_FUNC_INFO, "invalid QMetaObject"); + const QString className = qMetaObject->className(); + if ( !m_q->hasNodeMetaInfo(className) + && !QmlMetaType::qmlTypeNames().contains(typeName(qMetaObject).toAscii()) ) { + NodeMetaInfo nodeMetaInfo(*m_q); + nodeMetaInfo.setTypeName(typeName(qMetaObject)); + parseProperties(nodeMetaInfo, qMetaObject); + parseClassInfo(nodeMetaInfo, qMetaObject); + + if (debug) + qDebug() << "adding non qml type" << className << typeName(qMetaObject) << ", parent type" << typeName(qMetaObject->superClass()); + m_q->addNodeInfo(nodeMetaInfo, typeName(qMetaObject->superClass())); + } + + if (const QMetaObject *superClass = qMetaObject->superClass()) { + parseNonQmlClassRecursively(superClass); + } +} + + +QString MetaInfoPrivate::typeName(const QMetaObject *qMetaObject) const +{ + if (!qMetaObject) + return QString(); + QString className = qMetaObject->className(); + if (QmlType *qmlType = QmlMetaType::qmlType(qMetaObject)) { + QString qmlClassName(qmlType->qmlTypeName()); + if (!qmlClassName.isEmpty()) + className = qmlType->qmlTypeName(); // Ensure that we always use the qml name, + // if available. + } + return className; +} + +void MetaInfoPrivate::parseQmlTypes() +{ + foreach (QmlType *qmlType, QmlMetaType::qmlTypes()) { + const QString qtTypeName(qmlType->typeName()); + const QString qmlTypeName(qmlType->qmlTypeName()); + m_QtTypesToQmlTypes.insert(qtTypeName, qmlTypeName); + } + foreach (QmlType *qmlType, QmlMetaType::qmlTypes()) { + const QMetaObject *qMetaObject = qmlType->metaObject(); + + // parseQmlTypes is called iteratively e.g. when plugins are loaded + if (m_q->hasNodeMetaInfo(qmlType->qmlTypeName(), qmlType->majorVersion(), qmlType->minorVersion())) + continue; + + NodeMetaInfo nodeMetaInfo(*m_q); + nodeMetaInfo.setTypeName(qmlType->qmlTypeName()); + nodeMetaInfo.setMajorVersion(qmlType->majorVersion()); + nodeMetaInfo.setMinorVersion(qmlType->minorVersion()); + + parseProperties(nodeMetaInfo, qMetaObject); + parseClassInfo(nodeMetaInfo, qMetaObject); + + QString superTypeName = typeName(qMetaObject->superClass()); + if (qmlType->baseMetaObject() != qMetaObject) { + // type is declared with Q_DECLARE_EXTENDED_TYPE + // also parse properties of original type + parseProperties(nodeMetaInfo, qmlType->baseMetaObject()); + superTypeName = typeName(qmlType->baseMetaObject()->superClass()); + } + + m_q->addNodeInfo(nodeMetaInfo, superTypeName); + } +} + +void MetaInfoPrivate::parseNonQmlTypes() +{ + foreach (QmlType *qmlType, QmlMetaType::qmlTypes()) { + parseNonQmlClassRecursively(qmlType->metaObject()); + } +} + +} // namespace Internal + +using QKineticDesigner::Internal::MetaInfoPrivate; + +MetaInfo MetaInfo::s_global; +QStringList MetaInfo::s_pluginDirs; + + +/*! +\class QKineticDesigner::MetaInfo +\ingroup CoreModel +\brief The MetaInfo class provides meta information about qml types and properties. + +The MetaInfo, NodeMetaInfo, PropertyMetaInfo and EnumeratorMetaInfo +classes provide information about the (static and dynamic) qml types available in +a specific model. Just like their Model, ModelNode and AbstractProperty counterparts, +objects of these classes are handles - that means, they are implicitly shared, and +should be created on the stack. + +The MetaInfo object should always be accessed via the model (see Model::metaInfo()). +Otherwise types specific to a model (like sub components) might +be missed. + +\see Model::metaInfo(), QKineticDesigner::NodeMetaInfo, QKineticDesigner::PropertyMetaInfo, QKineticDesigner::EnumeratorMetaInfo +*/ + +/*! + \brief Constructs a copy of the given meta info. + */ +MetaInfo::MetaInfo(const MetaInfo &metaInfo) : + m_p(metaInfo.m_p) +{ +} + +/*! + \brief Creates a meta information object with just the qml types registered statically. + You almost always want to use Model::metaInfo() instead! + + You almost certainly want to access the meta information for the model. + + \see Model::metaInfo() + */ +MetaInfo::MetaInfo() : + m_p(new MetaInfoPrivate(this)) +{ +} + +MetaInfo::~MetaInfo() +{ +} + +/*! + \brief Assigns other to this meta information and returns a reference to this meta information. + */ +MetaInfo& MetaInfo::operator=(const MetaInfo &other) +{ + m_p = other.m_p; + return *this; +} + +QList<NodeMetaInfo> MetaInfo::allTypes() const +{ + return m_p->m_nodeMetaInfoHash.values(); +} + +/*! + \brief Returns whether a type with the given name is registered in the meta system. + */ +bool MetaInfo::hasNodeMetaInfo(const QString &typeName, int /*majorVersion*/, int /*minorVersion*/) const +{ + if (m_p->m_nodeMetaInfoHash.contains(typeName)) + return true; + if (!isGlobal()) + return global().hasNodeMetaInfo(typeName); + return false; +} + +/*! + \brief Returns meta information for a qml type. An invalid NodeMetaInfo object if the type is unknown. + */ +NodeMetaInfo MetaInfo::nodeMetaInfo(const QString &typeName, int /*majorVersion*/, int /*minorVersion*/) const +{ + if (m_p->m_nodeMetaInfoHash.contains(typeName)) + return m_p->m_nodeMetaInfoHash.value(typeName, NodeMetaInfo()); + if (!isGlobal()) + return global().nodeMetaInfo(typeName); + + return NodeMetaInfo(); +} + +QStringList MetaInfo::superClasses(const QString &className) const +{ + QStringList ancestorList = m_p->m_superClassHash.values(className); + foreach (const QString &ancestor, ancestorList) { + QStringList superClassList = superClasses(ancestor); + if (!superClassList.isEmpty()) + ancestorList += superClassList; + } + if (!isGlobal()) + ancestorList += global().superClasses(className); + return ancestorList; +} + +QStringList MetaInfo::directSuperClasses(const QString &className) const +{ + QStringList directAncestorList = m_p->m_superClassHash.values(className); + if (!isGlobal()) + directAncestorList += global().directSuperClasses(className); + return directAncestorList; +} + +QList<NodeMetaInfo> MetaInfo::superClasses(const NodeMetaInfo &nodeInfo) const +{ + if (!nodeInfo.isValid()) { + Q_ASSERT_X(nodeInfo.isValid(), Q_FUNC_INFO, "Invalid nodeInfo argument"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + QList<NodeMetaInfo> superClassList; + + foreach (const QString &typeName, superClasses(nodeInfo.typeName())) { + if (!hasNodeMetaInfo(typeName)) + continue; + const NodeMetaInfo superClass = nodeMetaInfo(typeName); + if (!superClassList.contains(superClass)) + superClassList.append(superClass); + } + return superClassList; +} + +QList<NodeMetaInfo> MetaInfo::directSuperClasses(const NodeMetaInfo &nodeInfo) const +{ + if (!nodeInfo.isValid()) { + Q_ASSERT_X(nodeInfo.isValid(), Q_FUNC_INFO, "Invalid nodeInfo argument"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + QList<NodeMetaInfo> superClassList; + + foreach (const QString &typeName, directSuperClasses(nodeInfo.typeName())) { + if (!hasNodeMetaInfo(typeName)) + continue; + const NodeMetaInfo superClass = nodeMetaInfo(typeName); + if (!superClassList.contains(superClass)) + superClassList.append(superClass); + } + return superClassList; +} + +QStringList MetaInfo::itemLibraryItems() const +{ + QStringList completeList = m_p->m_nodeMetaInfoHash.keys(); + QStringList finalList; + foreach (const QString &name, completeList) { + if (nodeMetaInfo(name).isVisibleToItemLibrary()) + finalList.append(name); + } + + if (!isGlobal()) + finalList += global().itemLibraryItems(); + + return finalList; +} + +/*! + \brief Returns whether className is the same type or a type derived from superClassName. + */ +bool MetaInfo::isSubclassOf(const QString &className, const QString &superClassName) const +{ + return (className == superClassName) || superClasses(className).contains(superClassName); +} + +/*! + \brief Access to the global meta information object. + You almost always want to use Model::metaInfo() instead. + + Internally all meta information objects share this "global" object + where static qml type information is stored. + */ +MetaInfo MetaInfo::global() +{ + if (!s_global.m_p->m_isInitialized) { + s_global.m_p = QSharedPointer<MetaInfoPrivate>(new MetaInfoPrivate(&s_global)); + s_global.m_p->initialize(); + } + return s_global; +} + +/*! + \brief Clears the global meta information object. + + This method should be called once on application shutdown to free static data structures. + */ +void MetaInfo::clearGlobal() +{ + MetaInfo::global().m_p->clear(); +} + +void MetaInfo::setPluginPaths(const QStringList &paths) +{ + s_pluginDirs = paths; +} + +/*! + This bypasses the notifications to the model that the metatype has changed. + Use MetaInfo::addNodeInfo() instead + */ +void MetaInfo::addSuperClassRelationship(const QString &superClassName, const QString &className) +{ + m_p->m_superClassHash.insert(className, superClassName); +} + +void MetaInfo::addNodeInfo(NodeMetaInfo &nodeInfo, const QString &baseType) +{ + if (nodeInfo.typeName().isEmpty() || nodeInfo.metaInfo() != *this) + throw new InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + + if (nodeInfo.typeName() == baseType) // prevent simple recursion + throw new InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + + m_p->m_nodeMetaInfoHash.insert(nodeInfo.typeName(), nodeInfo); + + if (!baseType.isEmpty()) { + m_p->m_superClassHash.insert(nodeInfo.typeName(), baseType); + } +} + +bool MetaInfo::isGlobal() const +{ + return (this->m_p == s_global.m_p); +} + +bool operator==(const MetaInfo &first, const MetaInfo &second) +{ + return first.m_p == second.m_p; +} + +bool operator!=(const MetaInfo &first, const MetaInfo &second) +{ + return !(first == second); +} +} //namespace QKineticDesigner diff --git a/src/shared/qml/metatype/metainfo.h b/src/shared/qml/metatype/metainfo.h new file mode 100644 index 00000000000..86a2447c7f5 --- /dev/null +++ b/src/shared/qml/metatype/metainfo.h @@ -0,0 +1,83 @@ +#ifndef METAINFO_H +#define METAINFO_H + +#include <qml/qml_global.h> +#include <qml/metatype/nodemetainfo.h> +#include <qml/metatype/propertymetainfo.h> + +#include <QMultiHash> +#include <QString> +#include <QStringList> +#include <QtCore/QSharedPointer> + +namespace QKineticDesigner { + +class ModelNode; +class AbstractProperty; + +namespace Internal { + class MetaInfoPrivate; + class ModelPrivate; + class SubComponentManagerPrivate; + typedef QSharedPointer<MetaInfoPrivate> MetaInfoPrivatePointer; +} + +QML_EXPORT bool operator==(const MetaInfo &first, const MetaInfo &second); +QML_EXPORT bool operator!=(const MetaInfo &first, const MetaInfo &second); + +class QML_EXPORT MetaInfo +{ + friend class QKineticDesigner::Internal::MetaInfoPrivate; + friend class QKineticDesigner::Internal::MetaInfoParser; + friend class QKineticDesigner::NodeMetaInfo; + friend bool QKineticDesigner::operator==(const MetaInfo &, const MetaInfo &); + +public: + MetaInfo(const MetaInfo &metaInfo); + ~MetaInfo(); + MetaInfo& operator=(const MetaInfo &other); + + QList<NodeMetaInfo> allTypes() const; + + bool hasNodeMetaInfo(const QString &typeName, int majorVersion = 4, int minorVersion = 6) const; + // ### makes no sense since ModelNode has minor/major version + NodeMetaInfo nodeMetaInfo(const ModelNode &node) const; + NodeMetaInfo nodeMetaInfo(const QString &typeName, int majorVersion = 4, int minorVersion = 6) const; + + // TODO: Move these to private + bool isSubclassOf(const QString &className, const QString &superClassName) const; + bool isSubclassOf(const ModelNode &modelNode, const QString &superClassName) const; + + bool hasEnumerator(const QString &enumeratorName) const; + + QStringList itemLibraryItems() const; + +public: + static MetaInfo global(); + static void clearGlobal(); + + static void setPluginPaths(const QStringList &paths); + +private: + QStringList superClasses(const QString &className) const; + QStringList directSuperClasses(const QString &className) const; + QList<NodeMetaInfo> superClasses(const NodeMetaInfo &nodeMetaInfo) const; + QList<NodeMetaInfo> directSuperClasses(const NodeMetaInfo &nodeMetaInfo) const; + + void addSuperClassRelationship(const QString &superClassName, const QString &className); + + void addNodeInfo(NodeMetaInfo &info, const QString &baseType); + + bool isGlobal() const; + +private: + MetaInfo(); + + Internal::MetaInfoPrivatePointer m_p; + static MetaInfo s_global; + static QStringList s_pluginDirs; +}; + +} //namespace QKineticDesigner + +#endif // METAINFO_H diff --git a/src/shared/qml/metatype/nodemetainfo.cpp b/src/shared/qml/metatype/nodemetainfo.cpp new file mode 100644 index 00000000000..b3b136c076e --- /dev/null +++ b/src/shared/qml/metatype/nodemetainfo.cpp @@ -0,0 +1,695 @@ +#include "invalidmetainfoexception.h" +#include "metainfo.h" +#include "nodemetainfo.h" +#include "propertymetainfo.h" + +#include <QtCore/QSharedData> +#include <QtCore/QtDebug> +#include <QtGui/QIcon> +#include <QtDeclarative/QmlMetaType> +#include <QtDeclarative/QmlContext> +#include <QtDeclarative/QmlEngine> +#include <QtDeclarative/QmlComponent> +#include <private/qmlvaluetype_p.h> + +namespace QKineticDesigner { + +namespace Internal { + +class NodeMetaInfoData : public QSharedData +{ +public: + typedef enum { + No = -1, + Unknown = 0, + Yes = 1, + } TristateBoolean; + +public: + NodeMetaInfoData(const MetaInfo &metaInfo) : + metaInfo(metaInfo), + isContainer(false), + isVisibleToItemLibrary(false), + isFXItem(Unknown), + icon(), + category("misc") + { } + + MetaInfo metaInfo; + QString typeName; + bool isContainer; + bool isVisibleToItemLibrary; + TristateBoolean isFXItem; + QHash<QString, PropertyMetaInfo> propertyMetaInfoHash; + QIcon icon; + QString category; + QString qmlFile; + QString defaultProperty; + int majorVersion; + int minorVersion; +}; + +} // namespace Internal + +/*! +\class QKineticDesigner::NodeMetaInfo +\ingroup CoreModel +\brief The NodeMetaInfo class provides meta information about a qml type. + +A NodeMetaInfo object can be created via ModelNode::metaInfo, or MetaInfo::nodeMetaInfo. + +The object can be invalid - you can check this by calling isValid(). +The object is invalid if you ask for meta information for +an non-existing qml property. Also the node meta info can become invalid +if the enclosing type is deregistered from the meta type system (e.g. +a sub component qml file is deleted). Trying to call any accessor methods on an invalid +NodeMetaInfo object will result in an InvalidMetaInfoException being thrown. + +\see QKineticDesigner::MetaInfo, QKineticDesigner::PropertyMetaInfo, QKineticDesigner::EnumeratorMetaInfo +*/ + +NodeMetaInfo::NodeMetaInfo() + : m_data(0) +{ + // create invalid node +} + +NodeMetaInfo::NodeMetaInfo(const MetaInfo &metaInfo) + : m_data(new Internal::NodeMetaInfoData(metaInfo)) +{ +} + +NodeMetaInfo::~NodeMetaInfo() +{ +} + +/*! + \brief Creates a copy of the handle. + */ +NodeMetaInfo::NodeMetaInfo(const NodeMetaInfo &other) + : m_data(other.m_data) +{ +} + +/*! + \brief Copies the handle. + */ +NodeMetaInfo &NodeMetaInfo::operator=(const NodeMetaInfo &other) +{ + if (this != &other) + this->m_data = other.m_data; + + return *this; +} + +/*! + \brief Returns whether the meta information system knows about this type. + */ +bool NodeMetaInfo::isValid() const +{ + return (m_data.data() != 0); +} + +MetaInfo NodeMetaInfo::metaInfo() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return m_data->metaInfo; +} + +/*! + \brief Creates an instance of the qml type in the given qml context. + + \throws InvalidArgumentException when the context argument is a null pointer + \throws InvalidMetaInfoException if the object is not valid + */ +QObject *NodeMetaInfo::createInstance(QmlContext *parentContext) const +{ + if (!parentContext) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Context cannot be null"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + QObject *object = 0; + if (isComponent()) { + // qml component + // TODO: This is maybe expensive ... + QmlComponent component(parentContext->engine(), QUrl::fromLocalFile(m_data->qmlFile)); + object = component.create(parentContext); + } else { + // primitive + object = QmlMetaType::qmlType(typeName().toAscii(), 4, 6)->create(); + if (object && parentContext) + QmlEngine::setContextForObject(object, new QmlContext(parentContext, object)); + } + return object; +} + +/*! + \brief Returns all (direct and indirect) ancestor types. + + \throws InvalidMetaInfoException if the object is not valid + */ +QList<NodeMetaInfo> NodeMetaInfo::superClasses() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return m_data->metaInfo.superClasses(*this); +} + +/*! + \brief Returns direct ancestor types. + + \throws InvalidMetaInfoException if the object is not valid + */ +QList<NodeMetaInfo> NodeMetaInfo::directSuperClasses() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return m_data->metaInfo.directSuperClasses(*this); +} + +/*! + \brief Returns meta information for all properties, including properties inherited from base types. + + Returns a Hash with the name of the property as key and property meta information as value. Node + In case there are multiple properties with the same name in the hierarchy the property defined + in the more concrete subclass is chosen. + + \throws InvalidMetaInfoException if the object is not valid + */ +QHash<QString,PropertyMetaInfo> NodeMetaInfo::properties(bool resolveDotSyntax ) const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + QHash<QString,PropertyMetaInfo> propertiesInfo; + propertiesInfo = m_data->propertyMetaInfoHash; + foreach (const NodeMetaInfo &nodeInfo, directSuperClasses()) { + QHash<QString,PropertyMetaInfo> superClassProperties = nodeInfo.properties(); + QHashIterator<QString,PropertyMetaInfo> iter(superClassProperties); + while (iter.hasNext()) { + iter.next(); + if (!propertiesInfo.contains(iter.key())) + propertiesInfo.insert(iter.key(), iter.value()); + } + } + if (resolveDotSyntax) { + QHashIterator<QString,PropertyMetaInfo> iter(dotProperties()); + while (iter.hasNext()) { + iter.next(); + if (!propertiesInfo.contains(iter.key())) + propertiesInfo.insert(iter.key(), iter.value()); + } + } + return propertiesInfo; +} + +/*! + \brief Returns meta information for all dot properties, including properties inherited from base types. + + */ +QHash<QString,PropertyMetaInfo> NodeMetaInfo::dotProperties() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + QHash<QString,PropertyMetaInfo> propertiesInfo; + + foreach (const QString &propertyName, properties().keys()) { + if (property(propertyName).hasDotSubProperties()) { + QString propertyType = property(propertyName).type(); + if (propertyType.right(1) == "*") + propertyType = propertyType.left(propertyType.size() - 1).trimmed(); + NodeMetaInfo nodeInfo(m_data->metaInfo.nodeMetaInfo(propertyType, majorVersion(), minorVersion())); + if (nodeInfo.isValid()) { + QHashIterator<QString,PropertyMetaInfo> iter(nodeInfo.properties()); + while (iter.hasNext()) { + iter.next(); + if (!propertiesInfo.contains(iter.key()) && iter.key() != "objectName") + propertiesInfo.insert(propertyName + "." + iter.key(), iter.value()); + } + } + } + } + return propertiesInfo; +} + +/*! + \brief Returns meta information for a property. An invalid PropertyMetaInfo object if the given property name is unknown. + + \throws InvalidMetaInfoException if the object is not valid + */ +PropertyMetaInfo NodeMetaInfo::property(const QString &propertyName, bool resolveDotSyntax) const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + if (resolveDotSyntax && propertyName.contains('.')) { + const QStringList nameParts = propertyName.split('.'); + NodeMetaInfo nodeInfo = *this; + const int partCount = nameParts.size(); + for (int i = 0; i < partCount; ++i) { + const QString namePart(nameParts.at(i)); + const PropertyMetaInfo propInfo = nodeInfo.property(namePart, false); + + if (!propInfo.isValid()) + break; + + if (i + 1 == partCount) + return propInfo; + + QString propertyType = propInfo.type(); + if (propertyType.right(1) == "*") + propertyType = propertyType.left(propertyType.size() - 1).trimmed(); + nodeInfo = m_data->metaInfo.nodeMetaInfo(propertyType, majorVersion(), minorVersion()); + if (!nodeInfo.isValid()) { + qDebug() << "no type info available for" << propertyType; + break; + } + } + + return PropertyMetaInfo(); + } else { + PropertyMetaInfo propertyMetaInfo; + + if (hasLocalProperty(propertyName)) { + propertyMetaInfo = m_data->propertyMetaInfoHash.value(propertyName, PropertyMetaInfo()); + } else { + foreach (const NodeMetaInfo &superTypeMetaInfo, directSuperClasses()) { + Q_ASSERT(superTypeMetaInfo.isValid()); + propertyMetaInfo = superTypeMetaInfo.property(propertyName); + if (propertyMetaInfo.isValid()) + break; + } + } + + return propertyMetaInfo; + } +} + +/*! + \brief Returns whether the type has a (not inherited) property. + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::hasLocalProperty(const QString &propertyName, bool resolveDotSyntax) const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + if (resolveDotSyntax && propertyName.contains('.')) { + const QStringList nameParts = propertyName.split('.'); + NodeMetaInfo nodeInfo = *this; + const int partCount = nameParts.size(); + for (int i = 0; i < partCount; ++i) { + QString namePart(nameParts.at(i)); + const PropertyMetaInfo propInfo = nodeInfo.property(namePart, false); + + if (!propInfo.isValid()) + break; + + if (i + 1 == partCount) + return true; + + QString propertyType = propInfo.type(); + if (propertyType.right(1) == "*") + propertyType = propertyType.left(propertyType.size() - 1).trimmed(); + nodeInfo = m_data->metaInfo.nodeMetaInfo(propertyType, majorVersion(), minorVersion()); + if (!nodeInfo.isValid()) { + qDebug() << "no type info available for" << propertyType; + break; + } + } + + return false; + } else { + return m_data->propertyMetaInfoHash.contains(propertyName); + } +} + +/*! + \brief Returns whether the type has a (inherited or not inherited) property. + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::hasProperty(const QString &propertyName, bool resolveDotSyntax) const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + if (hasLocalProperty(propertyName, resolveDotSyntax)) + return true; + + foreach (const NodeMetaInfo &nodeMetaInfo, directSuperClasses()) { + if (nodeMetaInfo.hasProperty(propertyName, resolveDotSyntax)) + return true; + } + + return false; +} + +void NodeMetaInfo::addProperty(const PropertyMetaInfo &property) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->propertyMetaInfoHash.insert(property.name(), property); +} + +/*! + \brief Returns the name of the qml type. + + This is not necessarily the class name: E.g. the class defining "Item" is QmlGraphicsItem. + + \throws InvalidMetaInfoException if the object is not valid + */ +QString NodeMetaInfo::typeName() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->typeName; +} + +/*! + \brief Returns the name of the major number of the qml type. + + \throws InvalidMetaInfoException if the object is not valid +*/ +int NodeMetaInfo::majorVersion() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return 4; +} + + +/*! + \brief Returns the name of the minor number of the qml type to which the type is used. + + \throws InvalidMetaInfoException if the object is not valid +*/ +int NodeMetaInfo::minorVersion() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return m_data->minorVersion; +} + +bool NodeMetaInfo::hasDefaultProperty() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return m_data->defaultProperty.isNull(); +} + +QString NodeMetaInfo::defaultProperty() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + return m_data->defaultProperty; +} + +void NodeMetaInfo::setDefaultProperty(const QString &defaultProperty) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + m_data->defaultProperty = defaultProperty; +} + +void NodeMetaInfo::setMajorVersion(int version) +{ + m_data->majorVersion = version; +} + +void NodeMetaInfo::setMinorVersion(int version) +{ + m_data->minorVersion = version; +} + +void NodeMetaInfo::setInvalid() +{ + if (!isValid()) + return; + + m_data = 0; +} + +void NodeMetaInfo::setTypeName(const QString &typeName) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->typeName = typeName; +} + +uint qHash(const NodeMetaInfo &nodeMetaInfo) +{ + if (!nodeMetaInfo.isValid()) + return 0; + return qHash(nodeMetaInfo.m_data->typeName); +} + +bool operator==(const NodeMetaInfo &firstNodeInfo, + const NodeMetaInfo &secondNodeInfo) +{ + if (!firstNodeInfo.isValid() || !secondNodeInfo.isValid()) + return false; + return firstNodeInfo.m_data->typeName == secondNodeInfo.m_data->typeName; +} + +/*! + \brief Returns whether objects of these type can have children. + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::isContainer() const +{ + // TODO KAI: Is this too generic? + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->isContainer; +} + +bool NodeMetaInfo::isVisibleToItemLibrary() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->isVisibleToItemLibrary; +} + +void NodeMetaInfo::setIsContainer(bool isContainer) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->isContainer = isContainer; +} + +void NodeMetaInfo::setIsVisibleToItemLibrary(bool isVisibleToItemLibrary) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->isVisibleToItemLibrary = isVisibleToItemLibrary; +} + +QIcon NodeMetaInfo::icon() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->icon; +} + +QString NodeMetaInfo::category() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->category; +} + +void NodeMetaInfo::setIcon(const QIcon &icon) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->icon = icon; +} + +void NodeMetaInfo::setCategory(const QString &category) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->category = category; +} + +/*! + \brief Returns whether the type inherits from "QWidget". + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::isWidget() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->metaInfo.isSubclassOf(m_data->typeName, "Qt/QWidget"); +} + +/*! + \brief Returns whether the type inherits from "QGraphicsWidget". + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::isGraphicsWidget() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->metaInfo.isSubclassOf(m_data->typeName, "Qt/QGraphicsWidget"); +} + +/*! + \brief Returns whether the type inherits from "QGraphicsObject". + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::isGraphicsObject() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->metaInfo.isSubclassOf(m_data->typeName, "QGraphicsObject"); +} + +/*! + \brief Returns whether the type inherits from "Item/QmlGraphicsItem". + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::isQmlGraphicsItem() const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + + if (m_data->isFXItem == Internal::NodeMetaInfoData::Unknown) { + m_data->isFXItem = m_data->metaInfo.isSubclassOf(m_data->typeName, "Qt/Item") ? Internal::NodeMetaInfoData::Yes : Internal::NodeMetaInfoData::No; + } + + return m_data->isFXItem == Internal::NodeMetaInfoData::Yes; +} + +bool NodeMetaInfo::isComponent() const +{ + return !m_data->qmlFile.isEmpty(); +} + +/*! + \brief Returns whether the type inherits from a type. + + \throws InvalidMetaInfoException if the object is not valid + */ +bool NodeMetaInfo::isSubclassOf(const QString &type, int /*majorVersion*/, int /*minorVersion*/) const +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + return m_data->metaInfo.isSubclassOf(m_data->typeName, type); +} + +void NodeMetaInfo::setQmlFile(const QString &filePath) +{ + if (!isValid()) { + Q_ASSERT_X(0, Q_FUNC_INFO, "Invalid NodeMetaInfo object"); + throw InvalidMetaInfoException(__LINE__, __FUNCTION__, __FILE__); + } + m_data->qmlFile = filePath; +} + +//QDataStream& operator<<(QDataStream& stream, const NodeMetaInfo& nodeMetaInfo) +//{ +// stream << nodeMetaInfo.typeName(); +// stream << nodeMetaInfo.majorVersion(); +// stream << nodeMetaInfo.minorVersionTo(); +// +// return stream; +//} +// +//QDataStream& operator>>(QDataStream& stream, NodeMetaInfo& nodeMetaInfo) +//{ +// QString typeName; +// int minorVersion; +// int majorVersion; +// +// stream >> minorVersion; +// stream >> majorVersion; +// stream >> typeName; +// +// nodeMetaInfo = MetaInfo::global().nodeMetaInfo(typeName/*, majorVersion ,minorVersion*/); +// +// return stream; +//} + +} // namespace QKineticDesigner diff --git a/src/shared/qml/metatype/nodemetainfo.h b/src/shared/qml/metatype/nodemetainfo.h new file mode 100644 index 00000000000..1d1215a90d3 --- /dev/null +++ b/src/shared/qml/metatype/nodemetainfo.h @@ -0,0 +1,103 @@ +#ifndef NODEMETAINFO_H +#define NODEMETAINFO_H + +#include <qml/qml_global.h> + +#include <QList> +#include <QString> +#include <QExplicitlySharedDataPointer> +#include <QIcon> + +class QmlContext; + +namespace QKineticDesigner { + +class MetaInfo; + +namespace Internal { + class MetaInfoPrivate; + class MetaInfoParser; + class NodeMetaInfoData; + class SubComponentManagerPrivate; + class ItemLibraryInfoData; +} + +class PropertyMetaInfo; + +class QML_EXPORT NodeMetaInfo +{ + friend class QKineticDesigner::MetaInfo; + friend class QKineticDesigner::Internal::ItemLibraryInfoData; + friend class QKineticDesigner::Internal::MetaInfoPrivate; + friend class QKineticDesigner::Internal::MetaInfoParser; + friend QML_EXPORT uint qHash(const NodeMetaInfo &nodeMetaInfo); + friend QML_EXPORT bool operator ==(const NodeMetaInfo &firstNodeInfo, const NodeMetaInfo &secondNodeInfo); + +public: + ~NodeMetaInfo(); + + NodeMetaInfo(const NodeMetaInfo &other); + NodeMetaInfo &operator=(const NodeMetaInfo &other); + + bool isValid() const; + MetaInfo metaInfo() const; + + QObject *createInstance(QmlContext *parentContext) const; + + PropertyMetaInfo property(const QString &propertyName, bool resolveDotSyntax = false) const; + + QList<NodeMetaInfo> superClasses() const; + QList<NodeMetaInfo> directSuperClasses() const; + QHash<QString,PropertyMetaInfo> properties(bool resolveDotSyntax = false) const; + + + QString typeName() const; + int majorVersion() const; + int minorVersion() const; + + bool hasDefaultProperty() const; + QString defaultProperty() const; + + bool hasProperty(const QString &propertyName, bool resolveDotSyntax = false) const; + bool isContainer() const; + bool isVisibleToItemLibrary() const; + + bool isWidget() const; + bool isGraphicsWidget() const; + bool isGraphicsObject() const; + bool isQmlGraphicsItem() const; + bool isComponent() const; + bool isSubclassOf(const QString& type, int majorVersion = 4, int minorVersion = 6) const; + + QIcon icon() const; + QString category() const; + +private: + NodeMetaInfo(); + NodeMetaInfo(const MetaInfo &metaInfo); + + void setInvalid(); + void setTypeName(const QString &typeName); + void addProperty(const PropertyMetaInfo &property); + void setIsContainer(bool isContainer); + void setIsVisibleToItemLibrary(bool isVisibleToItemLibrary); + void setIcon(const QIcon &icon); + void setCategory(const QString &category); + void setQmlFile(const QString &filePath); + void setDefaultProperty(const QString &defaultProperty); + void setMajorVersion(int version); + void setMinorVersion(int version); + + bool hasLocalProperty(const QString &propertyName, bool resolveDotSyntax = false) const; + QHash<QString,PropertyMetaInfo> dotProperties() const; + +private: + QExplicitlySharedDataPointer<Internal::NodeMetaInfoData> m_data; +}; + +QML_EXPORT uint qHash(const NodeMetaInfo &nodeMetaInfo); +QML_EXPORT bool operator ==(const NodeMetaInfo &firstNodeInfo, + const NodeMetaInfo &secondNodeInfo); +} + +#endif // NODEMETAINFO_H diff --git a/src/shared/qml/metatype/propertymetainfo.cpp b/src/shared/qml/metatype/propertymetainfo.cpp new file mode 100644 index 00000000000..fae7fa49bef --- /dev/null +++ b/src/shared/qml/metatype/propertymetainfo.cpp @@ -0,0 +1,378 @@ +#include "propertymetainfo.h" + +#include <QSharedData> + +#include "invalidmetainfoexception.h" +#include "metainfo.h" +#include <private/qmlvaluetype_p.h> + +namespace QKineticDesigner { + +namespace Internal +{ + +class PropertyMetaInfoData : public QSharedData +{ +public: + PropertyMetaInfoData() + : QSharedData(), + isValid(false), + readable(false), + writeable(false), + resettable(false), + enumType(false), + flagType(false), + isVisible(false) + {} + + QString name; + QString type; + int majorVersion; + int minorVersion; + bool isValid; + + bool readable; + bool writeable; + bool resettable; + + bool enumType; + bool flagType; + bool isVisible; + + QHash<QString, QVariant> defaultValueHash; +}; + +} + +/*! +\class QKineticDesigner::PropertyMetaInfo +\ingroup CoreModel +\brief The PropertyMetaInfo class provides meta information about a qml type property. + +A PropertyMetaInfo object can be NodeMetaInfo, or AbstractProperty::metaInfo. + +The object can be invalid - you can check this by calling isValid(). +The object is invalid if you ask for meta information for +an non-existing qml type. Also the node meta info can become invalid +if the type is deregistered from the meta type system (e.g. +a sub component qml file is deleted). Trying to call any accessor methods on an invalid +PropertyMetaInfo object will result in an InvalidMetaInfoException being thrown. + + +\see QKineticDesigner::MetaInfo, QKineticDesigner::NodeMetaInfo, QKineticDesigner::EnumeratorMetaInfo +*/ + +PropertyMetaInfo::PropertyMetaInfo() + : m_data(new Internal::PropertyMetaInfoData) +{ +} + +PropertyMetaInfo::~PropertyMetaInfo() +{ +} + +/*! + \brief Creates a copy of the handle. + */ +PropertyMetaInfo::PropertyMetaInfo(const PropertyMetaInfo &other) + : m_data(other.m_data) +{ +} + +/*! + \brief Copies the handle. + */ +PropertyMetaInfo &PropertyMetaInfo::operator=(const PropertyMetaInfo &other) +{ + if (this != &other) + m_data = other.m_data; + + return *this; +} + +/*! + \brief Returns whether the meta information system knows about this property. + */ +bool PropertyMetaInfo::isValid() const +{ + return m_data->isValid; +} + +/*! + \brief Returns the name of the property. + */ +QString PropertyMetaInfo::name() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->name; +} + +/*! + \brief Returns the type name of the property. + */ +QString PropertyMetaInfo::type() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->type; +} + +int PropertyMetaInfo::typeMajorVersion() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->majorVersion; +} + +int PropertyMetaInfo::typeMinorVersion() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->minorVersion; +} + +bool PropertyMetaInfo::isVisibleToPropertyEditor() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->isVisible; +} + +void PropertyMetaInfo::setIsVisibleToPropertyEditor(bool isVisible) +{ + m_data->isVisible = isVisible; +} + +/*! + \brief Returns the QVariant type of the property. + */ +QVariant::Type PropertyMetaInfo::variantTypeId() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + Q_ASSERT(!m_data->type.isEmpty()); + return QVariant::nameToType(m_data->type.toLatin1().data()); +} + +/*! + \brief Returns whether the propery is readable. + */ +bool PropertyMetaInfo::isReadable() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->readable; +} + +/*! + \brief Returns whether the propery is writeable. + */ +bool PropertyMetaInfo::isWriteable() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->writeable; +} + +/*! + \brief Returns whether the propery is resettable. + */ +bool PropertyMetaInfo::isResettable() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->resettable; +} + +/*! + \brief Returns whether the propery is complex value type. + */ +bool PropertyMetaInfo::isValueType() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + + QmlValueType *valueType(QmlValueTypeFactory::valueType(variantTypeId())); + return valueType; +} + +/*! + \brief Returns whether the propery is a QmlList. + */ +bool PropertyMetaInfo::isListProperty() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + + return type().contains("QmlList"); +} + +/*! + \brief Returns whether the propery has sub properties with "." syntax e.g. font + */ +bool PropertyMetaInfo::hasDotSubProperties() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + + return isValueType() || !isWriteable(); +} + +/*! + \brief Returns whether the propery stores an enum value. + */ +bool PropertyMetaInfo::isEnumType() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->enumType; +} + +/*! + \brief Returns whether the propery stores a flag value. + */ +bool PropertyMetaInfo::isFlagType() const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + return m_data->flagType; +} + +/*! + \brief Returns a default value if there is one specified, an invalid QVariant otherwise. + */ +QVariant PropertyMetaInfo::defaultValue(const NodeMetaInfo &nodeMetaInfoArg) const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + + QList<NodeMetaInfo> nodeMetaInfoList(nodeMetaInfoArg.superClasses()); + nodeMetaInfoList.prepend(nodeMetaInfoArg); + foreach (const NodeMetaInfo &nodeMetaInfo, nodeMetaInfoList) { + if (m_data->defaultValueHash.contains(nodeMetaInfo.typeName())) + return m_data->defaultValueHash.value(nodeMetaInfo.typeName()); + } + + return QVariant(); +} + +void PropertyMetaInfo::setName(const QString &name) +{ + m_data->name = name; +} + +void PropertyMetaInfo::setType(const QString &type, int majorVersion, int minorVersion) +{ + m_data->type = type; + m_data->majorVersion = majorVersion; + m_data->minorVersion = minorVersion; +} + +void PropertyMetaInfo::setValid(bool isValid) +{ + m_data->isValid = isValid; +} + +void PropertyMetaInfo::setReadable(bool isReadable) +{ + m_data->readable = isReadable; +} + +void PropertyMetaInfo::setWritable(bool isWritable) +{ + m_data->writeable = isWritable; +} + +void PropertyMetaInfo::setResettable(bool isRessetable) +{ + m_data->resettable = isRessetable; +} + +void PropertyMetaInfo::setEnumType(bool isEnumType) +{ + m_data->enumType = isEnumType; +} + +void PropertyMetaInfo::setFlagType(bool isFlagType) +{ + m_data->flagType = isFlagType; +} + +void PropertyMetaInfo::setDefaultValue(const NodeMetaInfo &nodeMetaInfo, const QVariant &value) +{ + m_data->defaultValueHash.insert(nodeMetaInfo.typeName(), value); +} + +/*! + \brief cast value type of QVariant parameter + + If the type of the passed variant does not correspond to type(), the method tries to convert + the value according to QVariant::convert(). Returns a new QVariant with casted value type + if successful, an invalid QVariant otherwise. + + \param variant the QVariant to take the value from + \returns QVariant with aligned value type, or invalid QVariant + */ +QVariant PropertyMetaInfo::castedValue(const QVariant &originalVariant) const +{ + if (!isValid()) { + Q_ASSERT_X(isValid(), Q_FUNC_INFO, ""); + throw InvalidMetaInfoException(__LINE__, Q_FUNC_INFO, __FILE__); + } + + QVariant variant = originalVariant; + if (m_data->enumType) { + return variant; + } + + QVariant::Type typeId = variantTypeId(); + + if (typeId == QVariant::UserType && m_data->type == QLatin1String("QVariant")) { + return variant; + } else if (variant.type() == QVariant::List && variant.type() == QVariant::List) { + // TODO: check the contents of the list + return variant; + } else if (type() == "var" || type() == "variant") { + return variant; + } else if (type() == "alias") { + // TODO: The Qml compiler resolves the alias type. We probably should do the same. + return variant; + } else if (variant.convert(typeId)) { + return variant; + } else { + return QVariant(); + } +} + +} diff --git a/src/shared/qml/metatype/propertymetainfo.h b/src/shared/qml/metatype/propertymetainfo.h new file mode 100644 index 00000000000..d24b340b784 --- /dev/null +++ b/src/shared/qml/metatype/propertymetainfo.h @@ -0,0 +1,84 @@ +#ifndef PROPERTYMETAINFO_H +#define PROPERTYMETAINFO_H + +#include <qml/qml_global.h> + +#include <QString> +#include <QExplicitlySharedDataPointer> +#include <QVariant> + +namespace QKineticDesigner { + +class MetaInfo; +class NodeMetaInfo; + +namespace Internal { + +class MetaInfoPrivate; +class MetaInfoParser; +class PropertyMetaInfoData; + +} + +class QML_EXPORT PropertyMetaInfo +{ + friend class QKineticDesigner::Internal::MetaInfoPrivate; + friend class QKineticDesigner::Internal::MetaInfoParser; + friend class QKineticDesigner::MetaInfo; + friend class QKineticDesigner::NodeMetaInfo; +public: + PropertyMetaInfo(); + ~PropertyMetaInfo(); + + PropertyMetaInfo(const PropertyMetaInfo &other); + PropertyMetaInfo& operator=(const PropertyMetaInfo &other); + + bool isValid() const; + + QString name() const; + QString type() const; + int typeMajorVersion() const; + int typeMinorVersion() const; + + QVariant::Type variantTypeId() const; + + bool isReadable() const; + bool isWriteable() const; + bool isResettable() const; + bool isValueType() const; + bool isListProperty() const; + + bool isEnumType() const; + bool isFlagType() const; + + QVariant defaultValue(const NodeMetaInfo &nodeMetaInfo) const; + bool isVisibleToPropertyEditor() const; + + QVariant castedValue(const QVariant &variant) const; + +private: + void setName(const QString &name); + void setType(const QString &type, int majorVersion, int minorVersion); + void setValid(bool isValid); + + void setReadable(bool isReadable); + void setWritable(bool isWritable); + void setResettable(bool isRessetable); + + void setEnumType(bool isEnumType); + void setFlagType(bool isFlagType); + + void setDefaultValue(const NodeMetaInfo &nodeMetaInfo, const QVariant &value); + void setIsVisibleToPropertyEditor(bool isVisible); + + bool hasDotSubProperties() const; + + +private: + QExplicitlySharedDataPointer<Internal::PropertyMetaInfoData> m_data; +}; + +} + + +#endif // PROPERTYMETAINFO_H diff --git a/src/shared/qml/metatype/qmltypesystem.cpp b/src/shared/qml/metatype/qmltypesystem.cpp new file mode 100644 index 00000000000..4186151eacc --- /dev/null +++ b/src/shared/qml/metatype/qmltypesystem.cpp @@ -0,0 +1,42 @@ +#include "QmlMetaTypeBackend.h" +#include "qmltypesystem.h" + +#ifdef BUILD_DECLARATIVE_BACKEND +# include "QtDeclarativeMetaTypeBackend.h" +#endif // BUILD_DECLARATIVE_BACKEND + +#include <QDebug> + +using namespace Qml; +using namespace Qml::MetaType; + +QmlTypeSystem::QmlTypeSystem() +{ +#ifdef BUILD_DECLARATIVE_BACKEND + backends.append(new Internal::QtDeclarativeMetaTypeBackend(this)); +#endif // BUILD_DECLARATIVE_BACKEND +} + +QmlTypeSystem::~QmlTypeSystem() +{ + qDeleteAll(backends); +} + +QList<QmlSymbol *> QmlTypeSystem::availableTypes(const QString &package, int majorVersion, int minorVersion) +{ + QList<QmlSymbol *> results; + + foreach (QmlMetaTypeBackend *backend, backends) + results.append(backend->availableTypes(package, majorVersion, minorVersion)); + + return results; +} + +QmlSymbol *QmlTypeSystem::resolve(const QString &typeName, const QList<PackageInfo> &packages) +{ + foreach (QmlMetaTypeBackend *backend, backends) + if (QmlSymbol *symbol = backend->resolve(typeName, packages)) + return symbol; + + return 0; +} diff --git a/src/shared/qml/metatype/qmltypesystem.h b/src/shared/qml/metatype/qmltypesystem.h new file mode 100644 index 00000000000..d12b1726867 --- /dev/null +++ b/src/shared/qml/metatype/qmltypesystem.h @@ -0,0 +1,34 @@ +#ifndef QMLTYPESYSTEM_H +#define QMLTYPESYSTEM_H + +#include <qml/qml_global.h> +#include <qml/qmlpackageinfo.h> +#include <qml/qmlsymbol.h> + +#include <QtCore/QList> +#include <QtCore/QObject> + +namespace Qml { +namespace MetaType { + +class QmlMetaTypeBackend; + +class QML_EXPORT QmlTypeSystem: public QObject +{ + Q_OBJECT + +public: + QmlTypeSystem(); + virtual ~QmlTypeSystem(); + + QList<QmlSymbol *> availableTypes(const QString &package, int majorVersion, int minorVersion); + QmlSymbol *resolve(const QString &typeName, const QList<PackageInfo> &packages); + +private: + QList<QmlMetaTypeBackend *> backends; +}; + +} // namespace MetaType +} // namespace Qml + +#endif // QMLTYPESYSTEM_H diff --git a/src/shared/qml/qml.pri b/src/shared/qml/qml.pri index 2fa88866729..caafdd10ab2 100644 --- a/src/shared/qml/qml.pri +++ b/src/shared/qml/qml.pri @@ -7,11 +7,37 @@ HEADERS += \ $$PWD/qml_global.h \ $$PWD/qmlidcollector.h \ $$PWD/qmldocument.h \ - $$PWD/qmlsymbol.h + $$PWD/qmlpackageinfo.h \ + $$PWD/qmlsymbol.h \ + $$PWD/metatype/QmlMetaTypeBackend.h \ + $$PWD/metatype/qmltypesystem.h SOURCES += \ $$PWD/qmlidcollector.cpp \ $$PWD/qmldocument.cpp \ - $$PWD/qmlsymbol.cpp + $$PWD/qmlsymbol.cpp \ + $$PWD/qmlpackageinfo.cpp \ + $$PWD/metatype/QmlMetaTypeBackend.cpp \ + $$PWD/metatype/qmltypesystem.cpp +contains(QT_CONFIG, declarative) { + QT += declarative + DEFINES += BUILD_DECLARATIVE_BACKEND + + HEADERS += \ + $$PWD/metatype/metainfo.h \ + $$PWD/metatype/nodemetainfo.h \ + $$PWD/metatype/propertymetainfo.h \ + $$PWD/metatype/QtDeclarativeMetaTypeBackend.h \ + $$PWD/metatype/invalidmetainfoexception.h \ + $$PWD/metatype/exception.h + + SOURCES += \ + $$PWD/metatype/metainfo.cpp \ + $$PWD/metatype/nodemetainfo.cpp \ + $$PWD/metatype/propertymetainfo.cpp \ + $$PWD/metatype/QtDeclarativeMetaTypeBackend.cpp \ + $$PWD/metatype/invalidmetainfoexception.cpp \ + $$PWD/metatype/exception.cpp +} diff --git a/src/shared/qml/qmldocument.cpp b/src/shared/qml/qmldocument.cpp index a71152119fd..06e11626730 100644 --- a/src/shared/qml/qmldocument.cpp +++ b/src/shared/qml/qmldocument.cpp @@ -35,6 +35,7 @@ #include "qmljsnodepool_p.h" #include "qmljsastfwd_p.h" +using namespace Qml; using namespace QmlEditor; using namespace QmlJS; @@ -115,7 +116,7 @@ bool QmlDocument::parse() _symbols.append(new QmlSymbolFromFile(_fileName, iter->member)); Internal::QmlIdCollector collect; - _ids = collect(this); + _ids = collect(*this); } return _parsedCorrectly; diff --git a/src/shared/qml/qmldocument.h b/src/shared/qml/qmldocument.h index 5797d7299e5..c45a3af09d6 100644 --- a/src/shared/qml/qmldocument.h +++ b/src/shared/qml/qmldocument.h @@ -46,7 +46,7 @@ class QML_EXPORT QmlDocument public: typedef QSharedPointer<QmlDocument> Ptr; typedef QList<QmlDocument::Ptr> PtrList; - typedef QMap<QString, QmlIdSymbol*> IdTable; + typedef QMap<QString, Qml::QmlIdSymbol*> IdTable; protected: QmlDocument(const QString &fileName); @@ -73,8 +73,8 @@ public: QString path() const { return _path; } QString componentName() const { return _componentName; } - QmlSymbolFromFile *findSymbol(QmlJS::AST::Node *node) const; - QmlSymbol::List symbols() const + Qml::QmlSymbolFromFile *findSymbol(QmlJS::AST::Node *node) const; + Qml::QmlSymbol::List symbols() const { return _symbols; } private: @@ -88,7 +88,7 @@ private: QString _source; bool _parsedCorrectly; IdTable _ids; - QmlSymbol::List _symbols; + Qml::QmlSymbol::List _symbols; }; class QML_EXPORT Snapshot: public QMap<QString, QmlDocument::Ptr> diff --git a/src/shared/qml/qmlidcollector.cpp b/src/shared/qml/qmlidcollector.cpp index a06ae2dde35..0b348c5d74e 100644 --- a/src/shared/qml/qmlidcollector.cpp +++ b/src/shared/qml/qmlidcollector.cpp @@ -6,16 +6,16 @@ using namespace QmlJS; using namespace QmlJS::AST; -using namespace QmlEditor; -using namespace QmlEditor::Internal; +using namespace Qml; +using namespace Qml::Internal; -QMap<QString, QmlIdSymbol*> QmlIdCollector::operator()(QmlDocument *doc) +QMap<QString, QmlIdSymbol*> QmlIdCollector::operator()(QmlEditor::QmlDocument &doc) { - _doc = doc; + _doc = &doc; _ids.clear(); _currentSymbol = 0; - Node::accept(doc->program(), this); + Node::accept(doc.program(), this); return _ids; } diff --git a/src/shared/qml/qmlidcollector.h b/src/shared/qml/qmlidcollector.h index 0e8c88df3b6..5a0a92fb44d 100644 --- a/src/shared/qml/qmlidcollector.h +++ b/src/shared/qml/qmlidcollector.h @@ -10,13 +10,13 @@ #include <qml/qmldocument.h> #include <qml/qmlsymbol.h> -namespace QmlEditor { +namespace Qml { namespace Internal { class QML_EXPORT QmlIdCollector: protected QmlJS::AST::Visitor { public: - QMap<QString, QmlIdSymbol*> operator()(QmlDocument *doc); + QMap<QString, Qml::QmlIdSymbol*> operator()(QmlEditor::QmlDocument &doc); protected: virtual bool visit(QmlJS::AST::UiArrayBinding *ast); @@ -25,16 +25,16 @@ protected: virtual bool visit(QmlJS::AST::UiScriptBinding *ast); private: - QmlSymbolFromFile *switchSymbol(QmlJS::AST::UiObjectMember *node); + Qml::QmlSymbolFromFile *switchSymbol(QmlJS::AST::UiObjectMember *node); void addId(const QString &id, QmlJS::AST::UiScriptBinding *ast); private: - QmlDocument *_doc; - QMap<QString, QmlIdSymbol*> _ids; - QmlSymbolFromFile *_currentSymbol; + QmlEditor::QmlDocument *_doc; + QMap<QString, Qml::QmlIdSymbol*> _ids; + Qml::QmlSymbolFromFile *_currentSymbol; }; } // namespace Internal -} // namespace QmlEditor +} // namespace Qml #endif // QMLIDCOLLECTOR_H diff --git a/src/shared/qml/qmlpackageinfo.cpp b/src/shared/qml/qmlpackageinfo.cpp new file mode 100644 index 00000000000..d9223877bc5 --- /dev/null +++ b/src/shared/qml/qmlpackageinfo.cpp @@ -0,0 +1,10 @@ +#include "qmlpackageinfo.h" + +using namespace Qml; + +PackageInfo::PackageInfo(const QString &name, int majorVersion, int minorVersion): + m_name(name), + m_majorVersion(majorVersion), + m_minorVersion(minorVersion) +{ +} diff --git a/src/shared/qml/qmlpackageinfo.h b/src/shared/qml/qmlpackageinfo.h new file mode 100644 index 00000000000..770606904b6 --- /dev/null +++ b/src/shared/qml/qmlpackageinfo.h @@ -0,0 +1,32 @@ +#ifndef PACKAGEINFO_H +#define PACKAGEINFO_H + +#include <qml/qml_global.h> + +#include <QtCore/QString> + +namespace Qml { + +class QML_EXPORT PackageInfo +{ +public: + PackageInfo(const QString &name, int majorVersion, int minorVersion); + + QString name() const + { return m_name; } + + int majorVersion() const + { return m_majorVersion; } + + int minorVersion() const + { return m_minorVersion; } + +private: + QString m_name; + int m_majorVersion; + int m_minorVersion; +}; + +} // namespace Qml + +#endif // PACKAGEINFO_H diff --git a/src/shared/qml/qmlsymbol.cpp b/src/shared/qml/qmlsymbol.cpp index afd0f7e719d..ad8491685b5 100644 --- a/src/shared/qml/qmlsymbol.cpp +++ b/src/shared/qml/qmlsymbol.cpp @@ -2,13 +2,12 @@ #include "qmljsengine_p.h" #include "qmlsymbol.h" -using namespace QmlEditor; +using namespace Qml; using namespace QmlJS; using namespace QmlJS::AST; QmlSymbol::~QmlSymbol() { - qDeleteAll(_members); } bool QmlSymbol::isBuildInSymbol() @@ -35,15 +34,17 @@ QmlIdSymbol *QmlSymbol::asIdSymbol() QmlPropertyDefinitionSymbol *QmlSymbol::asPropertyDefinitionSymbol() { return 0; } -const QmlSymbol::List QmlSymbol::members() -{ return _members; } - QmlBuildInSymbol::~QmlBuildInSymbol() {} QmlBuildInSymbol *QmlBuildInSymbol::asBuildInSymbol() { return this; } +QmlSymbolWithMembers::~QmlSymbolWithMembers() +{ qDeleteAll(_members); } + +const QmlSymbol::List QmlSymbolWithMembers::members() +{ return _members; } QmlSymbolFromFile::QmlSymbolFromFile(const QString &fileName, QmlJS::AST::UiObjectMember *node): _fileName(fileName), diff --git a/src/shared/qml/qmlsymbol.h b/src/shared/qml/qmlsymbol.h index 159badf0bbb..33561daa069 100644 --- a/src/shared/qml/qmlsymbol.h +++ b/src/shared/qml/qmlsymbol.h @@ -1,24 +1,24 @@ #ifndef QMLSYMBOL_H #define QMLSYMBOL_H -#include <QList> -#include <QString> - #include <qml/parser/qmljsastfwd_p.h> #include <qml/qml_global.h> -namespace QmlEditor { +#include <QList> +#include <QString> + +namespace Qml { class QML_EXPORT QmlSymbol { public: - typedef QList<QmlSymbol*> List; + typedef QList<QmlSymbol *> List; public: - virtual ~QmlSymbol(); + virtual ~QmlSymbol() = 0; virtual const QString name() const = 0; - virtual const List members(); + virtual const List members() = 0; bool isBuildInSymbol(); bool isSymbolFromFile(); @@ -29,30 +29,41 @@ public: virtual class QmlSymbolFromFile *asSymbolFromFile(); virtual class QmlIdSymbol *asIdSymbol(); virtual class QmlPropertyDefinitionSymbol *asPropertyDefinitionSymbol(); - -protected: - List _members; }; class QML_EXPORT QmlBuildInSymbol: public QmlSymbol { public: - QmlBuildInSymbol(const QString &name): _name(name) {} - virtual ~QmlBuildInSymbol(); + virtual ~QmlBuildInSymbol() = 0; virtual QmlBuildInSymbol *asBuildInSymbol(); - virtual const QString name() const - { return _name; } + virtual QmlBuildInSymbol *type() const = 0; + virtual List members(bool includeBaseClassMembers) = 0; +}; - void addMember(QmlBuildInSymbol *symbol) - { _members.append(symbol); } +class QML_EXPORT QmlPrimitiveSymbol: public QmlBuildInSymbol +{ +public: + virtual ~QmlPrimitiveSymbol() = 0; -private: - QString _name; + virtual bool isString() const = 0; + virtual bool isNumber() const = 0; + virtual bool isObject() const = 0; +}; + +class QML_EXPORT QmlSymbolWithMembers: public QmlSymbol +{ +public: + virtual ~QmlSymbolWithMembers() = 0; + + virtual const List members(); + +protected: + List _members; }; -class QML_EXPORT QmlSymbolFromFile: public QmlSymbol +class QML_EXPORT QmlSymbolFromFile: public QmlSymbolWithMembers { public: QmlSymbolFromFile(const QString &fileName, QmlJS::AST::UiObjectMember *node); @@ -125,6 +136,6 @@ private: QmlJS::AST::UiPublicMember *propertyNode() const; }; -} // namespace QmlEditor +} // namespace Qml #endif // QMLSYMBOL_H -- GitLab