CppEditor: remove dependencies between different outline views

Change-Id: If371811ac236c971d21815ef8738df5a169865e3
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2022-08-17 13:26:49 +02:00
parent 7c7fdf6460
commit 33001a866f
8 changed files with 84 additions and 77 deletions

View File

@@ -140,18 +140,6 @@ bool CppEditorOutline::isSorted() const
return m_proxyModel->sortColumn() == 0; return m_proxyModel->sortColumn() == 0;
} }
QModelIndex CppEditorOutline::modelIndex()
{
if (!m_modelIndex.isValid()) {
int line = 0, column = 0;
m_editorWidget->convertPosition(m_editorWidget->position(), &line, &column);
m_modelIndex = indexForPosition(line, column);
emit modelIndexChanged(m_modelIndex);
}
return m_modelIndex;
}
QWidget *CppEditorOutline::widget() const QWidget *CppEditorOutline::widget() const
{ {
return m_combo; return m_combo;
@@ -184,8 +172,9 @@ void CppEditorOutline::updateIndexNow()
m_updateIndexTimer->stop(); m_updateIndexTimer->stop();
m_modelIndex = QModelIndex(); //invalidate int line = 0, column = 0;
QModelIndex comboIndex = modelIndex(); m_editorWidget->convertPosition(m_editorWidget->position(), &line, &column);
QModelIndex comboIndex = m_model->indexForPosition(line, column);
if (comboIndex.isValid()) { if (comboIndex.isValid()) {
QSignalBlocker blocker(m_combo); QSignalBlocker blocker(m_combo);
@@ -214,41 +203,6 @@ void CppEditorOutline::gotoSymbolInEditor()
emit m_editorWidget->activateEditor(); emit m_editorWidget->activateEditor();
} }
static bool contains(const OverviewModel::Range &range, int line, int column)
{
if (line < range.first.line || line > range.second.line)
return false;
if (line == range.first.line && column < range.first.column)
return false;
if (line == range.second.line && column > range.second.column)
return false;
return true;
}
QModelIndex CppEditorOutline::indexForPosition(int line, int column,
const QModelIndex &rootIndex) const
{
QModelIndex lastIndex = rootIndex;
const int rowCount = m_model->rowCount(rootIndex);
for (int row = 0; row < rowCount; ++row) {
const QModelIndex index = m_model->index(row, 0, rootIndex);
const OverviewModel::Range range = m_model->rangeFromIndex(index);
if (range.first.line > line)
break;
// Skip ranges that do not include current line and column.
if (range.second != range.first && !contains(range, line, column))
continue;
lastIndex = index;
}
if (lastIndex != rootIndex) {
// recurse
lastIndex = indexForPosition(line, column, lastIndex);
}
return lastIndex;
}
} // namespace CppEditor::Internal } // namespace CppEditor::Internal
#include <cppeditoroutline.moc> #include <cppeditoroutline.moc>

View File

@@ -53,13 +53,8 @@ class CppEditorOutline : public QObject
public: public:
explicit CppEditorOutline(CppEditorWidget *editorWidget); explicit CppEditorOutline(CppEditorWidget *editorWidget);
QModelIndex modelIndex();
QWidget *widget() const; // Must be deleted by client. QWidget *widget() const; // Must be deleted by client.
signals:
void modelIndexChanged(const QModelIndex &index);
public slots: public slots:
void updateIndex(); void updateIndex();
@@ -72,8 +67,6 @@ private:
CppEditorOutline(); CppEditorOutline();
bool isSorted() const; bool isSorted() const;
QModelIndex indexForPosition(int line, int column,
const QModelIndex &rootIndex = QModelIndex()) const;
OverviewModel *m_model = nullptr; // Not owned OverviewModel *m_model = nullptr; // Not owned
@@ -81,7 +74,6 @@ private:
Utils::TreeViewComboBox *m_combo = nullptr; // Not owned Utils::TreeViewComboBox *m_combo = nullptr; // Not owned
QSortFilterProxyModel *m_proxyModel = nullptr; QSortFilterProxyModel *m_proxyModel = nullptr;
QModelIndex m_modelIndex;
QAction *m_sortAction = nullptr; QAction *m_sortAction = nullptr;
QTimer *m_updateIndexTimer = nullptr; QTimer *m_updateIndexTimer = nullptr;
}; };

View File

@@ -597,11 +597,6 @@ CppEditorDocument *CppEditorWidget::cppEditorDocument() const
return d->m_cppEditorDocument; return d->m_cppEditorDocument;
} }
CppEditorOutline *CppEditorWidget::outline() const
{
return d->m_cppEditorOutline;
}
void CppEditorWidget::paste() void CppEditorWidget::paste()
{ {
if (d->m_localRenaming.handlePaste()) if (d->m_localRenaming.handlePaste())

View File

@@ -57,7 +57,6 @@ public:
~CppEditorWidget() override; ~CppEditorWidget() override;
Internal::CppEditorDocument *cppEditorDocument() const; Internal::CppEditorDocument *cppEditorDocument() const;
Internal::CppEditorOutline *outline() const;
bool isSemanticInfoValidExceptLocalUses() const; bool isSemanticInfoValidExceptLocalUses() const;
bool isSemanticInfoValid() const; bool isSemanticInfoValid() const;

View File

@@ -99,13 +99,13 @@ Qt::DropActions CppOutlineFilterModel::supportedDragActions() const
CppOutlineWidget::CppOutlineWidget(CppEditorWidget *editor) : CppOutlineWidget::CppOutlineWidget(CppEditorWidget *editor) :
m_editor(editor), m_editor(editor),
m_treeView(new CppOutlineTreeView(this)), m_treeView(new CppOutlineTreeView(this)),
m_model(&m_editor->cppEditorDocument()->outlineModel()),
m_proxyModel(new CppOutlineFilterModel(*m_model, this)),
m_enableCursorSync(true), m_enableCursorSync(true),
m_blockCursorSync(false), m_blockCursorSync(false),
m_sorted(false) m_sorted(false)
{ {
OverviewModel *model = &m_editor->cppEditorDocument()->outlineModel(); m_proxyModel->setSourceModel(m_model);
m_proxyModel = new CppOutlineFilterModel(*model, this);
m_proxyModel->setSourceModel(model);
auto *layout = new QVBoxLayout; auto *layout = new QVBoxLayout;
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
@@ -117,13 +117,19 @@ CppOutlineWidget::CppOutlineWidget(CppEditorWidget *editor) :
m_treeView->setSortingEnabled(true); m_treeView->setSortingEnabled(true);
setFocusProxy(m_treeView); setFocusProxy(m_treeView);
connect(model, &QAbstractItemModel::modelReset, this, &CppOutlineWidget::modelUpdated); connect(m_model, &QAbstractItemModel::modelReset, this, &CppOutlineWidget::modelUpdated);
modelUpdated(); modelUpdated();
connect(m_editor->outline(), &CppEditorOutline::modelIndexChanged,
this, &CppOutlineWidget::updateSelectionInTree);
connect(m_treeView, &QAbstractItemView::activated, connect(m_treeView, &QAbstractItemView::activated,
this, &CppOutlineWidget::onItemActivated); this, &CppOutlineWidget::onItemActivated);
connect(editor, &QPlainTextEdit::cursorPositionChanged, this, [this] {
if (m_model->rootItem()->hasChildren())
updateIndex();
});
m_updateIndexTimer.setSingleShot(true);
m_updateIndexTimer.setInterval(500);
connect(&m_updateIndexTimer, &QTimer::timeout, this, &CppOutlineWidget::updateIndexNow);
} }
QList<QAction*> CppOutlineWidget::filterMenuActions() const QList<QAction*> CppOutlineWidget::filterMenuActions() const
@@ -135,7 +141,7 @@ void CppOutlineWidget::setCursorSynchronization(bool syncWithCursor)
{ {
m_enableCursorSync = syncWithCursor; m_enableCursorSync = syncWithCursor;
if (m_enableCursorSync) if (m_enableCursorSync)
updateSelectionInTree(m_editor->outline()->modelIndex()); updateIndexNow();
} }
bool CppOutlineWidget::isSorted() const bool CppOutlineWidget::isSorted() const
@@ -164,17 +170,37 @@ void CppOutlineWidget::modelUpdated()
m_treeView->expandAll(); m_treeView->expandAll();
} }
void CppOutlineWidget::updateSelectionInTree(const QModelIndex &index) void CppOutlineWidget::updateIndex()
{
m_updateIndexTimer.start();
}
void CppOutlineWidget::updateIndexNow()
{ {
if (!syncCursor()) if (!syncCursor())
return; return;
QModelIndex proxyIndex = m_proxyModel->mapFromSource(index); const auto revision = static_cast<unsigned>(m_editor->document()->revision());
if (m_model->editorRevision() != revision) {
m_editor->cppEditorDocument()->updateOutline();
m_updateIndexTimer.start();
return;
}
m_updateIndexTimer.stop();
int line = 0, column = 0;
m_editor->convertPosition(m_editor->position(), &line, &column);
QModelIndex index = m_model->indexForPosition(line, column);
if (index.isValid()) {
m_blockCursorSync = true;
QModelIndex proxyIndex = m_proxyModel->mapFromSource(index);
m_treeView->setCurrentIndex(proxyIndex);
m_treeView->scrollTo(proxyIndex);
m_blockCursorSync = false;
}
m_blockCursorSync = true;
m_treeView->setCurrentIndex(proxyIndex);
m_treeView->scrollTo(proxyIndex);
m_blockCursorSync = false;
} }
void CppOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex) void CppOutlineWidget::updateTextCursor(const QModelIndex &proxyIndex)

View File

@@ -33,6 +33,7 @@
#include <utils/navigationtreeview.h> #include <utils/navigationtreeview.h>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QTimer>
namespace CppEditor { namespace CppEditor {
namespace Internal { namespace Internal {
@@ -75,7 +76,8 @@ public:
QVariantMap settings() const override; QVariantMap settings() const override;
private: private:
void modelUpdated(); void modelUpdated();
void updateSelectionInTree(const QModelIndex &index); void updateIndex();
void updateIndexNow();
void updateTextCursor(const QModelIndex &index); void updateTextCursor(const QModelIndex &index);
void onItemActivated(const QModelIndex &index); void onItemActivated(const QModelIndex &index);
bool syncCursor(); bool syncCursor();
@@ -83,7 +85,9 @@ private:
private: private:
CppEditorWidget *m_editor; CppEditorWidget *m_editor;
CppOutlineTreeView *m_treeView; CppOutlineTreeView *m_treeView;
OverviewModel * const m_model;
QSortFilterProxyModel *m_proxyModel; QSortFilterProxyModel *m_proxyModel;
QTimer m_updateIndexTimer;
bool m_enableCursorSync; bool m_enableCursorSync;
bool m_blockCursorSync; bool m_blockCursorSync;

View File

@@ -290,4 +290,39 @@ void OverviewModel::buildTree(SymbolItem *root, bool isRoot)
} }
} }
static bool contains(const OverviewModel::Range &range, int line, int column)
{
if (line < range.first.line || line > range.second.line)
return false;
if (line == range.first.line && column < range.first.column)
return false;
if (line == range.second.line && column > range.second.column)
return false;
return true;
}
QModelIndex OverviewModel::indexForPosition(int line, int column,
const QModelIndex &rootIndex) const
{
QModelIndex lastIndex = rootIndex;
const int rowCount = this->rowCount(rootIndex);
for (int row = 0; row < rowCount; ++row) {
const QModelIndex index = this->index(row, 0, rootIndex);
const OverviewModel::Range range = rangeFromIndex(index);
if (range.first.line > line)
break;
// Skip ranges that do not include current line and column.
if (range.second != range.first && !contains(range, line, column))
continue;
lastIndex = index;
}
if (lastIndex != rootIndex) {
// recurse
lastIndex = indexForPosition(line, column, lastIndex);
}
return lastIndex;
}
} // namespace CppEditor::Internal } // namespace CppEditor::Internal

View File

@@ -70,6 +70,8 @@ public:
using Range = std::pair<Utils::LineColumn, Utils::LineColumn>; using Range = std::pair<Utils::LineColumn, Utils::LineColumn>;
Range rangeFromIndex(const QModelIndex &sourceIndex) const; Range rangeFromIndex(const QModelIndex &sourceIndex) const;
QModelIndex indexForPosition(int line, int column, const QModelIndex &rootIndex = {}) const;
private: private:
void rebuild(); void rebuild();
CPlusPlus::Symbol *symbolFromIndex(const QModelIndex &index) const; CPlusPlus::Symbol *symbolFromIndex(const QModelIndex &index) const;