window.cpp Example File
dialogs/findfiles/window.cpp/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the examples of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** BSD License Usage ** Alternatively, you may use this file under the terms of the BSD license ** as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of The Qt Company Ltd nor the names of its ** contributors may be used to endorse or promote products derived ** from this software without specific prior written permission. ** ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include <QtWidgets> #include "window.h" enum { absoluteFileNameRole = Qt::UserRole + 1 }; static inline QString fileNameOfItem(const QTableWidgetItem *item) { return item->data(absoluteFileNameRole).toString(); } static inline void openFile(const QString &fileName) { QDesktopServices::openUrl(QUrl::fromLocalFile(fileName)); } Window::Window(QWidget *parent) : QWidget(parent) { QPushButton *browseButton = new QPushButton(tr("&Browse..."), this); connect(browseButton, &QAbstractButton::clicked, this, &Window::browse); findButton = new QPushButton(tr("&Find"), this); connect(findButton, &QAbstractButton::clicked, this, &Window::find); fileComboBox = createComboBox(tr("*")); connect(fileComboBox->lineEdit(), &QLineEdit::returnPressed, this, &Window::animateFindClick); textComboBox = createComboBox(); connect(textComboBox->lineEdit(), &QLineEdit::returnPressed, this, &Window::animateFindClick); directoryComboBox = createComboBox(QDir::toNativeSeparators(QDir::currentPath())); connect(directoryComboBox->lineEdit(), &QLineEdit::returnPressed, this, &Window::animateFindClick); filesFoundLabel = new QLabel; createFilesTable(); QGridLayout *mainLayout = new QGridLayout(this); mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0); mainLayout->addWidget(fileComboBox, 0, 1, 1, 2); mainLayout->addWidget(new QLabel(tr("Containing text:")), 1, 0); mainLayout->addWidget(textComboBox, 1, 1, 1, 2); mainLayout->addWidget(new QLabel(tr("In directory:")), 2, 0); mainLayout->addWidget(directoryComboBox, 2, 1); mainLayout->addWidget(browseButton, 2, 2); mainLayout->addWidget(filesTable, 3, 0, 1, 3); mainLayout->addWidget(filesFoundLabel, 4, 0, 1, 2); mainLayout->addWidget(findButton, 4, 2); setWindowTitle(tr("Find Files")); const QRect screenGeometry = QApplication::desktop()->screenGeometry(this); resize(screenGeometry.width() / 2, screenGeometry.height() / 3); } void Window::browse() { QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Find Files"), QDir::currentPath())); if (!directory.isEmpty()) { if (directoryComboBox->findText(directory) == -1) directoryComboBox->addItem(directory); directoryComboBox->setCurrentIndex(directoryComboBox->findText(directory)); } } static void updateComboBox(QComboBox *comboBox) { if (comboBox->findText(comboBox->currentText()) == -1) comboBox->addItem(comboBox->currentText()); } 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); } void Window::find() { filesTable->setRowCount(0); QString fileName = fileComboBox->currentText(); QString text = textComboBox->currentText(); QString path = QDir::cleanPath(directoryComboBox->currentText()); updateComboBox(fileComboBox); updateComboBox(textComboBox); updateComboBox(directoryComboBox); currentDir = QDir(path); QStringList files; findRecursion(path, fileName.isEmpty() ? QStringLiteral("*") : fileName, &files); if (!text.isEmpty()) files = findFiles(files, text); showFiles(files); } void Window::animateFindClick() { findButton->animateClick(); } QStringList Window::findFiles(const QStringList &files, const QString &text) { QProgressDialog progressDialog(this); progressDialog.setCancelButtonText(tr("&Cancel")); progressDialog.setRange(0, files.size()); progressDialog.setWindowTitle(tr("Find Files")); QMimeDatabase mimeDatabase; QStringList foundFiles; for (int i = 0; i < files.size(); ++i) { progressDialog.setValue(i); progressDialog.setLabelText(tr("Searching file number %1 of %n...", 0, files.size()).arg(i)); QCoreApplication::processEvents(); if (progressDialog.wasCanceled()) break; const QString fileName = files.at(i); const QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName); if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) { qWarning() << "Not searching binary file " << QDir::toNativeSeparators(fileName); continue; } QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QString line; QTextStream in(&file); while (!in.atEnd()) { if (progressDialog.wasCanceled()) break; line = in.readLine(); if (line.contains(text, Qt::CaseInsensitive)) { foundFiles << files[i]; break; } } } } return foundFiles; } void Window::showFiles(const QStringList &files) { for (int i = 0; i < files.size(); ++i) { const QString &fileName = files.at(i); const QString toolTip = QDir::toNativeSeparators(fileName); const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(fileName)); const qint64 size = QFileInfo(fileName).size(); QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath); fileNameItem->setData(absoluteFileNameRole, QVariant(fileName)); fileNameItem->setToolTip(toolTip); fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable); QTableWidgetItem *sizeItem = new QTableWidgetItem(tr("%1 KB") .arg(int((size + 1023) / 1024))); sizeItem->setData(absoluteFileNameRole, QVariant(fileName)); sizeItem->setToolTip(toolTip); sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable); int row = filesTable->rowCount(); filesTable->insertRow(row); filesTable->setItem(row, 0, fileNameItem); filesTable->setItem(row, 1, sizeItem); } filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", 0, files.size())); filesFoundLabel->setWordWrap(true); } QComboBox *Window::createComboBox(const QString &text) { QComboBox *comboBox = new QComboBox; comboBox->setEditable(true); comboBox->addItem(text); comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); return comboBox; } void Window::createFilesTable() { filesTable = new QTableWidget(0, 2); filesTable->setSelectionBehavior(QAbstractItemView::SelectRows); QStringList labels; labels << tr("Filename") << tr("Size"); filesTable->setHorizontalHeaderLabels(labels); filesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); filesTable->verticalHeader()->hide(); filesTable->setShowGrid(false); filesTable->setContextMenuPolicy(Qt::CustomContextMenu); connect(filesTable, &QTableWidget::customContextMenuRequested, this, &Window::contextMenu); connect(filesTable, &QTableWidget::cellActivated, this, &Window::openFileOfItem); } void Window::openFileOfItem(int row, int /* column */) { const QTableWidgetItem *item = filesTable->item(row, 0); openFile(fileNameOfItem(item)); } void Window::contextMenu(const QPoint &pos) { const QTableWidgetItem *item = filesTable->itemAt(pos); if (!item) return; QMenu menu; #ifndef QT_NO_CLIPBOARD QAction *copyAction = menu.addAction("Copy Name"); #endif QAction *openAction = menu.addAction("Open"); QAction *action = menu.exec(filesTable->mapToGlobal(pos)); if (!action) return; const QString fileName = fileNameOfItem(item); if (action == openAction) openFile(fileName); #ifndef QT_NO_CLIPBOARD else if (action == copyAction) QGuiApplication::clipboard()->setText(QDir::toNativeSeparators(fileName)); #endif }