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 <fawzi.mohamed@digia.com>
This commit is contained in:
Eike Ziller
2014-01-30 17:18:35 +01:00
parent 1e6bc2758d
commit 58b717fbb8
5 changed files with 60 additions and 50 deletions

View File

@@ -114,7 +114,6 @@ void QmlJSTextEditorWidget::ctor()
{ {
m_qmlJsEditorDocument = static_cast<QmlJSEditorDocument *>(baseTextDocument()); m_qmlJsEditorDocument = static_cast<QmlJSEditorDocument *>(baseTextDocument());
m_outlineCombo = 0; m_outlineCombo = 0;
m_outlineModel = new QmlOutlineModel(m_qmlJsEditorDocument);
m_contextPane = 0; m_contextPane = 0;
m_findReferences = new FindReferences(this); m_findReferences = new FindReferences(this);
@@ -130,11 +129,6 @@ void QmlJSTextEditorWidget::ctor()
connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUses())); connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUses()));
connect(this, SIGNAL(cursorPositionChanged()), m_updateUsesTimer, SLOT(start())); 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 = new QTimer(this);
m_updateOutlineIndexTimer->setInterval(UPDATE_OUTLINE_INTERVAL); m_updateOutlineIndexTimer->setInterval(UPDATE_OUTLINE_INTERVAL);
m_updateOutlineIndexTimer->setSingleShot(true); m_updateOutlineIndexTimer->setSingleShot(true);
@@ -157,14 +151,14 @@ void QmlJSTextEditorWidget::ctor()
connect(this->document(), SIGNAL(modificationChanged(bool)), this, SLOT(modificationChanged(bool))); 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)), connect(m_qmlJsEditorDocument, SIGNAL(semanticInfoUpdated(QmlJSTools::SemanticInfo)),
this, SLOT(semanticInfoUpdated(QmlJSTools::SemanticInfo))); this, SLOT(semanticInfoUpdated(QmlJSTools::SemanticInfo)));
connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)), connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)),
SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker))); SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker)));
connect(baseTextDocument(), SIGNAL(updateCodeWarnings(QmlJS::Document::Ptr)),
this, SLOT(updateCodeWarnings(QmlJS::Document::Ptr)));
setRequestMarkEnabled(true); setRequestMarkEnabled(true);
} }
@@ -194,7 +188,7 @@ bool QmlJSTextEditorWidget::isSemanticInfoOutdated() const
QmlOutlineModel *QmlJSTextEditorWidget::outlineModel() const QmlOutlineModel *QmlJSTextEditorWidget::outlineModel() const
{ {
return m_outlineModel; return m_qmlJsEditorDocument->outlineModel();
} }
QModelIndex QmlJSTextEditorWidget::outlineModelIndex() QModelIndex QmlJSTextEditorWidget::outlineModelIndex()
@@ -285,7 +279,7 @@ void QmlJSTextEditorWidget::modificationChanged(bool changed)
void QmlJSTextEditorWidget::jumpToOutlineElement(int /*index*/) void QmlJSTextEditorWidget::jumpToOutlineElement(int /*index*/)
{ {
QModelIndex index = m_outlineCombo->view()->currentIndex(); QModelIndex index = m_outlineCombo->view()->currentIndex();
AST::SourceLocation location = m_outlineModel->sourceLocation(index); AST::SourceLocation location = m_qmlJsEditorDocument->outlineModel()->sourceLocation(index);
if (!location.isValid()) if (!location.isValid())
return; return;
@@ -300,33 +294,12 @@ void QmlJSTextEditorWidget::jumpToOutlineElement(int /*index*/)
setFocus(); 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<QTreeView*>(m_outlineCombo->view());
treeView->expandAll();
updateOutlineIndexNow();
}
void QmlJSTextEditorWidget::updateOutlineIndexNow() void QmlJSTextEditorWidget::updateOutlineIndexNow()
{ {
if (m_updateOutlineTimer->isActive()) if (!m_qmlJsEditorDocument->outlineModel()->document())
return; // updateOutlineNow will call this function soon anyway
if (!m_outlineModel->document())
return; return;
if (m_outlineModel->document()->editorRevision() != editorRevision()) { if (m_qmlJsEditorDocument->outlineModel()->document()->editorRevision() != editorRevision()) {
m_updateOutlineIndexTimer->start(); m_updateOutlineIndexTimer->start();
return; return;
} }
@@ -604,7 +577,7 @@ void QmlJSTextEditorWidget::createToolBar(QmlJSEditor *editor)
{ {
m_outlineCombo = new QComboBox; m_outlineCombo = new QComboBox;
m_outlineCombo->setMinimumContentsLength(22); m_outlineCombo->setMinimumContentsLength(22);
m_outlineCombo->setModel(m_outlineModel); m_outlineCombo->setModel(m_qmlJsEditorDocument->outlineModel());
QTreeView *treeView = new QTreeView; QTreeView *treeView = new QTreeView;
@@ -627,6 +600,11 @@ void QmlJSTextEditorWidget::createToolBar(QmlJSEditor *editor)
m_outlineCombo->setSizePolicy(policy); m_outlineCombo->setSizePolicy(policy);
connect(m_outlineCombo, SIGNAL(activated(int)), this, SLOT(jumpToOutlineElement(int))); 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())); connect(this, SIGNAL(cursorPositionChanged()), m_updateOutlineIndexTimer, SLOT(start()));
editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo); editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo);
@@ -856,8 +834,10 @@ void QmlJSTextEditorWidget::unCommentSelection()
void QmlJSTextEditorWidget::semanticInfoUpdated(const SemanticInfo &semanticInfo) void QmlJSTextEditorWidget::semanticInfoUpdated(const SemanticInfo &semanticInfo)
{ {
if (isVisible()) if (isVisible()) {
baseTextDocument()->triggerPendingUpdates(); // trigger semantic highlighting if necessary // trigger semantic highlighting and model update if necessary
baseTextDocument()->triggerPendingUpdates();
}
if (m_contextPane) { if (m_contextPane) {
Node *newNode = semanticInfo.declaringMemberNoProperties(position()); Node *newNode = semanticInfo.declaringMemberNoProperties(position());
@@ -868,9 +848,6 @@ void QmlJSTextEditorWidget::semanticInfoUpdated(const SemanticInfo &semanticInfo
} }
updateUses(); updateUses();
// update outline
m_updateOutlineTimer->start();
} }
void QmlJSTextEditorWidget::onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker) void QmlJSTextEditorWidget::onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker)
@@ -883,11 +860,11 @@ QModelIndex QmlJSTextEditorWidget::indexForPosition(unsigned cursorPosition, con
{ {
QModelIndex lastIndex = rootIndex; QModelIndex lastIndex = rootIndex;
QmlOutlineModel *model = m_qmlJsEditorDocument->outlineModel();
const int rowCount = m_outlineModel->rowCount(rootIndex); const int rowCount = model->rowCount(rootIndex);
for (int i = 0; i < rowCount; ++i) { for (int i = 0; i < rowCount; ++i) {
QModelIndex childIndex = m_outlineModel->index(i, 0, rootIndex); QModelIndex childIndex = model->index(i, 0, rootIndex);
AST::SourceLocation location = m_outlineModel->sourceLocation(childIndex); AST::SourceLocation location = model->sourceLocation(childIndex);
if ((cursorPosition >= location.offset) if ((cursorPosition >= location.offset)
&& (cursorPosition <= location.offset + location.length)) { && (cursorPosition <= location.offset + location.length)) {

View File

@@ -105,8 +105,8 @@ public:
bool isSemanticInfoOutdated() const; bool isSemanticInfoOutdated() const;
int editorRevision() const; int editorRevision() const;
QVector<QTextLayout::FormatRange> diagnosticRanges() const; QVector<QTextLayout::FormatRange> diagnosticRanges() const;
Internal::QmlOutlineModel *outlineModel() const; Internal::QmlOutlineModel *outlineModel() const;
QModelIndex outlineModelIndex(); QModelIndex outlineModelIndex();
static QVector<TextEditor::TextStyle> highlighterFormatCategories(); static QVector<TextEditor::TextStyle> highlighterFormatCategories();
@@ -126,7 +126,6 @@ private slots:
void modificationChanged(bool); void modificationChanged(bool);
void jumpToOutlineElement(int index); void jumpToOutlineElement(int index);
void updateOutlineNow();
void updateOutlineIndexNow(); void updateOutlineIndexNow();
void updateContextPane(); void updateContextPane();
void showTextMarker(); void showTextMarker();
@@ -166,11 +165,9 @@ private:
Internal::QmlJSEditorDocument *m_qmlJsEditorDocument; Internal::QmlJSEditorDocument *m_qmlJsEditorDocument;
QTimer *m_updateUsesTimer; // to wait for multiple text cursor position changes QTimer *m_updateUsesTimer; // to wait for multiple text cursor position changes
QTimer *m_updateOutlineTimer;
QTimer *m_updateOutlineIndexTimer; QTimer *m_updateOutlineIndexTimer;
QTimer *m_contextPaneTimer; QTimer *m_contextPaneTimer;
QComboBox *m_outlineCombo; QComboBox *m_outlineCombo;
Internal::QmlOutlineModel *m_outlineModel;
QModelIndex m_outlineModelIndex; QModelIndex m_outlineModelIndex;
QmlJS::ModelManagerInterface *m_modelManager; QmlJS::ModelManagerInterface *m_modelManager;

View File

@@ -33,6 +33,7 @@
#include "qmljshighlighter.h" #include "qmljshighlighter.h"
#include "qmljssemantichighlighter.h" #include "qmljssemantichighlighter.h"
#include "qmljssemanticinfoupdater.h" #include "qmljssemanticinfoupdater.h"
#include "qmloutlinemodel.h"
#include <qmljstools/qmljsindenter.h> #include <qmljstools/qmljsindenter.h>
#include <qmljstools/qmljsmodelmanager.h> #include <qmljstools/qmljsmodelmanager.h>
@@ -46,7 +47,8 @@ using namespace QmlJSTools;
namespace { namespace {
enum { enum {
UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100 UPDATE_DOCUMENT_DEFAULT_INTERVAL = 100,
UPDATE_OUTLINE_INTERVAL = 500
}; };
class FindIdDeclarations: protected Visitor class FindIdDeclarations: protected Visitor
@@ -399,7 +401,9 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare
: m_q(parent), : m_q(parent),
m_semanticInfoDocRevision(-1), m_semanticInfoDocRevision(-1),
m_semanticHighlighter(new SemanticHighlighter(parent)), m_semanticHighlighter(new SemanticHighlighter(parent)),
m_semanticHighlightingNecessary(false) m_semanticHighlightingNecessary(false),
m_outlineModelNeedsUpdate(false),
m_outlineModel(new QmlOutlineModel(parent))
{ {
ModelManagerInterface *modelManager = ModelManagerInterface::instance(); ModelManagerInterface *modelManager = ModelManagerInterface::instance();
@@ -425,6 +429,12 @@ QmlJSEditorDocumentPrivate::QmlJSEditorDocumentPrivate(QmlJSEditorDocument *pare
connect(m_reupdateSemanticInfoTimer, SIGNAL(timeout()), this, SLOT(reupdateSemanticInfo())); connect(m_reupdateSemanticInfoTimer, SIGNAL(timeout()), this, SLOT(reupdateSemanticInfo()));
connect(modelManager, SIGNAL(libraryInfoUpdated(QString,QmlJS::LibraryInfo)), connect(modelManager, SIGNAL(libraryInfoUpdated(QString,QmlJS::LibraryInfo)),
m_reupdateSemanticInfoTimer, SLOT(start())); 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() QmlJSEditorDocumentPrivate::~QmlJSEditorDocumentPrivate()
@@ -490,8 +500,18 @@ void QmlJSEditorDocumentPrivate::acceptNewSemanticInfo(const SemanticInfo &seman
FindIdDeclarations updateIds; FindIdDeclarations updateIds;
m_semanticInfo.idLocations = updateIds(doc); m_semanticInfo.idLocations = updateIds(doc);
m_outlineModelNeedsUpdate = true;
m_semanticHighlightingNecessary = 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() QmlJSEditorDocument::QmlJSEditorDocument()
@@ -523,6 +543,11 @@ QVector<QTextLayout::FormatRange> QmlJSEditorDocument::diagnosticRanges() const
return m_d->m_diagnosticRanges; return m_d->m_diagnosticRanges;
} }
QmlOutlineModel *QmlJSEditorDocument::outlineModel() const
{
return m_d->m_outlineModel;
}
void QmlJSEditorDocument::setDiagnosticRanges(const QVector<QTextLayout::FormatRange> &ranges) void QmlJSEditorDocument::setDiagnosticRanges(const QVector<QTextLayout::FormatRange> &ranges)
{ {
m_d->m_diagnosticRanges = ranges; m_d->m_diagnosticRanges = ranges;
@@ -546,6 +571,10 @@ void QmlJSEditorDocument::triggerPendingUpdates()
m_d->m_semanticHighlightingNecessary = false; m_d->m_semanticHighlightingNecessary = false;
m_d->m_semanticHighlighter->rerun(m_d->m_semanticInfo); 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 } // Internal

View File

@@ -40,6 +40,7 @@ namespace QmlJSEditor {
namespace Internal { namespace Internal {
class QmlJSEditorDocumentPrivate; class QmlJSEditorDocumentPrivate;
class QmlOutlineModel;
class QmlJSEditorDocument : public TextEditor::BaseTextDocument class QmlJSEditorDocument : public TextEditor::BaseTextDocument
{ {
@@ -52,6 +53,7 @@ public:
bool isSemanticInfoOutdated() const; bool isSemanticInfoOutdated() const;
QVector<QTextLayout::FormatRange> diagnosticRanges() const; QVector<QTextLayout::FormatRange> diagnosticRanges() const;
void setDiagnosticRanges(const QVector<QTextLayout::FormatRange> &ranges); void setDiagnosticRanges(const QVector<QTextLayout::FormatRange> &ranges);
Internal::QmlOutlineModel *outlineModel() const;
signals: signals:
void updateCodeWarnings(QmlJS::Document::Ptr doc); void updateCodeWarnings(QmlJS::Document::Ptr doc);

View File

@@ -41,6 +41,7 @@ namespace QmlJSEditor {
namespace Internal { namespace Internal {
class QmlJSEditorDocument; class QmlJSEditorDocument;
class QmlOutlineModel;
class SemanticHighlighter; class SemanticHighlighter;
class SemanticInfoUpdater; class SemanticInfoUpdater;
@@ -58,6 +59,7 @@ public slots:
void onDocumentUpdated(QmlJS::Document::Ptr doc); void onDocumentUpdated(QmlJS::Document::Ptr doc);
void reupdateSemanticInfo(); void reupdateSemanticInfo();
void acceptNewSemanticInfo(const QmlJSTools::SemanticInfo &semanticInfo); void acceptNewSemanticInfo(const QmlJSTools::SemanticInfo &semanticInfo);
void updateOutlineModel();
public: public:
QmlJSEditorDocument *m_q; QmlJSEditorDocument *m_q;
@@ -69,6 +71,9 @@ public:
QVector<QTextLayout::FormatRange> m_diagnosticRanges; QVector<QTextLayout::FormatRange> m_diagnosticRanges;
Internal::SemanticHighlighter *m_semanticHighlighter; Internal::SemanticHighlighter *m_semanticHighlighter;
bool m_semanticHighlightingNecessary; bool m_semanticHighlightingNecessary;
bool m_outlineModelNeedsUpdate;
QTimer *m_updateOutlineModelTimer;
Internal::QmlOutlineModel *m_outlineModel;
}; };
} // Internal } // Internal