Improve the findfiles example: use QDirIterator, etc

It hasn't been necessary for a long time now to write the recursive
file-find function manually.  It has just been an obscurely documented
feature of QDirIterator for far too long.

Demonstrate the new QLocale::formattedDataSize() function.

Also sync up the qdoc description of this example with the recent changes.

Change-Id: I9c2bb15bb5ec353d38181b160f0be198774cbea2
Reviewed-by: Robin Burchell <robin.burchell@crimson.no>
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
This commit is contained in:
Shawn Rutledge 2017-05-09 12:42:18 +02:00
parent c4f397ee11
commit 0c4d31d8c9
3 changed files with 46 additions and 54 deletions

View File

@ -74,6 +74,7 @@ static inline void openFile(const QString &fileName)
Window::Window(QWidget *parent) Window::Window(QWidget *parent)
: QWidget(parent) : QWidget(parent)
{ {
setWindowTitle(tr("Find Files"));
QPushButton *browseButton = new QPushButton(tr("&Browse..."), this); QPushButton *browseButton = new QPushButton(tr("&Browse..."), this);
connect(browseButton, &QAbstractButton::clicked, this, &Window::browse); connect(browseButton, &QAbstractButton::clicked, this, &Window::browse);
findButton = new QPushButton(tr("&Find"), this); findButton = new QPushButton(tr("&Find"), this);
@ -92,9 +93,7 @@ Window::Window(QWidget *parent)
filesFoundLabel = new QLabel; filesFoundLabel = new QLabel;
createFilesTable(); createFilesTable();
//! [0]
//! [1]
QGridLayout *mainLayout = new QGridLayout(this); QGridLayout *mainLayout = new QGridLayout(this);
mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0); mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0);
mainLayout->addWidget(fileComboBox, 0, 1, 1, 2); mainLayout->addWidget(fileComboBox, 0, 1, 1, 2);
@ -106,12 +105,13 @@ Window::Window(QWidget *parent)
mainLayout->addWidget(filesTable, 3, 0, 1, 3); mainLayout->addWidget(filesTable, 3, 0, 1, 3);
mainLayout->addWidget(filesFoundLabel, 4, 0, 1, 2); mainLayout->addWidget(filesFoundLabel, 4, 0, 1, 2);
mainLayout->addWidget(findButton, 4, 2); mainLayout->addWidget(findButton, 4, 2);
//! [0]
setWindowTitle(tr("Find Files"));
const QRect screenGeometry = QApplication::desktop()->screenGeometry(this);
resize(screenGeometry.width() / 2, screenGeometry.height() / 3);
}
//! [1] //! [1]
connect(new QShortcut(QKeySequence::Quit, this), &QShortcut::activated,
qApp, &QApplication::quit);
//! [1]
}
//! [2] //! [2]
void Window::browse() void Window::browse()
@ -133,21 +133,7 @@ static void updateComboBox(QComboBox *comboBox)
comboBox->addItem(comboBox->currentText()); comboBox->addItem(comboBox->currentText());
} }
//! [13]
static void findRecursion(const QString &path, const QString &pattern, QStringList *result)
{
QDir currentDir(path);
const QString prefix = path + QLatin1Char('/');
foreach (const QString &match, currentDir.entryList(QStringList(pattern), QDir::Files | QDir::NoSymLinks))
result->append(prefix + match);
foreach (const QString &dir, currentDir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot))
findRecursion(prefix + dir, pattern, result);
}
//! [13]
//! [3] //! [3]
void Window::find() void Window::find()
{ {
filesTable->setRowCount(0); filesTable->setRowCount(0);
@ -155,6 +141,7 @@ void Window::find()
QString fileName = fileComboBox->currentText(); QString fileName = fileComboBox->currentText();
QString text = textComboBox->currentText(); QString text = textComboBox->currentText();
QString path = QDir::cleanPath(directoryComboBox->currentText()); QString path = QDir::cleanPath(directoryComboBox->currentText());
currentDir = QDir(path);
//! [3] //! [3]
updateComboBox(fileComboBox); updateComboBox(fileComboBox);
@ -162,12 +149,16 @@ void Window::find()
updateComboBox(directoryComboBox); updateComboBox(directoryComboBox);
//! [4] //! [4]
QStringList filter;
currentDir = QDir(path); if (!fileName.isEmpty())
filter << fileName;
QDirIterator it(path, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
QStringList files; QStringList files;
findRecursion(path, fileName.isEmpty() ? QStringLiteral("*") : fileName, &files); while (it.hasNext())
files << it.next();
if (!text.isEmpty()) if (!text.isEmpty())
files = findFiles(files, text); files = findFiles(files, text);
files.sort();
showFiles(files); showFiles(files);
} }
//! [4] //! [4]
@ -225,20 +216,18 @@ QStringList Window::findFiles(const QStringList &files, const QString &text)
//! [7] //! [7]
//! [8] //! [8]
void Window::showFiles(const QStringList &files) void Window::showFiles(const QStringList &paths)
{ {
for (int i = 0; i < files.size(); ++i) { for (const QString &filePath : paths) {
const QString &fileName = files.at(i); const QString toolTip = QDir::toNativeSeparators(filePath);
const QString toolTip = QDir::toNativeSeparators(fileName); const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(filePath));
const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(fileName)); const qint64 size = QFileInfo(filePath).size();
const qint64 size = QFileInfo(fileName).size();
QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath); QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath);
fileNameItem->setData(absoluteFileNameRole, QVariant(fileName)); fileNameItem->setData(absoluteFileNameRole, QVariant(filePath));
fileNameItem->setToolTip(toolTip); fileNameItem->setToolTip(toolTip);
fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable); fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable);
QTableWidgetItem *sizeItem = new QTableWidgetItem(tr("%1 KB") QTableWidgetItem *sizeItem = new QTableWidgetItem(QLocale().formattedDataSize(size));
.arg(int((size + 1023) / 1024))); sizeItem->setData(absoluteFileNameRole, QVariant(filePath));
sizeItem->setData(absoluteFileNameRole, QVariant(fileName));
sizeItem->setToolTip(toolTip); sizeItem->setToolTip(toolTip);
sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable); sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable);
@ -248,7 +237,7 @@ void Window::showFiles(const QStringList &files)
filesTable->setItem(row, 0, fileNameItem); filesTable->setItem(row, 0, fileNameItem);
filesTable->setItem(row, 1, sizeItem); filesTable->setItem(row, 1, sizeItem);
} }
filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", 0, files.size())); filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", 0, paths.size()));
filesFoundLabel->setWordWrap(true); filesFoundLabel->setWordWrap(true);
} }
//! [8] //! [8]

View File

@ -79,7 +79,7 @@ private slots:
private: private:
QStringList findFiles(const QStringList &files, const QString &text); QStringList findFiles(const QStringList &files, const QString &text);
void showFiles(const QStringList &files); void showFiles(const QStringList &paths);
QComboBox *createComboBox(const QString &text = QString()); QComboBox *createComboBox(const QString &text = QString());
void createFilesTable(); void createFilesTable();

View File

@ -74,19 +74,23 @@
\snippet dialogs/findfiles/window.cpp 0 \snippet dialogs/findfiles/window.cpp 0
We create the application's buttons using the private \c We create the widgets to build up the UI, and we add them to a main layout
createButton() function. Then we create the comboboxes associated using QGridLayout. We have, however, put the \c Find and \c Quit buttons
with the search specifications, using the private \c and a stretchable space in a separate \l QHBoxLayout first, to make the
createComboBox() function. We also create the application's labels buttons appear in the \c Window widget's bottom right corner.
before we use the private \c createFilesTable() function to create
the table displaying the search results. Alternatively, we could have used Qt Designer to construct a UI file,
and \l {uic} to generate this code.
\snippet dialogs/findfiles/window.cpp 1 \snippet dialogs/findfiles/window.cpp 1
Then we add all the widgets to a main layout using QGridLayout. We We did not create a \l QMenuBar with a \uicontrol Quit menu item; but we
have, however, put the \c Find and \c Quit buttons and a would still like to have a keyboard shortcut for quitting. Since we
stretchable space in a separate QHBoxLayout first, to make the construct a \l QShortcut with \l QKeySequence::Quit, and connect it to
buttons appear in the \c Window widget's bottom right corner. \l QApplication::quit(), on most platforms it will be possible to press
Control-Q to quit (or whichever standard Quit key is configured on that platform).
(On \macos, this is redundant, because every application gets a
\uicontrol Quit menu item automatically; but it helps to make the application portable.)
\snippet dialogs/findfiles/window.cpp 2 \snippet dialogs/findfiles/window.cpp 2
@ -122,18 +126,16 @@
We use the directory's path to create a QDir; the QDir class We use the directory's path to create a QDir; the QDir class
provides access to directory structures and their contents. provides access to directory structures and their contents.
\snippet dialogs/findfiles/window.cpp 13 We use QDirIterator to iterate over the files that match the
specified file name and build a QStringList of paths.
We recursively create a list of the files (contained in the newl
created QDir) that match the specified file name.
Then we search through all the files in the list, using the private Then we search through all the files in the list, using the private
\c findFiles() function, eliminating the ones that don't contain \c findFiles() function, eliminating the ones that don't contain the
the specified text. And finally, we display the results using the specified text. We sort them (because QDirIterator did not). And finally,
private \c showFiles() function. we display the results using the private \c showFiles() function.
If the user didn't specify any text, there is no reason to search If the user didn't specify any text, there is no reason to search
through the files, and we display the results immediately. through the files, so we sort and display the results immediately.
\image findfiles_progress_dialog.png Screenshot of the Progress Dialog \image findfiles_progress_dialog.png Screenshot of the Progress Dialog
@ -196,7 +198,8 @@
the \c find() slot. In the \c showFiles() function we run through the \c find() slot. In the \c showFiles() function we run through
the provided list of file names, adding each relative file name to the the provided list of file names, adding each relative file name to the
first column in the table widget and retrieving the file's size using first column in the table widget and retrieving the file's size using
QFileInfo for the second column. For later use, we set QFileInfo for the second column. We use \l QLocale::formattedDataSize()
to format the file size in a human-readable form. For later use, we set
the absolute path as a data on the QTableWidget using the the absolute path as a data on the QTableWidget using the
the role absoluteFileNameRole defined to be Qt::UserRole + 1. the role absoluteFileNameRole defined to be Qt::UserRole + 1.