forked from qt-creator/qt-creator
Core: Use TreeModel for OpenEditorWindow
With 2000 open files this brings the population time from ~170ms to ~20ms on my machine. Change-Id: I1e6ba77ee4595276a7eaecafc9d7c84386b2155a Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -10,9 +10,11 @@
|
||||
#include "../idocument.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/basetreeview.h>
|
||||
#include <utils/fsengine/fileiconprovider.h>
|
||||
#include <utils/hostosinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/treemodel.h>
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QFocusEvent>
|
||||
@@ -24,59 +26,120 @@
|
||||
Q_DECLARE_METATYPE(Core::Internal::EditorView*)
|
||||
Q_DECLARE_METATYPE(Core::IDocument*)
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
namespace Core::Internal {
|
||||
|
||||
class OpenEditorsTreeWidget : public QTreeWidget
|
||||
class OpenEditorsItem : public TreeItem
|
||||
{
|
||||
public:
|
||||
explicit OpenEditorsTreeWidget(QWidget *parent) : QTreeWidget(parent) {}
|
||||
QVariant data(int column, int role) const override
|
||||
{
|
||||
if (column != 0)
|
||||
return {};
|
||||
|
||||
if (!entry)
|
||||
return {};
|
||||
|
||||
if (role == Qt::DecorationRole) {
|
||||
return !entry->filePath().isEmpty() && entry->document->isFileReadOnly()
|
||||
? DocumentModel::lockedIcon() : FileIconProvider::icon(entry->filePath());
|
||||
}
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
QString title = entry->displayName();
|
||||
if (entry->document->isModified())
|
||||
title += Tr::tr("*");
|
||||
return title;
|
||||
}
|
||||
|
||||
if (role == Qt::ToolTipRole)
|
||||
return entry->filePath().toUserOutput();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
DocumentModel::Entry *entry = nullptr;
|
||||
EditorView *view = nullptr;
|
||||
};
|
||||
|
||||
static void selectEditor(OpenEditorsItem *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
if (!EditorManagerPrivate::activateEditorForEntry(item->view, item->entry))
|
||||
delete item;
|
||||
}
|
||||
|
||||
class OpenEditorsView : public QTreeView
|
||||
{
|
||||
public:
|
||||
OpenEditorsView()
|
||||
{
|
||||
m_model.setHeader({{}});
|
||||
setModel(&m_model);
|
||||
}
|
||||
|
||||
QSize sizeHint() const override
|
||||
{
|
||||
return QSize(sizeHintForColumn(0) + verticalScrollBar()->width() + frameWidth() * 2,
|
||||
viewportSizeHint().height() + frameWidth() * 2);
|
||||
}
|
||||
};
|
||||
|
||||
enum class Role
|
||||
{
|
||||
Entry = Qt::UserRole,
|
||||
View = Qt::UserRole + 1
|
||||
OpenEditorsItem *currentItem() const
|
||||
{
|
||||
QModelIndexList indexes = selectedIndexes();
|
||||
return indexes.size() == 1 ? m_model.itemForIndexAtLevel<1>(indexes.front()) : nullptr;
|
||||
}
|
||||
|
||||
int currentRow() const
|
||||
{
|
||||
QModelIndexList indexes = selectedIndexes();
|
||||
return indexes.size() == 1 ? indexes.front().row() : -1;
|
||||
}
|
||||
|
||||
void mouseReleaseEvent(QMouseEvent *ev) override
|
||||
{
|
||||
QPoint pos = ev->pos();
|
||||
QModelIndex idx = indexAt(pos);
|
||||
if (OpenEditorsItem *item = m_model.itemForIndexAtLevel<1>(idx))
|
||||
selectEditor(item);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
TreeModel<TreeItem, OpenEditorsItem> m_model;
|
||||
};
|
||||
|
||||
OpenEditorsWindow::OpenEditorsWindow(QWidget *parent) :
|
||||
QFrame(parent, Qt::Popup),
|
||||
m_editorList(new OpenEditorsTreeWidget(this))
|
||||
QFrame(parent, Qt::Popup)
|
||||
{
|
||||
m_editorView = new OpenEditorsView;
|
||||
|
||||
setMinimumSize(300, 200);
|
||||
m_editorList->setColumnCount(1);
|
||||
m_editorList->header()->hide();
|
||||
m_editorList->setIndentation(0);
|
||||
m_editorList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_editorList->setTextElideMode(Qt::ElideMiddle);
|
||||
m_editorView->header()->hide();
|
||||
m_editorView->setIndentation(0);
|
||||
m_editorView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
m_editorView->setTextElideMode(Qt::ElideMiddle);
|
||||
if (Utils::HostOsInfo::isMacHost())
|
||||
m_editorList->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_editorList->installEventFilter(this);
|
||||
m_editorList->setUniformRowHeights(true);
|
||||
m_editorView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_editorView->installEventFilter(this);
|
||||
m_editorView->setUniformRowHeights(true);
|
||||
|
||||
// We disable the frame on this list view and use a QFrame around it instead.
|
||||
// This improves the look with QGTKStyle.
|
||||
if (!Utils::HostOsInfo::isMacHost())
|
||||
setFrameStyle(m_editorList->frameStyle());
|
||||
m_editorList->setFrameStyle(QFrame::NoFrame);
|
||||
setFrameStyle(m_editorView->frameStyle());
|
||||
m_editorView->setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(m_editorList);
|
||||
|
||||
connect(m_editorList, &QTreeWidget::itemClicked,
|
||||
this, &OpenEditorsWindow::editorClicked);
|
||||
layout->addWidget(m_editorView);
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::selectAndHide()
|
||||
{
|
||||
setVisible(false);
|
||||
selectEditor(m_editorList->currentItem());
|
||||
selectEditor(m_editorView->currentItem());
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::setVisible(bool visible)
|
||||
@@ -88,7 +151,7 @@ void OpenEditorsWindow::setVisible(bool visible)
|
||||
|
||||
bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e)
|
||||
{
|
||||
if (obj == m_editorList) {
|
||||
if (obj == m_editorView) {
|
||||
if (e->type() == QEvent::KeyPress) {
|
||||
auto ke = static_cast<QKeyEvent*>(e);
|
||||
if (ke->key() == Qt::Key_Escape) {
|
||||
@@ -97,7 +160,7 @@ bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e)
|
||||
}
|
||||
if (ke->key() == Qt::Key_Return
|
||||
|| ke->key() == Qt::Key_Enter) {
|
||||
selectEditor(m_editorList->currentItem());
|
||||
selectEditor(m_editorView->currentItem());
|
||||
return true;
|
||||
}
|
||||
} else if (e->type() == QEvent::KeyRelease) {
|
||||
@@ -115,18 +178,18 @@ bool OpenEditorsWindow::eventFilter(QObject *obj, QEvent *e)
|
||||
|
||||
void OpenEditorsWindow::focusInEvent(QFocusEvent *)
|
||||
{
|
||||
m_editorList->setFocus();
|
||||
m_editorView->setFocus();
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::selectUpDown(bool up)
|
||||
{
|
||||
int itemCount = m_editorList->topLevelItemCount();
|
||||
int itemCount = m_editorView->m_model.rootItem()->childCount();
|
||||
if (itemCount < 2)
|
||||
return;
|
||||
int index = m_editorList->indexOfTopLevelItem(m_editorList->currentItem());
|
||||
int index = m_editorView->currentRow();
|
||||
if (index < 0)
|
||||
return;
|
||||
QTreeWidgetItem *editor = nullptr;
|
||||
TreeItem *editor = nullptr;
|
||||
int count = 0;
|
||||
while (!editor && count < itemCount) {
|
||||
if (up) {
|
||||
@@ -138,11 +201,12 @@ void OpenEditorsWindow::selectUpDown(bool up)
|
||||
if (index >= itemCount)
|
||||
index = 0;
|
||||
}
|
||||
editor = m_editorList->topLevelItem(index);
|
||||
editor = m_editorView->m_model.rootItem()->childAt(index);
|
||||
count++;
|
||||
}
|
||||
if (editor) {
|
||||
m_editorList->setCurrentItem(editor);
|
||||
// m_editorView->setCurrentItem(editor);
|
||||
m_editorView->setCurrentIndex(m_editorView->m_model.index(index, 0));
|
||||
ensureCurrentVisible();
|
||||
}
|
||||
}
|
||||
@@ -154,7 +218,7 @@ void OpenEditorsWindow::selectPreviousEditor()
|
||||
|
||||
QSize OpenEditorsWindow::sizeHint() const
|
||||
{
|
||||
return m_editorList->sizeHint() + QSize(frameWidth() * 2, frameWidth() * 2);
|
||||
return m_editorView->sizeHint() + QSize(frameWidth() * 2, frameWidth() * 2);
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::selectNextEditor()
|
||||
@@ -164,7 +228,7 @@ void OpenEditorsWindow::selectNextEditor()
|
||||
|
||||
void OpenEditorsWindow::setEditors(const QList<EditLocation> &globalHistory, EditorView *view)
|
||||
{
|
||||
m_editorList->clear();
|
||||
m_editorView->m_model.clear();
|
||||
|
||||
QSet<const DocumentModel::Entry *> entriesDone;
|
||||
addHistoryItems(view->editorHistory(), view, entriesDone);
|
||||
@@ -176,26 +240,9 @@ void OpenEditorsWindow::setEditors(const QList<EditLocation> &globalHistory, Edi
|
||||
addRemainingItems(view, entriesDone);
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::selectEditor(QTreeWidgetItem *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
auto entry = item->data(0, int(Role::Entry)).value<DocumentModel::Entry *>();
|
||||
QTC_ASSERT(entry, return);
|
||||
auto view = item->data(0, int(Role::View)).value<EditorView *>();
|
||||
if (!EditorManagerPrivate::activateEditorForEntry(view, entry))
|
||||
delete item;
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::editorClicked(QTreeWidgetItem *item)
|
||||
{
|
||||
selectEditor(item);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
void OpenEditorsWindow::ensureCurrentVisible()
|
||||
{
|
||||
m_editorList->scrollTo(m_editorList->currentIndex(), QAbstractItemView::PositionAtCenter);
|
||||
m_editorView->scrollTo(m_editorView->currentIndex(), QAbstractItemView::PositionAtCenter);
|
||||
}
|
||||
|
||||
static DocumentModel::Entry *entryForEditLocation(const EditLocation &item)
|
||||
@@ -228,23 +275,14 @@ void OpenEditorsWindow::addItem(DocumentModel::Entry *entry,
|
||||
{
|
||||
if (!Utils::insert(entriesDone, entry))
|
||||
return;
|
||||
QString title = entry->displayName();
|
||||
QTC_ASSERT(!title.isEmpty(), return);
|
||||
auto item = new QTreeWidgetItem();
|
||||
if (entry->document->isModified())
|
||||
title += Tr::tr("*");
|
||||
item->setIcon(0, !entry->filePath().isEmpty() && entry->document->isFileReadOnly()
|
||||
? DocumentModel::lockedIcon() : Utils::FileIconProvider::icon(entry->filePath()));
|
||||
item->setText(0, title);
|
||||
item->setToolTip(0, entry->filePath().toString());
|
||||
item->setData(0, int(Role::Entry), QVariant::fromValue(entry));
|
||||
item->setData(0, int(Role::View), QVariant::fromValue(view));
|
||||
item->setTextAlignment(0, Qt::AlignLeft);
|
||||
|
||||
m_editorList->addTopLevelItem(item);
|
||||
auto item = new OpenEditorsItem;
|
||||
item->entry = entry;
|
||||
item->view = view;
|
||||
m_editorView->m_model.rootItem()->appendChild(item);
|
||||
|
||||
if (m_editorList->topLevelItemCount() == 1)
|
||||
m_editorList->setCurrentItem(item);
|
||||
if (m_editorView->m_model.rootItem()->childCount() == 1)
|
||||
m_editorView->setCurrentIndex(m_editorView->m_model.index(0, 0));
|
||||
}
|
||||
|
||||
} // Core::Internal
|
||||
|
||||
@@ -9,12 +9,11 @@
|
||||
#include <QFrame>
|
||||
#include <QList>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QTreeWidgetItem;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Core::Internal {
|
||||
|
||||
class OpenEditorsItem;
|
||||
class OpenEditorsView;
|
||||
|
||||
class OpenEditorsWindow : public QFrame
|
||||
{
|
||||
public:
|
||||
@@ -34,8 +33,7 @@ public:
|
||||
void selectAndHide();
|
||||
|
||||
private:
|
||||
void editorClicked(QTreeWidgetItem *item);
|
||||
static void selectEditor(QTreeWidgetItem *item);
|
||||
void editorClicked(OpenEditorsItem *item);
|
||||
|
||||
void addHistoryItems(const QList<EditLocation> &history, EditorView *view,
|
||||
QSet<const DocumentModel::Entry *> &entriesDone);
|
||||
@@ -46,7 +44,7 @@ private:
|
||||
void ensureCurrentVisible();
|
||||
void selectUpDown(bool up);
|
||||
|
||||
class OpenEditorsTreeWidget *m_editorList;
|
||||
OpenEditorsView *m_editorView;
|
||||
};
|
||||
|
||||
} // Core::Internal
|
||||
|
||||
Reference in New Issue
Block a user