diff --git a/share/qtcreator/qmlicons/Qt/16x16/BorderImage.png b/share/qtcreator/qmlicons/Qt/16x16/BorderImage.png new file mode 100644 index 0000000000000000000000000000000000000000..ef21dd9710709b536736c433368d595b2fe298fc Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/BorderImage.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Flickable.png b/share/qtcreator/qmlicons/Qt/16x16/Flickable.png new file mode 100644 index 0000000000000000000000000000000000000000..963a7afea358303873397bfd01b9088d6b990287 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Flickable.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Flipable.png b/share/qtcreator/qmlicons/Qt/16x16/Flipable.png new file mode 100644 index 0000000000000000000000000000000000000000..354f5bd91c30220917b3863200ee6c874c4bd015 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Flipable.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/FocusScope.png b/share/qtcreator/qmlicons/Qt/16x16/FocusScope.png new file mode 100644 index 0000000000000000000000000000000000000000..3a65e43525e391b936ca47531dc5dd382ebe8870 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/FocusScope.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/GridView.png b/share/qtcreator/qmlicons/Qt/16x16/GridView.png new file mode 100644 index 0000000000000000000000000000000000000000..011392dc557b73596cde95264b91dff8e2624bfc Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/GridView.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Image.png b/share/qtcreator/qmlicons/Qt/16x16/Image.png new file mode 100644 index 0000000000000000000000000000000000000000..fc4c7eccc1fc5d76ea874b2adbe4fb501df8d9b9 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Image.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Item.png b/share/qtcreator/qmlicons/Qt/16x16/Item.png new file mode 100644 index 0000000000000000000000000000000000000000..6d1e0f214d5076df6648f36330e8e16dc7460ac6 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Item.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/ListView.png b/share/qtcreator/qmlicons/Qt/16x16/ListView.png new file mode 100644 index 0000000000000000000000000000000000000000..b2e62ca068f82f81e9f09e778f63f8387f7d2776 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/ListView.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/MouseArea.png b/share/qtcreator/qmlicons/Qt/16x16/MouseArea.png new file mode 100644 index 0000000000000000000000000000000000000000..b28576ac8772a6ae778ee1ac543be04c1ab5f665 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/MouseArea.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/PathView.png b/share/qtcreator/qmlicons/Qt/16x16/PathView.png new file mode 100644 index 0000000000000000000000000000000000000000..23c3a2f5dae22b63da65a3f127c8481dd3377d0e Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/PathView.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Rectangle.png b/share/qtcreator/qmlicons/Qt/16x16/Rectangle.png new file mode 100644 index 0000000000000000000000000000000000000000..f6c33cacd7b16f55cce98ba1cf22443762f380ad Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Rectangle.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/State.png b/share/qtcreator/qmlicons/Qt/16x16/State.png new file mode 100644 index 0000000000000000000000000000000000000000..d400b013aeb020c7a656826ad25c2afd827f9a48 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/State.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Text.png b/share/qtcreator/qmlicons/Qt/16x16/Text.png new file mode 100644 index 0000000000000000000000000000000000000000..a49a39c33c6a882f898ead68dc81122f2d0ddf05 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Text.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/TextEdit.png b/share/qtcreator/qmlicons/Qt/16x16/TextEdit.png new file mode 100644 index 0000000000000000000000000000000000000000..4f41cd9bc5269d0f4eb348e8a0fc25ff44ffbcc9 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/TextEdit.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/TextInput.png b/share/qtcreator/qmlicons/Qt/16x16/TextInput.png new file mode 100644 index 0000000000000000000000000000000000000000..394ac907cf686515d102e0b366fec7665deb920b Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/TextInput.png differ diff --git a/share/qtcreator/qmlicons/Qt/16x16/Transition.png b/share/qtcreator/qmlicons/Qt/16x16/Transition.png new file mode 100644 index 0000000000000000000000000000000000000000..86f591ff7bdc287872b1170e1d5c54f3fa639115 Binary files /dev/null and b/share/qtcreator/qmlicons/Qt/16x16/Transition.png differ diff --git a/share/qtcreator/qmlicons/QtWebkit/16x16/WebView.png b/share/qtcreator/qmlicons/QtWebkit/16x16/WebView.png new file mode 100644 index 0000000000000000000000000000000000000000..3f61ad0b1c0740c7c671686cffc3ddaf8c6a232f Binary files /dev/null and b/share/qtcreator/qmlicons/QtWebkit/16x16/WebView.png differ diff --git a/src/libs/qmljs/qmljsicons.cpp b/src/libs/qmljs/qmljsicons.cpp index 710e619847f8431f19a0a44c0486518a1b6a0b6b..f423c124466f51a65dd00f275abbe132743fc446 100644 --- a/src/libs/qmljs/qmljsicons.cpp +++ b/src/libs/qmljs/qmljsicons.cpp @@ -28,17 +28,29 @@ **************************************************************************/ #include "qmljsicons.h" +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QHash> +#include <QtCore/QPair> using namespace QmlJS; using namespace QmlJS::AST; +enum { + debug = false +}; + namespace QmlJS { +Icons *Icons::m_instance = 0; + class IconsPrivate { public: QIcon elementIcon; QIcon propertyIcon; + QHash<QPair<QString,QString>,QIcon> iconHash; + QString resourcePath; }; } // namespace QmlJS @@ -52,9 +64,55 @@ Icons::Icons() Icons::~Icons() { + m_instance = 0; delete m_d; } +Icons *Icons::instance() +{ + if (!m_instance) + m_instance = new Icons(); + return m_instance; +} + +void Icons::setIconFilesPath(const QString &iconPath) +{ + if (iconPath == m_d->resourcePath) + return; + + m_d->resourcePath = iconPath; + + if (debug) + qDebug() << "QmlJSIcons -" << "parsing" << iconPath; + QDir topDir(iconPath); + foreach (const QFileInfo &subDirInfo, topDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (debug) + qDebug() << "QmlJSIcons - parsing" << subDirInfo.absoluteFilePath(); + const QString packageName = subDirInfo.fileName(); + QDir subDir(subDirInfo.absoluteFilePath() + QLatin1String("/16x16")); + foreach (const QFileInfo &iconFile, subDir.entryInfoList(QDir::Files)) { + QIcon icon(iconFile.absoluteFilePath()); + if (icon.isNull()) { + if (debug) + qDebug() << "QmlJSIcons - skipping" << iconFile.absoluteFilePath(); + continue; + } + if (debug) + qDebug() << "QmlJSIcons - adding" << packageName << iconFile.baseName() << "icon to database"; + QPair<QString,QString> element(packageName, iconFile.baseName()); + m_d->iconHash.insert(element, icon); + } + } +} + +QIcon Icons::icon(const QString &packageName, const QString typeName) const +{ + QPair<QString,QString> element(packageName, typeName); + if (debug) + qDebug() << "QmlJSIcons - icon for" << packageName << typeName << "requested" << m_d->iconHash.contains(element); + return m_d->iconHash.value(element); +} + QIcon Icons::icon(Node *node) const { if (dynamic_cast<AST::UiObjectDefinition*>(node)) { diff --git a/src/libs/qmljs/qmljsicons.h b/src/libs/qmljs/qmljsicons.h index 783e5ac4d6d00b600a8d834966274445e365296c..47cec83ef16e8cf2939353c3718888dbd81af749 100644 --- a/src/libs/qmljs/qmljsicons.h +++ b/src/libs/qmljs/qmljsicons.h @@ -41,14 +41,21 @@ class IconsPrivate; class QMLJS_EXPORT Icons { public: - Icons(); ~Icons(); + static Icons *instance(); + + void setIconFilesPath(const QString &iconPath); + + QIcon icon(const QString &packageName, const QString typeName) const; QIcon icon(AST::Node *node) const; QIcon objectDefinitionIcon() const; QIcon scriptBindingIcon() const; +private: + Icons(); + static Icons *m_instance; IconsPrivate *m_d; }; diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index b7144f1f30d940d91d393afd260bd20d54cea703..7528acd51b2a84d434aacc5bb2cb9edde19e64db 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -850,7 +850,7 @@ void QmlJSTextEditor::updateOutlineNow() return; } - m_outlineModel->update(document); + m_outlineModel->update(document, snapshot); updateOutlineIndexNow(); } diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp index d55d5b31dcfa9f5b59c1edf0e404791f5756fac4..944d34ae4cee24504091bdda71a42a35e10d4030 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.cpp +++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp @@ -39,6 +39,7 @@ #include "qmljsoutline.h" #include "qmljspreviewrunner.h" #include "qmljsquickfix.h" +#include "qmljs/qmljsicons.h" #include <qmldesigner/qmldesignerconstants.h> @@ -186,6 +187,13 @@ void QmlJSEditorPlugin::extensionsInitialized() { } +ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown() +{ + delete QmlJS::Icons::instance(); // delete object held by singleton + + return IPlugin::aboutToShutdown(); +} + void QmlJSEditorPlugin::openPreview() { Core::EditorManager *em = Core::EditorManager::instance(); diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h index af6e5f9280cfa75258bcbcdbb320fdf31855b93a..9fa7ba4a97e916bd6d8290d6517a5b784f0a699c 100644 --- a/src/plugins/qmljseditor/qmljseditorplugin.h +++ b/src/plugins/qmljseditor/qmljseditorplugin.h @@ -77,6 +77,7 @@ public: // IPlugin bool initialize(const QStringList &arguments, QString *errorMessage = 0); void extensionsInitialized(); + ShutdownFlag aboutToShutdown(); static QmlJSEditorPlugin *instance() { return m_instance; } diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp index bad1f2b7b3cc6426383c48b970225ecd52532a89..0a56622ba11d8a9d0cdf9a27cf984f15b880e56c 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.cpp +++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp @@ -1,7 +1,11 @@ #include "qmloutlinemodel.h" #include <qmljs/parser/qmljsastvisitor_p.h> +#include <qmljs/qmljsinterpreter.h> +#include <qmljs/qmljslookupcontext.h> +#include <coreplugin/icore.h> #include <QtCore/QDebug> +#include <QtCore/QTime> #include <typeinfo> using namespace QmlJS; @@ -11,7 +15,8 @@ enum { debug = false }; -namespace { +namespace QmlJSEditor { +namespace Internal { class QmlOutlineModelSync : protected AST::Visitor { @@ -22,14 +27,23 @@ public: { } - void operator()(Document::Ptr doc) + void operator()(Document::Ptr doc, const Snapshot &snapshot) { m_nodeToIndex.clear(); + // Set up lookup context once to do the element type lookup + // + // We're simplifying here by using the root context everywhere + // (empty node list). However, creating the LookupContext is quite expensive (about 3ms), + // and there is AFAIK no way to introduce new type names in a sub-context. + m_context = LookupContext::create(doc, snapshot, QList<AST::Node*>()); + if (debug) qDebug() << "QmlOutlineModel ------"; if (doc && doc->ast()) doc->ast()->accept(this); + + m_context.clear(); } private: @@ -64,7 +78,7 @@ private: } - + typedef QPair<QString,QString> ElementType; bool visit(AST::UiObjectDefinition *objDef) { if (!validElement(objDef)) { @@ -78,8 +92,14 @@ private: + objDef->lastSourceLocation().length; const QString typeName = asString(objDef->qualifiedTypeNameId); - const QString id = getId(objDef); - QModelIndex index = m_model->enterElement(typeName, id, location); + + if (!m_typeToIcon.contains(typeName)) { + m_typeToIcon.insert(typeName, getIcon(objDef)); + } + const QIcon icon = m_typeToIcon.value(typeName); + QString id = getId(objDef); + + QModelIndex index = m_model->enterElement(typeName, id, icon, location); m_nodeToIndex.insert(objDef, index); return true; } @@ -112,10 +132,33 @@ private: } bool validElement(AST::UiObjectDefinition *objDef) { - // For 'Rectangle { id }', id is parsed as UiObjectDefinition ... Filter this out.ctan + // For 'Rectangle { id }', id is parsed as UiObjectDefinition ... Filter this out. return objDef->qualifiedTypeNameId->name->asString().at(0).isUpper(); } + QIcon getIcon(AST::UiObjectDefinition *objDef) { + const QmlJS::Interpreter::Value *value = m_context->evaluate(objDef->qualifiedTypeNameId); + + if (const Interpreter::ObjectValue *objectValue = value->asObjectValue()) { + do { + QString module; + QString typeName; + if (const Interpreter::QmlObjectValue *qmlObjectValue = + dynamic_cast<const Interpreter::QmlObjectValue*>(objectValue)) { + module = qmlObjectValue->packageName(); + } + typeName = objectValue->className(); + + QIcon icon = m_model->m_icons->icon(module, typeName); + if (! icon.isNull()) + return icon; + + objectValue = objectValue->prototype(m_context->context()); + } while (objectValue); + } + return QIcon(); + } + QString getId(AST::UiObjectDefinition *objDef) { QString id; for (AST::UiObjectMemberList *it = objDef->initializer->members; it; it = it->next) { @@ -137,19 +180,19 @@ private: QmlOutlineModel *m_model; + LookupContext::Ptr m_context; + QHash<AST::Node*, QModelIndex> m_nodeToIndex; + QHash<QString, QIcon> m_typeToIcon; int indent; }; - -} // namespace - -namespace QmlJSEditor { -namespace Internal { - QmlOutlineModel::QmlOutlineModel(QObject *parent) : QStandardItemModel(parent) { + m_icons = Icons::instance(); + const QString resourcePath = Core::ICore::instance()->resourcePath(); + QmlJS::Icons::instance()->setIconFilesPath(resourcePath + "/qmlicons"); } QmlJS::Document::Ptr QmlOutlineModel::document() const @@ -157,7 +200,7 @@ QmlJS::Document::Ptr QmlOutlineModel::document() const return m_document; } -void QmlOutlineModel::update(QmlJS::Document::Ptr doc) +void QmlOutlineModel::update(QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot) { m_document = doc; @@ -166,12 +209,12 @@ void QmlOutlineModel::update(QmlJS::Document::Ptr doc) m_currentItem = invisibleRootItem(); QmlOutlineModelSync syncModel(this); - syncModel(doc); + syncModel(doc, snapshot); emit updated(); } -QModelIndex QmlOutlineModel::enterElement(const QString &type, const QString &id, const AST::SourceLocation &sourceLocation) +QModelIndex QmlOutlineModel::enterElement(const QString &type, const QString &id, const QIcon &icon, const AST::SourceLocation &sourceLocation) { QStandardItem *item = enterNode(sourceLocation); if (!id.isEmpty()) { @@ -179,8 +222,8 @@ QModelIndex QmlOutlineModel::enterElement(const QString &type, const QString &id } else { item->setText(type); } + item->setIcon(icon); item->setToolTip(type); - item->setIcon(m_icons.objectDefinitionIcon()); return item->index(); } @@ -193,7 +236,7 @@ QModelIndex QmlOutlineModel::enterProperty(const QString &name, const AST::Sourc { QStandardItem *item = enterNode(sourceLocation); item->setText(name); - item->setIcon(m_icons.scriptBindingIcon()); + item->setIcon(m_icons->scriptBindingIcon()); return item->index(); } diff --git a/src/plugins/qmljseditor/qmloutlinemodel.h b/src/plugins/qmljseditor/qmloutlinemodel.h index f2e914a36c79e982bf0dda8210a1ec36776887f4..dbc3e7f217b9d5d45c382bfaf91c1f5eb93e7725 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.h +++ b/src/plugins/qmljseditor/qmloutlinemodel.h @@ -20,9 +20,9 @@ public: QmlOutlineModel(QObject *parent = 0); QmlJS::Document::Ptr document() const; - void update(QmlJS::Document::Ptr doc); + void update(QmlJS::Document::Ptr doc, const QmlJS::Snapshot &snapshot); - QModelIndex enterElement(const QString &typeName, const QString &id, const QmlJS::AST::SourceLocation &location); + QModelIndex enterElement(const QString &typeName, const QString &id, const QIcon &icon, const QmlJS::AST::SourceLocation &location); void leaveElement(); QModelIndex enterProperty(const QString &name, const QmlJS::AST::SourceLocation &location); @@ -40,7 +40,9 @@ private: QmlJS::Document::Ptr m_document; QList<int> m_treePos; QStandardItem *m_currentItem; - QmlJS::Icons m_icons; + QmlJS::Icons *m_icons; + + friend class QmlOutlineModelSync; }; } // namespace Internal