diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro index f92ba23c6cbb619b90d035c4226eeacf3b225375..e35f6e40e303b73b76e39c677b02be38b41b89f0 100644 --- a/src/plugins/qmljseditor/qmljseditor.pro +++ b/src/plugins/qmljseditor/qmljseditor.pro @@ -24,7 +24,8 @@ HEADERS += \ qmljsquickfix.h \ qmljsrefactoringchanges.h \ qmljscomponentfromobjectdef.h \ - qmljsoutline.h + qmljsoutline.h \ + qmloutlinemodel.h SOURCES += \ qmljscodecompletion.cpp \ @@ -41,7 +42,8 @@ SOURCES += \ qmljsquickfix.cpp \ qmljsrefactoringchanges.cpp \ qmljscomponentfromobjectdef.cpp \ - qmljsoutline.cpp + qmljsoutline.cpp \ + qmloutlinemodel.cpp RESOURCES += qmljseditor.qrc OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml diff --git a/src/plugins/qmljseditor/qmljsoutline.cpp b/src/plugins/qmljseditor/qmljsoutline.cpp index 251121008633d3b4db909e1c38a94b6fb50705aa..a95c0842c90dc48277cb0cf2acb319d0d34335d5 100644 --- a/src/plugins/qmljseditor/qmljsoutline.cpp +++ b/src/plugins/qmljseditor/qmljsoutline.cpp @@ -1,15 +1,9 @@ #include "qmljsoutline.h" +#include "qmloutlinemodel.h" -#include <coreplugin/icore.h> -#include <extensionsystem/pluginmanager.h> -#include <qmljs/parser/qmljsast_p.h> -#include <qmljs/qmljsmodelmanagerinterface.h> - -#include <QtCore/QDebug> +#include <coreplugin/ifile.h> #include <QtGui/QVBoxLayout> -#include <typeinfo> - using namespace QmlJS; enum { @@ -19,11 +13,6 @@ enum { namespace QmlJSEditor { namespace Internal { -QmlOutlineModel::QmlOutlineModel(QObject *parent) : - QStandardItemModel(parent) -{ -} - QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) : QTreeView(parent) { @@ -38,203 +27,6 @@ QmlJSOutlineTreeView::QmlJSOutlineTreeView(QWidget *parent) : setExpandsOnDoubleClick(false); } -void QmlOutlineModel::startSync() -{ - m_treePos.clear(); - m_treePos.append(0); - m_currentItem = invisibleRootItem(); -} - -QModelIndex QmlOutlineModel::enterElement(const QString &type, const AST::SourceLocation &sourceLocation) -{ - QStandardItem *item = enterNode(sourceLocation); - item->setText(type); - item->setIcon(m_icons.objectDefinitionIcon()); - return item->index(); -} - -void QmlOutlineModel::leaveElement() -{ - leaveNode(); -} - -QModelIndex QmlOutlineModel::enterProperty(const QString &name, const AST::SourceLocation &sourceLocation) -{ - QStandardItem *item = enterNode(sourceLocation); - item->setText(name); - item->setIcon(m_icons.scriptBindingIcon()); - return item->index(); -} - -void QmlOutlineModel::leaveProperty() -{ - leaveNode(); -} - -QStandardItem *QmlOutlineModel::enterNode(const QmlJS::AST::SourceLocation &location) -{ - int siblingIndex = m_treePos.last(); - if (siblingIndex == 0) { - // first child - if (!m_currentItem->hasChildren()) { - QStandardItem *parentItem = m_currentItem; - m_currentItem = new QStandardItem; - m_currentItem->setEditable(false); - parentItem->appendRow(m_currentItem); - if (debug) - qDebug() << "QmlOutlineModel - Adding" << "element to" << parentItem->text(); - } else { - m_currentItem = m_currentItem->child(0); - } - } else { - // sibling - if (m_currentItem->rowCount() <= siblingIndex) { - // attach - QStandardItem *oldItem = m_currentItem; - m_currentItem = new QStandardItem; - m_currentItem->setEditable(false); - oldItem->appendRow(m_currentItem); - if (debug) - qDebug() << "QmlOutlineModel - Adding" << "element to" << oldItem->text(); - } else { - m_currentItem = m_currentItem->child(siblingIndex); - } - } - - m_treePos.append(0); - m_currentItem->setData(QVariant::fromValue(location), SourceLocationRole); - - return m_currentItem; -} - -void QmlOutlineModel::leaveNode() -{ - int lastIndex = m_treePos.takeLast(); - - - if (lastIndex > 0) { - // element has children - if (lastIndex < m_currentItem->rowCount()) { - if (debug) - qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << lastIndex << m_currentItem->rowCount() - lastIndex; - m_currentItem->removeRows(lastIndex, m_currentItem->rowCount() - lastIndex); - } - m_currentItem = parentItem(); - } else { - if (m_currentItem->hasChildren()) { - if (debug) - qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << 0 << m_currentItem->rowCount(); - m_currentItem->removeRows(0, m_currentItem->rowCount()); - } - m_currentItem = parentItem(); - } - - - m_treePos.last()++; -} - -QStandardItem *QmlOutlineModel::parentItem() -{ - QStandardItem *parent = m_currentItem->parent(); - if (!parent) - parent = invisibleRootItem(); - return parent; -} - -class QmlOutlineModelSync : protected AST::Visitor -{ -public: - QmlOutlineModelSync(QmlOutlineModel *model) : - m_model(model), - indent(0) - { - } - - void operator()(Document::Ptr doc) - { - m_nodeToIndex.clear(); - - if (debug) - qDebug() << "QmlOutlineModel ------"; - m_model->startSync(); - if (doc && doc->ast()) - doc->ast()->accept(this); - } - -private: - bool preVisit(AST::Node *node) - { - if (!node) - return false; - if (debug) - qDebug() << "QmlOutlineModel -" << QByteArray(indent++, '-').constData() << node << typeid(*node).name(); - return true; - } - - void postVisit(AST::Node *) - { - indent--; - } - - QString asString(AST::UiQualifiedId *id) - { - QString text; - for (; id; id = id->next) { - if (id->name) - text += id->name->asString(); - else - text += QLatin1Char('?'); - - if (id->next) - text += QLatin1Char('.'); - } - - return text; - } - - bool visit(AST::UiObjectDefinition *objDef) - { - AST::SourceLocation location; - location.offset = objDef->firstSourceLocation().offset; - location.length = objDef->lastSourceLocation().offset - - objDef->firstSourceLocation().offset - + objDef->lastSourceLocation().length; - - QModelIndex index = m_model->enterElement(asString(objDef->qualifiedTypeNameId), location); - m_nodeToIndex.insert(objDef, index); - return true; - } - - void endVisit(AST::UiObjectDefinition * /*objDefinition*/) - { - m_model->leaveElement(); - } - - bool visit(AST::UiScriptBinding *scriptBinding) - { - AST::SourceLocation location; - location.offset = scriptBinding->firstSourceLocation().offset; - location.length = scriptBinding->lastSourceLocation().offset - - scriptBinding->firstSourceLocation().offset - + scriptBinding->lastSourceLocation().length; - - QModelIndex index = m_model->enterProperty(asString(scriptBinding->qualifiedId), location); - m_nodeToIndex.insert(scriptBinding, index); - - return true; - } - - void endVisit(AST::UiScriptBinding * /*scriptBinding*/) - { - m_model->leaveProperty(); - } - - QmlOutlineModel *m_model; - QHash<AST::Node*, QModelIndex> m_nodeToIndex; - int indent; -}; - - QmlJSOutlineWidget::QmlJSOutlineWidget(QWidget *parent) : TextEditor::IOutlineWidget(parent), m_treeView(new QmlJSOutlineTreeView()), @@ -295,8 +87,7 @@ void QmlJSOutlineWidget::updateOutline(const QmlJSEditor::Internal::SemanticInfo // got a correctly parsed (or recovered) file. if (QmlOutlineModel *qmlModel = qobject_cast<QmlOutlineModel*>(m_model)) { - QmlOutlineModelSync syncModel(qmlModel); - syncModel(doc); + qmlModel->update(doc); } } else { // TODO: Maybe disable view? diff --git a/src/plugins/qmljseditor/qmljsoutline.h b/src/plugins/qmljseditor/qmljsoutline.h index 1571069afb12a3f78e32561dc3c7c52d42a29561..14441eff865f686dd8877759a287da42a51af5c4 100644 --- a/src/plugins/qmljseditor/qmljsoutline.h +++ b/src/plugins/qmljseditor/qmljsoutline.h @@ -3,16 +3,9 @@ #include "qmljseditor.h" -#include <coreplugin/editormanager/editormanager.h> -#include <coreplugin/inavigationwidgetfactory.h> #include <texteditor/ioutlinewidget.h> -#include <qmljs/parser/qmljsastvisitor_p.h> -#include <qmljs/qmljsdocument.h> -#include <qmljs/qmljsicons.h> -#include <QtGui/QStandardItemModel> #include <QtGui/QTreeView> -#include <QtGui/QWidget> namespace Core { class IEditor; @@ -25,35 +18,6 @@ class Editor; namespace QmlJSEditor { namespace Internal { -class QmlOutlineModel : public QStandardItemModel -{ - Q_OBJECT -public: - enum CustomRoles { - SourceLocationRole = Qt::UserRole + 1 - }; - - QmlOutlineModel(QObject *parent = 0); - - void startSync(); - - QModelIndex enterElement(const QString &typeName, const QmlJS::AST::SourceLocation &location); - void leaveElement(); - - QModelIndex enterProperty(const QString &name, const QmlJS::AST::SourceLocation &location); - void leaveProperty(); - -private: - QStandardItem *enterNode(const QmlJS::AST::SourceLocation &location); - void leaveNode(); - - QStandardItem *parentItem(); - - QList<int> m_treePos; - QStandardItem *m_currentItem; - QmlJS::Icons m_icons; -}; - class QmlJSOutlineTreeView : public QTreeView { Q_OBJECT @@ -61,7 +25,6 @@ public: QmlJSOutlineTreeView(QWidget *parent = 0); }; - class QmlJSOutlineWidget : public TextEditor::IOutlineWidget { Q_OBJECT @@ -103,6 +66,4 @@ public: } // namespace Internal } // namespace QmlJSEditor -Q_DECLARE_METATYPE(QmlJS::AST::SourceLocation); - #endif // QMLJSOUTLINE_H diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e0d7129640a83a054e2614b7a3ad2b917ff718a0 --- /dev/null +++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp @@ -0,0 +1,226 @@ +#include "qmloutlinemodel.h" +#include <qmljs/parser/qmljsastvisitor_p.h> + +#include <QtCore/QDebug> +#include <typeinfo> + +using namespace QmlJS; +using namespace QmlJSEditor::Internal; + +enum { + debug = false +}; + +namespace { + +class QmlOutlineModelSync : protected AST::Visitor +{ +public: + QmlOutlineModelSync(QmlOutlineModel *model) : + m_model(model), + indent(0) + { + } + + void operator()(Document::Ptr doc) + { + m_nodeToIndex.clear(); + + if (debug) + qDebug() << "QmlOutlineModel ------"; + if (doc && doc->ast()) + doc->ast()->accept(this); + } + +private: + bool preVisit(AST::Node *node) + { + if (!node) + return false; + if (debug) + qDebug() << "QmlOutlineModel -" << QByteArray(indent++, '-').constData() << node << typeid(*node).name(); + return true; + } + + void postVisit(AST::Node *) + { + indent--; + } + + QString asString(AST::UiQualifiedId *id) + { + QString text; + for (; id; id = id->next) { + if (id->name) + text += id->name->asString(); + else + text += QLatin1Char('?'); + + if (id->next) + text += QLatin1Char('.'); + } + + return text; + } + + bool visit(AST::UiObjectDefinition *objDef) + { + AST::SourceLocation location; + location.offset = objDef->firstSourceLocation().offset; + location.length = objDef->lastSourceLocation().offset + - objDef->firstSourceLocation().offset + + objDef->lastSourceLocation().length; + + QModelIndex index = m_model->enterElement(asString(objDef->qualifiedTypeNameId), location); + m_nodeToIndex.insert(objDef, index); + return true; + } + + void endVisit(AST::UiObjectDefinition * /*objDefinition*/) + { + m_model->leaveElement(); + } + + bool visit(AST::UiScriptBinding *scriptBinding) + { + AST::SourceLocation location; + location.offset = scriptBinding->firstSourceLocation().offset; + location.length = scriptBinding->lastSourceLocation().offset + - scriptBinding->firstSourceLocation().offset + + scriptBinding->lastSourceLocation().length; + + QModelIndex index = m_model->enterProperty(asString(scriptBinding->qualifiedId), location); + m_nodeToIndex.insert(scriptBinding, index); + + return true; + } + + void endVisit(AST::UiScriptBinding * /*scriptBinding*/) + { + m_model->leaveProperty(); + } + + QmlOutlineModel *m_model; + QHash<AST::Node*, QModelIndex> m_nodeToIndex; + int indent; +}; + + +} // namespace + +namespace QmlJSEditor { +namespace Internal { + +QmlOutlineModel::QmlOutlineModel(QObject *parent) : + QStandardItemModel(parent) +{ +} + +void QmlOutlineModel::update(QmlJS::Document::Ptr doc) +{ + m_treePos.clear(); + m_treePos.append(0); + m_currentItem = invisibleRootItem(); + + QmlOutlineModelSync syncModel(this); + syncModel(doc); +} + +QModelIndex QmlOutlineModel::enterElement(const QString &type, const AST::SourceLocation &sourceLocation) +{ + QStandardItem *item = enterNode(sourceLocation); + item->setText(type); + item->setIcon(m_icons.objectDefinitionIcon()); + return item->index(); +} + +void QmlOutlineModel::leaveElement() +{ + leaveNode(); +} + +QModelIndex QmlOutlineModel::enterProperty(const QString &name, const AST::SourceLocation &sourceLocation) +{ + QStandardItem *item = enterNode(sourceLocation); + item->setText(name); + item->setIcon(m_icons.scriptBindingIcon()); + return item->index(); +} + +void QmlOutlineModel::leaveProperty() +{ + leaveNode(); +} + +QStandardItem *QmlOutlineModel::enterNode(const QmlJS::AST::SourceLocation &location) +{ + int siblingIndex = m_treePos.last(); + if (siblingIndex == 0) { + // first child + if (!m_currentItem->hasChildren()) { + QStandardItem *parentItem = m_currentItem; + m_currentItem = new QStandardItem; + m_currentItem->setEditable(false); + parentItem->appendRow(m_currentItem); + if (debug) + qDebug() << "QmlOutlineModel - Adding" << "element to" << parentItem->text(); + } else { + m_currentItem = m_currentItem->child(0); + } + } else { + // sibling + if (m_currentItem->rowCount() <= siblingIndex) { + // attach + QStandardItem *oldItem = m_currentItem; + m_currentItem = new QStandardItem; + m_currentItem->setEditable(false); + oldItem->appendRow(m_currentItem); + if (debug) + qDebug() << "QmlOutlineModel - Adding" << "element to" << oldItem->text(); + } else { + m_currentItem = m_currentItem->child(siblingIndex); + } + } + + m_treePos.append(0); + m_currentItem->setData(QVariant::fromValue(location), SourceLocationRole); + + return m_currentItem; +} + +void QmlOutlineModel::leaveNode() +{ + int lastIndex = m_treePos.takeLast(); + + + if (lastIndex > 0) { + // element has children + if (lastIndex < m_currentItem->rowCount()) { + if (debug) + qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << lastIndex << m_currentItem->rowCount() - lastIndex; + m_currentItem->removeRows(lastIndex, m_currentItem->rowCount() - lastIndex); + } + m_currentItem = parentItem(); + } else { + if (m_currentItem->hasChildren()) { + if (debug) + qDebug() << "QmlOutlineModel - removeRows from " << m_currentItem->text() << 0 << m_currentItem->rowCount(); + m_currentItem->removeRows(0, m_currentItem->rowCount()); + } + m_currentItem = parentItem(); + } + + + m_treePos.last()++; +} + +QStandardItem *QmlOutlineModel::parentItem() +{ + QStandardItem *parent = m_currentItem->parent(); + if (!parent) + parent = invisibleRootItem(); + return parent; +} + +} // namespace Internal +} // namespace QmlJSEditor diff --git a/src/plugins/qmljseditor/qmloutlinemodel.h b/src/plugins/qmljseditor/qmloutlinemodel.h new file mode 100644 index 0000000000000000000000000000000000000000..67c2628f0dce585ffcd4be3a0fc7c8845e3da289 --- /dev/null +++ b/src/plugins/qmljseditor/qmloutlinemodel.h @@ -0,0 +1,46 @@ +#ifndef QMLOUTLINEMODEL_H +#define QMLOUTLINEMODEL_H + +#include <qmljs/qmljsdocument.h> +#include <qmljs/qmljsicons.h> + +#include <QStandardItemModel> + +namespace QmlJSEditor { +namespace Internal { + +class QmlOutlineModel : public QStandardItemModel +{ + Q_OBJECT +public: + enum CustomRoles { + SourceLocationRole = Qt::UserRole + 1 + }; + + QmlOutlineModel(QObject *parent = 0); + + void update(QmlJS::Document::Ptr doc); + + QModelIndex enterElement(const QString &typeName, const QmlJS::AST::SourceLocation &location); + void leaveElement(); + + QModelIndex enterProperty(const QString &name, const QmlJS::AST::SourceLocation &location); + void leaveProperty(); + +private: + QStandardItem *enterNode(const QmlJS::AST::SourceLocation &location); + void leaveNode(); + + QStandardItem *parentItem(); + + QList<int> m_treePos; + QStandardItem *m_currentItem; + QmlJS::Icons m_icons; +}; + +} // namespace Internal +} // namespace QmlJSEditor + +Q_DECLARE_METATYPE(QmlJS::AST::SourceLocation); + +#endif // QMLOUTLINEMODEL_H