Skip to content

Commit 083c7ec

Browse files
committed
FilesList: use a simpler list
Instead of using a QListItem, this code will use a new model, which is an enhanced QStringModel. This reduced memory footprint in my test case (a dir with 130k files). In this measurement, I open the ide with no project, load that project, unload and load again. I measured the memory usage as displayed by `btop` (in MB). Before: * before load 176M * after load 468M * after unload 442M * after load2 581M * after unload2 551M After: * before load 177M * after load 379M * after unload 338M * after load 469M * after unload 367M I see that after the unloads the memory does not drop back to original values. I am unsure if this is a bug (memory leak) in my code, or some internal Qt cache (as values differs between runs). This is a good fix anyway.
1 parent 5e85aed commit 083c7ec

File tree

2 files changed

+68
-28
lines changed

2 files changed

+68
-28
lines changed

src/widgets/FilesList.cpp

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include <QElapsedTimer>
1616
#include <QFileInfo>
1717
#include <QLineEdit>
18-
#include <QListWidget>
18+
#include <QListView>
1919
#include <QQueue>
2020
#include <QRegularExpression>
2121
#include <QThread>
@@ -74,7 +74,7 @@ void FileScannerWorker::start() {
7474

7575
void FileScannerWorker::scanDir(const QString &rootPath) {
7676
auto chunk = QStringList();
77-
auto const chunkSize = 2000;
77+
auto const chunkSize = 1000;
7878
auto queue = QQueue<QString>();
7979
queue.enqueue(rootPath);
8080

@@ -109,12 +109,13 @@ void FileScannerWorker::scanDir(const QString &rootPath) {
109109
FilesList::FilesList(QWidget *parent) : QWidget(parent) {
110110
auto layout = new QVBoxLayout(this);
111111
layout->setContentsMargins(0, 0, 0, 0);
112-
displayList = new QListWidget(this);
113112
excludeEdit = new QLineEdit(this);
114113
showEdit = new QLineEdit(this);
115114
loadingWidget = new LoadingWidget(this);
116-
115+
filesModel = new FilesListModel();
116+
displayList = new QListView(this);
117117
displayList->setAlternatingRowColors(true);
118+
displayList->setModel(filesModel);
118119

119120
showEdit->setClearButtonEnabled(true);
120121
showEdit->setPlaceholderText(tr("Files to show (e.g. main;*.cpp;*.h)"));
@@ -129,8 +130,8 @@ FilesList::FilesList(QWidget *parent) : QWidget(parent) {
129130
layout->addWidget(showEdit);
130131
layout->addWidget(excludeEdit);
131132

132-
connect(displayList, &QListWidget::itemClicked, this, [this](auto *it) {
133-
auto fileName = this->directory + QDir::separator() + it->text();
133+
connect(displayList, &QListView::clicked, this, [this](const QModelIndex &modelIndex) {
134+
auto fileName = this->directory + QDir::separator() + modelIndex.data().toString();
134135
auto fileInfo = QFileInfo(fileName);
135136
fileName = fileInfo.absoluteFilePath();
136137
fileName = QDir::toNativeSeparators(fileName);
@@ -167,7 +168,8 @@ void FilesList::setDir(const QString &dir) {
167168
}
168169
clear();
169170
directory = normalizeDirPath(dir);
170-
171+
filesModel->setBaseDir(dir);
172+
filesModel->clear();
171173
if (worker) {
172174
worker->requestStop();
173175
}
@@ -225,18 +227,12 @@ void FilesList::clear() {
225227
}
226228

227229
allFilesList.clear();
228-
displayList->clear();
230+
filesModel->clear();
229231
loadingWidget->stop();
230232
directory.clear();
231233
}
232234

233-
QStringList FilesList::currentFilteredFiles() const {
234-
auto res = QStringList();
235-
for (auto i = 0; i < displayList->count(); ++i) {
236-
res << displayList->item(i)->text();
237-
}
238-
return res;
239-
}
235+
const QStringList &FilesList::currentFilteredFiles() const { return filesModel->getFiles(); }
240236

241237
void FilesList::scheduleUpdateList() {
242238
if (updateTimer->isActive()) {
@@ -309,21 +305,51 @@ void FilesList::updateList(const QStringList &chunk, bool clearList) {
309305
}
310306
}
311307

308+
QElapsedTimer t1;
309+
t1.start();
312310
filtered.sort(Qt::CaseInsensitive);
311+
qDebug() << QString("Sorting %1 files took %2ms").arg(filtered.count()).arg(t1.elapsed());
313312
QTimer::singleShot(0, this, [this, clearList, filtered]() {
313+
QElapsedTimer t1;
314+
t1.start();
314315
if (clearList) {
315-
this->displayList->clear();
316-
}
317-
for (auto const &rel : filtered) {
318-
auto *item = new QListWidgetItem(QDir::toNativeSeparators(rel));
319-
item->setToolTip(QDir::toNativeSeparators(this->directory + rel));
320-
this->displayList->addItem(item);
316+
this->filesModel->clear();
321317
}
318+
319+
filesModel->addFiles(filtered);
320+
qDebug()
321+
<< QString("Adding %1 files took %2ms").arg(filtered.count()).arg(t1.elapsed());
322322
// auto s = tr("Displaying %1/%2 files").arg(filtered.size()).arg(allFilesList.size());
323323
// loadingWidget->setToolTip(s);
324324
});
325-
if (clearList) {
326-
emit filtersChanged();
327-
}
328325
});
329326
}
327+
328+
void FilesListModel::clear() {
329+
beginResetModel();
330+
displayFiles.clear();
331+
endResetModel();
332+
}
333+
334+
void FilesListModel::setBaseDir(const QString &newBaseDir) { baseDir = newBaseDir; }
335+
336+
void FilesListModel::addFiles(const QStringList &l) {
337+
beginResetModel();
338+
displayFiles.append(l);
339+
endResetModel();
340+
}
341+
342+
int FilesListModel::rowCount(const QModelIndex &) const { return displayFiles.size(); }
343+
344+
QVariant FilesListModel::data(const QModelIndex &index, int role) const {
345+
switch (role) {
346+
case Qt::DisplayRole:
347+
return displayFiles[index.row()];
348+
break;
349+
case Qt::ToolTipRole:
350+
return baseDir + displayFiles[index.row()];
351+
break;
352+
default:
353+
return {};
354+
}
355+
}

src/widgets/FilesList.hpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
#include <QThread>
1313
#include <QTimer>
1414
#include <QWidget>
15+
#include <qabstractitemmodel.h>
1516

1617
class QLineEdit;
17-
class QListWidget;
18+
class QListView;
1819
class FileScannerWorker;
1920
class FileFilterWorker;
2021
class LoadingWidget;
@@ -41,6 +42,19 @@ class FileScannerWorker : public QObject {
4142
bool shouldStop = false;
4243
};
4344

45+
class FilesListModel : public QAbstractListModel {
46+
QString baseDir;
47+
QStringList displayFiles;
48+
49+
public:
50+
void clear();
51+
void setBaseDir(const QString &newBaseDir);
52+
void addFiles(const QStringList &l);
53+
const QStringList &getFiles() const { return displayFiles; }
54+
virtual int rowCount(const QModelIndex &parent) const override;
55+
virtual QVariant data(const QModelIndex &index, int role) const override;
56+
};
57+
4458
class FilesList : public QWidget {
4559
Q_OBJECT
4660
public:
@@ -55,12 +69,11 @@ class FilesList : public QWidget {
5569
void setDir(const QString &dir);
5670
const QString &getDir() const { return directory; };
5771
void clear();
58-
QStringList currentFilteredFiles() const;
72+
const QStringList &currentFilteredFiles() const;
5973
const QStringList &getAllFiles() const { return allFilesList; }
6074

6175
signals:
6276
void fileSelected(const QString &filename);
63-
void filtersChanged();
6477

6578
private slots:
6679
void scheduleUpdateList();
@@ -72,7 +85,8 @@ class FilesList : public QWidget {
7285
const QStringList &showTokens) const;
7386

7487
LoadingWidget *loadingWidget = nullptr;
75-
QListWidget *displayList = nullptr;
88+
FilesListModel *filesModel = nullptr;
89+
QListView *displayList = nullptr;
7690
QLineEdit *excludeEdit = nullptr;
7791
QLineEdit *showEdit = nullptr;
7892
quint64 scanGeneration = 0;

0 commit comments

Comments
 (0)