From 58b717fbb8ca67b05cf77e6c14bc81e7d80dfa72 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 30 Jan 2014 17:18:35 +0100 Subject: [PATCH] QmlJSEditor: Move outline model to document Also the updating of the model is now done only once in the document, and delayed till an editor is visible if necessary. Change-Id: I69b1abebc2b691b37a618db7d1f5ebbbc8e75bca Reviewed-by: Fawzi Mohamed --- src/plugins/qmljseditor/qmljseditor.cpp | 63 ++++++------------- src/plugins/qmljseditor/qmljseditor.h | 5 +- .../qmljseditor/qmljseditordocument.cpp | 35 ++++++++++- src/plugins/qmljseditor/qmljseditordocument.h | 2 + .../qmljseditor/qmljseditordocument_p.h | 5 ++ 5 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index 9e026d5abbf..0dcd0f93a59 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -114,7 +114,6 @@ void QmlJSTextEditorWidget::ctor() { m_qmlJsEditorDocument = static_cast(baseTextDocument()); m_outlineCombo = 0; - m_outlineModel = new QmlOutlineModel(m_qmlJsEditorDocument); m_contextPane = 0; m_findReferences = new FindReferences(this); @@ -130,11 +129,6 @@ void QmlJSTextEditorWidget::ctor() connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUses())); connect(this, SIGNAL(cursorPositionChanged()), m_updateUsesTimer, SLOT(start())); - m_updateOutlineTimer = new QTimer(this); - m_updateOutlineTimer->setInterval(UPDATE_OUTLINE_INTERVAL); - m_updateOutlineTimer->setSingleShot(true); - connect(m_updateOutlineTimer, SIGNAL(timeout()), this, SLOT(updateOutlineNow())); - m_updateOutlineIndexTimer = new QTimer(this); m_updateOutlineIndexTimer->setInterval(UPDATE_OUTLINE_INTERVAL); m_updateOutlineIndexTimer->setSingleShot(true); @@ -157,14 +151,14 @@ void QmlJSTextEditorWidget::ctor() connect(this->document(), SIGNAL(modificationChanged(bool)), this, SLOT(modificationChanged(bool))); + connect(m_qmlJsEditorDocument, SIGNAL(updateCodeWarnings(QmlJS::Document::Ptr)), + this, SLOT(updateCodeWarnings(QmlJS::Document::Ptr))); connect(m_qmlJsEditorDocument, SIGNAL(semanticInfoUpdated(QmlJSTools::SemanticInfo)), this, SLOT(semanticInfoUpdated(QmlJSTools::SemanticInfo))); connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)), SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker))); - connect(baseTextDocument(), SIGNAL(updateCodeWarnings(QmlJS::Document::Ptr)), - this, SLOT(updateCodeWarnings(QmlJS::Document::Ptr))); setRequestMarkEnabled(true); } @@ -194,7 +188,7 @@ bool QmlJSTextEditorWidget::isSemanticInfoOutdated() const QmlOutlineModel *QmlJSTextEditorWidget::outlineModel() const { - return m_outlineModel; + return m_qmlJsEditorDocument->outlineModel(); } QModelIndex QmlJSTextEditorWidget::outlineModelIndex() @@ -285,7 +279,7 @@ void QmlJSTextEditorWidget::modificationChanged(bool changed) void QmlJSTextEditorWidget::jumpToOutlineElement(int /*index*/) { QModelIndex index = m_outlineCombo->view()->currentIndex(); - AST::SourceLocation location = m_outlineModel->sourceLocation(index); + AST::SourceLocation location = m_qmlJsEditorDocument->outlineModel()->sourceLocation(index); if (!location.isValid()) return; @@ -300,33 +294,12 @@ void QmlJSTextEditorWidget::jumpToOutlineElement(int /*index*/) setFocus(); } -void QmlJSTextEditorWidget::updateOutlineNow() -{ - if (!m_qmlJsEditorDocument->semanticInfo().document) - return; - - if (m_qmlJsEditorDocument->semanticInfo().document->editorRevision() != editorRevision()) { - m_updateOutlineTimer->start(); - return; - } - - m_outlineModel->update(m_qmlJsEditorDocument->semanticInfo()); - - QTreeView *treeView = static_cast(m_outlineCombo->view()); - treeView->expandAll(); - - updateOutlineIndexNow(); -} - void QmlJSTextEditorWidget::updateOutlineIndexNow() { - if (m_updateOutlineTimer->isActive()) - return; // updateOutlineNow will call this function soon anyway - - if (!m_outlineModel->document()) + if (!m_qmlJsEditorDocument->outlineModel()->document()) return; - if (m_outlineModel->document()->editorRevision() != editorRevision()) { + if (m_qmlJsEditorDocument->outlineModel()->document()->editorRevision() != editorRevision()) { m_updateOutlineIndexTimer->start(); return; } @@ -604,7 +577,7 @@ void QmlJSTextEditorWidget::createToolBar(QmlJSEditor *editor) { m_outlineCombo = new QComboBox; m_outlineCombo->setMinimumContentsLength(22); - m_outlineCombo->setModel(m_outlineModel); + m_outlineCombo->setModel(m_qmlJsEditorDocument->outlineModel()); QTreeView *treeView = new QTreeView; @@ -627,6 +600,11 @@ void QmlJSTextEditorWidget::createToolBar(QmlJSEditor *editor) m_outlineCombo->setSizePolicy(policy); connect(m_outlineCombo, SIGNAL(activated(int)), this, SLOT(jumpToOutlineElement(int))); + connect(m_qmlJsEditorDocument->outlineModel(), SIGNAL(updated()), + m_outlineCombo->view()/*QTreeView*/, SLOT(expandAll())); + connect(m_qmlJsEditorDocument->outlineModel(), SIGNAL(updated()), + this, SLOT(updateOutlineIndexNow())); + connect(this, SIGNAL(cursorPositionChanged()), m_updateOutlineIndexTimer, SLOT(start())); editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo); @@ -856,8 +834,10 @@ void QmlJSTextEditorWidget::unCommentSelection() void QmlJSTextEditorWidget::semanticInfoUpdated(const SemanticInfo &semanticInfo) { - if (isVisible()) - baseTextDocument()->triggerPendingUpdates(); // trigger semantic highlighting if necessary + if (isVisible()) { + // trigger semantic highlighting and model update if necessary + baseTextDocument()->triggerPendingUpdates(); + } if (m_contextPane) { Node *newNode = semanticInfo.declaringMemberNoProperties(position()); @@ -868,9 +848,6 @@ void QmlJSTextEditorWidget::semanticInfoUpdated(const SemanticInfo &semanticInfo } updateUses(); - - // update outline - m_updateOutlineTimer->start(); } void QmlJSTextEditorWidget::onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) @@ -883,11 +860,11 @@ QModelIndex QmlJSTextEditorWidget::indexForPosition(unsigned cursorPosition, con { QModelIndex lastIndex = rootIndex; - - const int rowCount = m_outlineModel->rowCount(rootIndex); + QmlOutlineModel *model = m_qmlJsEditorDocument->outlineModel(); + const int rowCount = model->rowCount(rootIndex); for (int i = 0; i < rowCount; ++i) { - QModelIndex childIndex = m_outlineModel->index(i, 0, rootIndex); - AST::SourceLocation location = m_outlineModel->sourceLocation(childIndex); + QModelIndex childIndex = model->index(i, 0, rootIndex); + AST::SourceLocation location = model->sourceLocation(childIndex); if ((cursorPosition >= location.offset) && (cursorPosition <= location.offset + location.length)) { diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h index e31d9084589..e93d564094c 100644 --- a/src/plugins/qmljseditor/qmljseditor.h +++ b/src/plugins/qmljseditor/qmljseditor.h @@ -105,8 +105,8 @@ public: bool isSemanticInfoOutdated() const; int editorRevision() const; QVector diagnosticRanges() const; - Internal::QmlOutlineModel *outlineModel() const; + QModelIndex outlineModelIndex(); static QVector highlighterFormatCategories(); @@ -126,7 +126,6 @@ private slots: void modificationChanged(bool); void jumpToOutlineElement(int index); - void updateOutlineNow(); void updateOutlineIndexNow(); void updateContextPane(); void showTextMarker(); @@ -166,11 +165,9 @@ private: Internal::QmlJSEditorDocument *m_qmlJsEditorDocument; QTimer *m_updateUsesTimer; // to wait for multiple text cursor position changes - QTimer *m_updateOutlineTimer; QTimer *m_updateOutlineIndexTimer; QTimer *m_contextPaneTimer; QComboBox *m_outlineCombo; - Internal::QmlOutlineModel *m_outlineModel; QModelIndex m_outlineModelIndex; QmlJS::ModelManagerInterface *m_modelManager; diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index 8cf8e24f19f..d15f485fc2b 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -33,6 +33,7 @@ #include "qmljshighlighter.h" #include "qmljssemantichighlighter.h" #include "qmljssemanticinfoupdater.h" +#include "qmloutlinemodel.h" #include #include @@ -46,7 +47,8 @@ using namespace QmlJSTools; namespace { enum { - UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100 + UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100, + UPDATE_OUTLINE_INTERVAL = 500 }; class FindIdDeclarations: protected Visitor @@ -399,7 +401,9 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare : m_q(parent), m_semanticInfoDocRevision(-1), m_semanticHighlighter(new SemanticHighlighter(parent)), - m_semanticHighlightingNecessary(false) + m_semanticHighlightingNecessary(false), + m_outlineModelNeedsUpdate(false), + m_outlineModel(new QmlOutlineModel(parent)) { ModelManagerInterface *modelManager = ModelManagerInterface::instance(); @@ -425,6 +429,12 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare connect(m_reupdateSemanticInfoTimer, SIGNAL(timeout()), this, SLOT(reupdateSemanticInfo())); connect(modelManager, SIGNAL(libraryInfoUpdated(QString,QmlJS::LibraryInfo)), m_reupdateSemanticInfoTimer, SLOT(start())); + + // outline model + m_updateOutlineModelTimer = new QTimer(this); + m_updateOutlineModelTimer->setInterval(UPDATE_OUTLINE_INTERVAL); + m_updateOutlineModelTimer->setSingleShot(true); + connect(m_updateOutlineModelTimer, SIGNAL(timeout()), this, SLOT(updateOutlineModel())); } QmlJSEditorDocumentPrivate::~QmlJSEditorDocumentPrivate() @@ -490,8 +500,18 @@ void QmlJSEditorDocumentPrivate::acceptNewSemanticInfo(const SemanticInfo &seman FindIdDeclarations updateIds; m_semanticInfo.idLocations = updateIds(doc); + m_outlineModelNeedsUpdate = true; m_semanticHighlightingNecessary = true; - emit m_q->semanticInfoUpdated(m_semanticInfo); + + emit m_q->semanticInfoUpdated(m_semanticInfo); // calls triggerPendingUpdates as necessary +} + +void QmlJSEditorDocumentPrivate::updateOutlineModel() +{ + if (m_q->isSemanticInfoOutdated()) + return; // outline update will be retriggered when semantic info is updated + + m_outlineModel->update(m_semanticInfo); } QmlJSEditorDocument::QmlJSEditorDocument() @@ -523,6 +543,11 @@ QVector QmlJSEditorDocument::diagnosticRanges() const return m_d->m_diagnosticRanges; } +QmlOutlineModel *QmlJSEditorDocument::outlineModel() const +{ + return m_d->m_outlineModel; +} + void QmlJSEditorDocument::setDiagnosticRanges(const QVector &ranges) { m_d->m_diagnosticRanges = ranges; @@ -546,6 +571,10 @@ void QmlJSEditorDocument::triggerPendingUpdates() m_d->m_semanticHighlightingNecessary = false; m_d->m_semanticHighlighter->rerun(m_d->m_semanticInfo); } + if (m_d->m_outlineModelNeedsUpdate && !isSemanticInfoOutdated()) { + m_d->m_outlineModelNeedsUpdate = false; + m_d->m_updateOutlineModelTimer->start(); + } } } // Internal diff --git a/src/plugins/qmljseditor/qmljseditordocument.h b/src/plugins/qmljseditor/qmljseditordocument.h index 551256c01ce..01870542aea 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.h +++ b/src/plugins/qmljseditor/qmljseditordocument.h @@ -40,6 +40,7 @@ namespace QmlJSEditor { namespace Internal { class QmlJSEditorDocumentPrivate; +class QmlOutlineModel; class QmlJSEditorDocument : public TextEditor::BaseTextDocument { @@ -52,6 +53,7 @@ public: bool isSemanticInfoOutdated() const; QVector diagnosticRanges() const; void setDiagnosticRanges(const QVector &ranges); + Internal::QmlOutlineModel *outlineModel() const; signals: void updateCodeWarnings(QmlJS::Document::Ptr doc); diff --git a/src/plugins/qmljseditor/qmljseditordocument_p.h b/src/plugins/qmljseditor/qmljseditordocument_p.h index 90df5e10afb..d99b0ece27b 100644 --- a/src/plugins/qmljseditor/qmljseditordocument_p.h +++ b/src/plugins/qmljseditor/qmljseditordocument_p.h @@ -41,6 +41,7 @@ namespace QmlJSEditor { namespace Internal { class QmlJSEditorDocument; +class QmlOutlineModel; class SemanticHighlighter; class SemanticInfoUpdater; @@ -58,6 +59,7 @@ public slots: void onDocumentUpdated(QmlJS::Document::Ptr doc); void reupdateSemanticInfo(); void acceptNewSemanticInfo(const QmlJSTools::SemanticInfo &semanticInfo); + void updateOutlineModel(); public: QmlJSEditorDocument *m_q; @@ -69,6 +71,9 @@ public: QVector m_diagnosticRanges; Internal::SemanticHighlighter *m_semanticHighlighter; bool m_semanticHighlightingNecessary; + bool m_outlineModelNeedsUpdate; + QTimer *m_updateOutlineModelTimer; + Internal::QmlOutlineModel *m_outlineModel; }; } // Internal