Skip to content

Commit

Permalink
Rewrite the fetchmore example
Browse files Browse the repository at this point in the history
- Start in root folder so that large directories (/bin/, Windows)
  are easily reachable
- Remove the line edit and navigate by double clicking instead
  since this is more in line with expectations
- Use a QPlainTextEdit for logging
- Make the log message more informative
- Add icons

Change-Id: Ia3cd7fc143efef80772923291f0b711913aa47be
Reviewed-by: Paul Wicking <[email protected]>
  • Loading branch information
FriedemannKleint committed Apr 23, 2021
1 parent 43d6778 commit 2393a40
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 55 deletions.
Binary file modified doc/src/images/fetchmore-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 10 additions & 7 deletions examples/widgets/doc/src/fetchmore.qdoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,25 @@

\image fetchmore-example.png


This example consists of a dialog where you can enter a directory
name in the \uicontrol Directory edit field. The application loads and
visualizes all files it finds as you are typing. It is not required
to press [Enter] to launch the search.

When you have large - or perhaps even infinite - data sets, you
will need to add items to the model in batches, and preferably only
when the items are needed by the view (i.e., when they are visible
when the items are needed by the view (i.e., when they become visible
in the view).

In this example, we implement \c FileListModel - an item view
model containing the entries of a directory. We also have \c
Window, which sets up the GUI and feeds the model with
directories.

The UI consists of a dialog with a list showing the contents
of the root directory. Directories can be navigated by double-clicking.

At the bottom, there is a log window displaying messages when the view
asks the model for more data.

To exercise it, navigate to a large directory (say \c /bin), and scroll
to the bottom. Log messages appear showing the data being retrieved.

Let's take a tour of \c {FileListModel}'s code.

\section1 FileListModel Class Definition
Expand Down
53 changes: 33 additions & 20 deletions examples/widgets/itemviews/fetchmore/filelistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@
#include <QDir>
#include <QPalette>

static const int batchSize = 100;

FileListModel::FileListModel(QObject *parent)
: QAbstractListModel(parent), fileCount(0)
: QAbstractListModel(parent)
{}

//![4]
Expand All @@ -67,24 +69,33 @@ int FileListModel::rowCount(const QModelIndex &parent) const
QVariant FileListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (index.row() >= fileList.size() || index.row() < 0)
return QVariant();

if (role == Qt::DisplayRole) {
return fileList.at(index.row());
} else if (role == Qt::BackgroundRole) {
int batch = (index.row() / 100) % 2;
if (batch == 0)
return qApp->palette().base();
else
return qApp->palette().alternateBase();
return {};

const int row = index.row();
if (row >= fileList.size() || row < 0)
return {};

switch (role) {
case Qt::DisplayRole:
return fileList.at(row).fileName();
case Qt::BackgroundRole: {
const int batch = row / batchSize;
const QPalette &palette = QGuiApplication::palette();
return (batch % 2) != 0 ? palette.alternateBase() : palette.base();
}
case Qt::DecorationRole:
return iconProvider.icon(fileList.at(row));
}
return QVariant();
return {};
}

//![4]

QFileInfo FileListModel::fileInfoAt(const QModelIndex &index) const
{
return fileList.at(index.row());
}

//![1]
bool FileListModel::canFetchMore(const QModelIndex &parent) const
{
Expand All @@ -99,19 +110,20 @@ void FileListModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid())
return;
int remainder = fileList.size() - fileCount;
int itemsToFetch = qMin(100, remainder);
const int start = fileCount;
const int remainder = int(fileList.size()) - start;
const int itemsToFetch = qMin(batchSize, remainder);

if (itemsToFetch <= 0)
return;

beginInsertRows(QModelIndex(), fileCount, fileCount + itemsToFetch - 1);
beginInsertRows(QModelIndex(), start, start + itemsToFetch - 1);

fileCount += itemsToFetch;

endInsertRows();

emit numberPopulated(itemsToFetch);
emit numberPopulated(path, start, itemsToFetch, int(fileList.size()));
}
//![2]

Expand All @@ -121,7 +133,8 @@ void FileListModel::setDirPath(const QString &path)
QDir dir(path);

beginResetModel();
fileList = dir.entryList();
this->path = path;
fileList = dir.entryInfoList(QDir::NoDot | QDir::AllEntries, QDir::Name);
fileCount = 0;
endResetModel();
}
Expand Down
13 changes: 9 additions & 4 deletions examples/widgets/itemviews/fetchmore/filelistmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@
#define FILELISTMODEL_H

#include <QAbstractListModel>
#include <QStringList>
#include <QFileInfoList>
#include <QFileIconProvider>

//![0]
class FileListModel : public QAbstractListModel
Expand All @@ -65,8 +66,10 @@ class FileListModel : public QAbstractListModel
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

QFileInfo fileInfoAt(const QModelIndex &) const;

signals:
void numberPopulated(int number);
void numberPopulated(const QString &path, int start, int number, int total);

public slots:
void setDirPath(const QString &path);
Expand All @@ -76,8 +79,10 @@ public slots:
void fetchMore(const QModelIndex &parent) override;

private:
QStringList fileList;
int fileCount;
QFileInfoList fileList;
QString path;
QFileIconProvider iconProvider;
int fileCount = 0;
};
//![0]

Expand Down
48 changes: 27 additions & 21 deletions examples/widgets/itemviews/fetchmore/window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,37 +56,43 @@
Window::Window(QWidget *parent)
: QWidget(parent)
{
FileListModel *model = new FileListModel(this);
model->setDirPath(QLibraryInfo::path(QLibraryInfo::PrefixPath));
model = new FileListModel(this);
model->setDirPath(QDir::rootPath());

QLabel *label = new QLabel(tr("&Directory:"));
QLineEdit *lineEdit = new QLineEdit;
label->setBuddy(lineEdit);

QListView *view = new QListView;
view = new QListView;
view->setModel(model);

logViewer = new QTextBrowser(this);
logViewer->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
logViewer = new QPlainTextEdit(this);
logViewer->setReadOnly(true);
logViewer->setSizePolicy(QSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Preferred));

connect(lineEdit, &QLineEdit::textChanged,
model, &FileListModel::setDirPath);
connect(lineEdit, &QLineEdit::textChanged,
logViewer, &QTextEdit::clear);
connect(model, &FileListModel::numberPopulated,
this, &Window::updateLog);
connect(view, &QAbstractItemView::activated,
this, &Window::activated);

QGridLayout *layout = new QGridLayout;
layout->addWidget(label, 0, 0);
layout->addWidget(lineEdit, 0, 1);
layout->addWidget(view, 1, 0, 1, 2);
layout->addWidget(logViewer, 2, 0, 1, 2);
auto *layout = new QVBoxLayout(this);
layout->addWidget(view);
layout->addWidget(logViewer);

setLayout(layout);
setWindowTitle(tr("Fetch More Example"));
}

void Window::updateLog(int number)
void Window::updateLog(const QString &path, int start, int number, int total)
{
const int last = start + number - 1;
const QString nativePath = QDir::toNativeSeparators(path);
const QString message = tr("%1..%2/%3 items from \"%4\" added.")
.arg(start).arg(last).arg(total).arg(nativePath);
logViewer->appendPlainText(message);
}

void Window::activated(const QModelIndex &index)
{
logViewer->append(tr("%1 items added.").arg(number));
const QFileInfo fi = model->fileInfoAt(index);
if (fi.isDir()) {
logViewer->clear();
model->setDirPath(fi.absoluteFilePath());
}
}
13 changes: 10 additions & 3 deletions examples/widgets/itemviews/fetchmore/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,13 @@
#include <QWidget>

QT_BEGIN_NAMESPACE
class QTextBrowser;
class QModelIndex;
class QListView;
class QPlainTextEdit;
QT_END_NAMESPACE

class FileListModel;

class Window : public QWidget
{
Q_OBJECT
Expand All @@ -65,10 +69,13 @@ class Window : public QWidget
Window(QWidget *parent = nullptr);

public slots:
void updateLog(int number);
void updateLog(const QString &path, int start, int number, int total);
void activated(const QModelIndex &);

private:
QTextBrowser *logViewer;
QPlainTextEdit *logViewer;
FileListModel *model;
QListView *view;
};

#endif // WINDOW_H

0 comments on commit 2393a40

Please sign in to comment.