Commit b598771b authored by Waqar Ahmed's avatar Waqar Ahmed Committed by Christoph Cullmann
Browse files

Improve quickopen performance

parent 048b1226
/* SPDX-License-Identifier: LGPL-2.0-or-later
SPDX-FileCopyrightText: 2007, 2009 Joseph Wenninger <jowenn@kde.org>
SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
......@@ -39,7 +40,7 @@
#include <kfts_fuzzy_match.h>
class QuickOpenFilterProxyModel : public QSortFilterProxyModel
class QuickOpenFilterProxyModel final : public QSortFilterProxyModel
{
public:
QuickOpenFilterProxyModel(QObject *parent = nullptr)
......@@ -50,38 +51,42 @@ public:
protected:
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override
{
int l = sourceLeft.data(KateQuickOpenModel::Score).toInt();
int r = sourceRight.data(KateQuickOpenModel::Score).toInt();
auto sm = sourceModel();
const int l = static_cast<KateQuickOpenModel *>(sm)->idxScore(sourceLeft);
const int r = static_cast<KateQuickOpenModel *>(sm)->idxScore(sourceRight);
return l < r;
}
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
bool filterAcceptsRow(int sourceRow, const QModelIndex &) const override
{
if (pattern.isEmpty()) {
return true;
}
const auto idx = sourceModel()->index(sourceRow, 0, sourceParent);
const QString name = idx.data(KateQuickOpenModel::FileName).toString();
const QString path = idx.data(KateQuickOpenModel::FilePath).toString();
auto sm = static_cast<KateQuickOpenModel *>(sourceModel());
if (!sm->isValid(sourceRow)) {
return false;
}
const QString &name = sm->idxToFileName(sourceRow);
int score = 0;
bool res = false;
{
int scorep = 0, scoren = 0;
bool resn = filterByName(name, scoren);
// only match file path if filename got a match
bool resp = false;
if (resn || pattern.contains(QLatin1Char('/'))) {
resp = filterByPath(path, scorep);
}
// store the score for sorting later
score = scoren + scorep;
res = resp || resn;
int scorep = 0, scoren = 0;
bool resn = filterByName(name, scoren);
// only match file path if filename got a match
bool resp = false;
if (resn || pathLike) {
const QString &path = sm->idxToFilePath(sourceRow);
resp = filterByPath(path, scorep);
}
sourceModel()->setData(idx, score, KateQuickOpenModel::Score);
// store the score for sorting later
score = scoren + scorep;
res = resp || resn;
sm->setScoreForIndex(sourceRow, score);
return res;
}
......@@ -91,6 +96,7 @@ public Q_SLOTS:
{
beginResetModel();
pattern = text;
pathLike = pattern.contains(QLatin1Char('/'));
endResetModel();
}
......@@ -107,6 +113,7 @@ private:
private:
QString pattern;
bool pathLike = false;
};
class QuickOpenStyleDelegate : public QStyledItemDelegate
......@@ -212,7 +219,7 @@ KateQuickOpen::KateQuickOpen(KateMainWindow *mainWindow)
m_listView->setTextElideMode(Qt::ElideLeft);
m_listView->setUniformRowHeights(true);
m_base_model = new KateQuickOpenModel(m_mainWindow, this);
m_base_model = new KateQuickOpenModel(this);
m_model = new QuickOpenFilterProxyModel(this);
m_model->setFilterRole(Qt::DisplayRole);
......@@ -251,7 +258,7 @@ KateQuickOpen::KateQuickOpen(KateMainWindow *mainWindow)
slotListModeChanged(m_inputLine->listMode());
// fill stuff
update();
update(mainWindow);
}
KateQuickOpen::~KateQuickOpen()
......@@ -314,9 +321,9 @@ void KateQuickOpen::reselectFirst()
m_listView->setCurrentIndex(index);
}
void KateQuickOpen::update()
void KateQuickOpen::update(KateMainWindow *mainWindow)
{
m_base_model->refresh();
m_base_model->refresh(mainWindow);
reselectFirst();
updateViewGeometry();
......@@ -331,6 +338,9 @@ void KateQuickOpen::slotReturnPressed()
m_mainWindow->wrapper()->openUrl(url);
hide();
m_mainWindow->slotWindowActivated();
// block signals for input line so that we dont trigger filtering again
const QSignalBlocker blocker(m_inputLine);
m_inputLine->clear();
}
......
/* SPDX-License-Identifier: LGPL-2.0-or-later
SPDX-FileCopyrightText: 2007, 2009 Joseph Wenninger <jowenn@kde.org>
SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
......@@ -35,7 +36,7 @@ public:
* update state
* will fill model with current open documents, project documents, ...
*/
void update();
void update(KateMainWindow *mainWindow);
void updateViewGeometry();
protected:
......
/* SPDX-License-Identifier: LGPL-2.0-or-later
SPDX-FileCopyrightText: 2018 Tomaz Canabrava <tcanabrava@kde.org>
SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
......@@ -14,11 +15,11 @@
#include <ktexteditor/view.h>
#include <QFileInfo>
#include <QIcon>
#include <QMimeDatabase>
KateQuickOpenModel::KateQuickOpenModel(KateMainWindow *mainWindow, QObject *parent)
KateQuickOpenModel::KateQuickOpenModel(QObject *parent)
: QAbstractTableModel(parent)
, m_mainWindow(mainWindow)
{
}
......@@ -48,7 +49,7 @@ QVariant KateQuickOpenModel::data(const QModelIndex &idx, int role) const
case Role::FileName:
return entry.fileName;
case Role::FilePath:
return entry.filePath;
return QString(entry.filePath).remove(m_projectBase);
case Qt::FontRole: {
if (entry.bold) {
QFont font;
......@@ -60,7 +61,7 @@ QVariant KateQuickOpenModel::data(const QModelIndex &idx, int role) const
case Qt::DecorationRole:
return QIcon::fromTheme(QMimeDatabase().mimeTypeForFile(entry.fileName, QMimeDatabase::MatchExtension).iconName());
case Qt::UserRole:
return entry.url;
return QUrl::fromLocalFile(entry.filePath);
case Role::Score:
return entry.score;
default:
......@@ -70,10 +71,10 @@ QVariant KateQuickOpenModel::data(const QModelIndex &idx, int role) const
return {};
}
void KateQuickOpenModel::refresh()
void KateQuickOpenModel::refresh(KateMainWindow *mainWindow)
{
QObject *projectView = m_mainWindow->pluginView(QStringLiteral("kateprojectplugin"));
const QList<KTextEditor::View *> sortedViews = m_mainWindow->viewManager()->sortedViews();
QObject *projectView = mainWindow->pluginView(QStringLiteral("kateprojectplugin"));
const QList<KTextEditor::View *> sortedViews = mainWindow->viewManager()->sortedViews();
const QList<KTextEditor::Document *> openDocs = KateApp::self()->documentManager()->documentList();
const QStringList projectDocs = projectView
? (m_listMode == CurrentProject ? projectView->property("projectFiles") : projectView->property("allProjectsFiles")).toStringList()
......@@ -94,40 +95,37 @@ void KateQuickOpenModel::refresh()
return ret;
}();
m_projectBase = projectBase;
QVector<ModelEntry> allDocuments;
allDocuments.reserve(sortedViews.size() + projectDocs.size());
QSet<QUrl> openedDocUrls;
QSet<QString> openedDocUrls;
openedDocUrls.reserve(sortedViews.size());
for (auto *view : qAsConst(sortedViews)) {
auto doc = view->document();
const auto url = doc->url();
if (openedDocUrls.contains(url)) {
continue;
}
openedDocUrls.insert(url);
allDocuments.push_back(
{url, doc->documentName(), url.toDisplayString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile).remove(projectBase), true, -1});
auto path = doc->url().toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
openedDocUrls.insert(path);
allDocuments.push_back({doc->documentName(), path, true, -1});
}
for (auto *doc : qAsConst(openDocs)) {
auto url = doc->url();
if (openedDocUrls.contains(url)) {
auto path = doc->url().toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
if (openedDocUrls.contains(path)) {
continue;
}
openedDocUrls.insert(url);
const auto normalizedUrl = url.toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile).remove(projectBase);
allDocuments.push_back({doc->url(), doc->documentName(), normalizedUrl, true, -1});
openedDocUrls.insert(path);
allDocuments.push_back({doc->documentName(), path, true, -1});
}
for (const auto &file : qAsConst(projectDocs)) {
QFileInfo fi(file);
const auto localFile = QUrl::fromLocalFile(fi.absoluteFilePath());
if (openedDocUrls.contains(localFile)) {
// projectDocs items have full path already, reuse that
if (openedDocUrls.contains(file)) {
continue;
}
allDocuments.push_back({localFile, fi.fileName(), fi.filePath().remove(projectBase), false, -1});
allDocuments.push_back({fi.fileName(), file, false, -1});
}
beginResetModel();
......
/* SPDX-License-Identifier: LGPL-2.0-or-later
SPDX-FileCopyrightText: 2018 Tomaz Canabrava <tcanabrava@kde.org>
SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
......@@ -9,15 +10,11 @@
#define KATEQUICKOPENMODEL_H
#include <QAbstractTableModel>
#include <QIcon>
#include <QUrl>
#include <QVariant>
#include <QVector>
class KateMainWindow;
struct ModelEntry {
QUrl url; // used for actually opening a selected file (local or remote)
QString fileName; // display string for left column
QString filePath; // display string for right column
bool bold; // format line in bold text or not
......@@ -32,11 +29,11 @@ class KateQuickOpenModel : public QAbstractTableModel
Q_OBJECT
public:
enum Role { FileName = Qt::UserRole + 1, FilePath, Score };
explicit KateQuickOpenModel(KateMainWindow *mainWindow, QObject *parent = nullptr);
explicit KateQuickOpenModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &idx, int role) const override;
void refresh();
void refresh(KateMainWindow *mainWindow);
// add a convenient in-class alias
using List = KateQuickOpenModelList;
List listMode() const
......@@ -48,27 +45,37 @@ public:
m_listMode = mode;
}
bool setData(const QModelIndex &index, const QVariant &value, int role) override
bool isValid(int row) const
{
if (!index.isValid()) {
return false;
}
if (role == Role::Score) {
auto row = index.row();
m_modelEntries[row].score = value.toInt();
return row >= 0 && row < m_modelEntries.size();
}
void setScoreForIndex(int row, int score)
{
m_modelEntries[row].score = score;
}
const QString &idxToFileName(int row) const
{
return m_modelEntries.at(row).fileName;
}
const QString &idxToFilePath(int row) const
{
return m_modelEntries.at(row).filePath;
}
int idxScore(const QModelIndex &idx) const
{
if (!idx.isValid()) {
return {};
}
return QAbstractTableModel::setData(index, value, role);
return m_modelEntries.at(idx.row()).score;
}
private:
QVector<ModelEntry> m_modelEntries;
/* TODO: don't rely in a pointer to the main window.
* this is bad engineering, but current code is too tight
* on this and it's hard to untangle without breaking existing
* code.
*/
KateMainWindow *m_mainWindow;
QString m_projectBase;
List m_listMode{};
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment