Qt 5.9 | Qt Widgets | Find Files Example | window.cpp Example File

Qt 5.9.9 Reference Documentation

# 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
      }