Skip to content

Commit

Permalink
Add widget and dialog for finding files by pattern match, with an
Browse files Browse the repository at this point in the history
optional recursive search
  • Loading branch information
nyalldawson committed Apr 30, 2019
1 parent 5edf06a commit 3f4c3d0
Show file tree
Hide file tree
Showing 6 changed files with 422 additions and 0 deletions.
82 changes: 82 additions & 0 deletions python/gui/auto_generated/qgsfindfilesbypatternwidget.sip.in
@@ -0,0 +1,82 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsfindfilesbypatternwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/





class QgsFindFilesByPatternWidget : QWidget
{
%Docstring
A reusable widget for finding files (recursively) by file pattern.

.. versionadded:: 3.8
%End

%TypeHeaderCode
#include "qgsfindfilesbypatternwidget.h"
%End
public:

QgsFindFilesByPatternWidget( QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsFindFilesByPatternWidget, with the specified ``parent`` widget.
%End

QStringList files() const;
%Docstring
Returns the list of files found by the dialog.

.. seealso:: :py:func:`filesFound`
%End

signals:

void filesFound( const QStringList &files );
%Docstring
Emitted after files are found in the dialog.

.. seealso:: :py:func:`files`
%End

};

class QgsFindFilesByPatternDialog : QDialog
{
%Docstring
A dialog for finding files (recursively) by file pattern.

.. versionadded:: 3.8
%End

%TypeHeaderCode
#include "qgsfindfilesbypatternwidget.h"
%End
public:

QgsFindFilesByPatternDialog( QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsFindFilesByPatternDialog, with the specified ``parent`` widget.
%End

QStringList files() const;
%Docstring
Returns the list of files found by the dialog.

.. seealso:: :py:func:`filesFound`
%End

};

/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/qgsfindfilesbypatternwidget.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
1 change: 1 addition & 0 deletions python/gui/gui_auto.sip
Expand Up @@ -113,6 +113,7 @@
%Include auto_generated/qgsfeatureselectiondlg.sip
%Include auto_generated/qgsfieldcombobox.sip
%Include auto_generated/qgsfieldexpressionwidget.sip
%Include auto_generated/qgsfindfilesbypatternwidget.sip
%Include auto_generated/qgsfeaturelistcombobox.sip
%Include auto_generated/qgsfieldvalidator.sip
%Include auto_generated/qgsfieldvalueslineedit.sip
Expand Down
2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -277,6 +277,7 @@ SET(QGIS_GUI_SRCS
qgsfilecontentsourcelineedit.cpp
qgsfilewidget.cpp
qgsfilterlineedit.cpp
qgsfindfilesbypatternwidget.cpp
qgsfloatingwidget.cpp
qgsfocuswatcher.cpp
qgsfontbutton.cpp
Expand Down Expand Up @@ -452,6 +453,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsfeatureselectiondlg.h
qgsfieldcombobox.h
qgsfieldexpressionwidget.h
qgsfindfilesbypatternwidget.h
qgsfeaturelistcombobox.h
qgsfieldvalidator.h
qgsfieldvalueslineedit.h
Expand Down
147 changes: 147 additions & 0 deletions src/gui/qgsfindfilesbypatternwidget.cpp
@@ -0,0 +1,147 @@
/***************************************************************************
qgsfindfilesbypatternwidget.cpp
-----------------------------
begin : April 2019
copyright : (C) 2019 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsfindfilesbypatternwidget.h"
#include "qgsgui.h"
#include "qgssettings.h"

#include <QDir>
#include <QDirIterator>
#include <QDialogButtonBox>


QgsFindFilesByPatternWidget::QgsFindFilesByPatternWidget( QWidget *parent )
: QWidget( parent )
{
setupUi( this );

mFolderWidget->setStorageMode( QgsFileWidget::GetDirectory );
mResultsTable->setColumnCount( 2 );

mResultsTable->setHorizontalHeaderLabels( QStringList() << tr( "File" ) << tr( "Directory" ) );
mResultsTable->horizontalHeader()->setSectionResizeMode( 0, QHeaderView::Stretch );
mResultsTable->horizontalHeader()->setSectionResizeMode( 1, QHeaderView::Stretch );

connect( mFindButton, &QPushButton::clicked, this, &QgsFindFilesByPatternWidget::find );

QgsSettings settings;
mFolderWidget->setFilePath( settings.value( QStringLiteral( "qgis/lastFindRecursiveFolder" ) ).toString() );
mFindButton->setEnabled( !mFolderWidget->filePath().isEmpty() );
connect( mFolderWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & filePath )
{
QgsSettings settings;
settings.setValue( QStringLiteral( "qgis/lastFindRecursiveFolder" ), filePath );
mFindButton->setEnabled( !filePath.isEmpty() );
} );

}

void QgsFindFilesByPatternWidget::find()
{
mFindButton->setText( tr( "Cancel" ) );
disconnect( mFindButton, &QPushButton::clicked, this, &QgsFindFilesByPatternWidget::find );
connect( mFindButton, &QPushButton::clicked, this, &QgsFindFilesByPatternWidget::cancel );
mCanceled = false;

mResultsTable->setRowCount( 0 );
mFiles.clear();

const QString pattern = mPatternLineEdit->text();
const QString path = mFolderWidget->filePath();

QDir startDir( path );

QStringList filter;
if ( !pattern.isEmpty() )
filter << pattern;

QDirIterator it( path, filter, QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot, mRecursiveCheckBox->isChecked() ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags );
QStringList files;
while ( it.hasNext() )
{
const QString fullPath = it.next();
mFiles << fullPath;

QFileInfo fi( fullPath );

const QString toolTip = QDir::toNativeSeparators( fullPath );
const QString fileName = fi.fileName();
const QString relativeDirectory = QDir::toNativeSeparators( startDir.relativeFilePath( fi.dir().absolutePath() ) );
const QString fullDirectory = QDir::toNativeSeparators( fi.dir().absolutePath() );

QTableWidgetItem *fileNameItem = new QTableWidgetItem( fileName );
fileNameItem->setToolTip( toolTip );
fileNameItem->setFlags( fileNameItem->flags() ^ Qt::ItemIsEditable );

QTableWidgetItem *directoryItem = new QTableWidgetItem( relativeDirectory );
directoryItem->setToolTip( fullDirectory );
directoryItem->setFlags( directoryItem->flags() ^ Qt::ItemIsEditable );

const int row = mResultsTable->rowCount();
mResultsTable->insertRow( row );
mResultsTable->setItem( row, 0, fileNameItem );
mResultsTable->setItem( row, 1, directoryItem );

QCoreApplication::processEvents();
if ( mCanceled )
break;
}

mFindButton->setText( tr( "Find Files" ) );
disconnect( mFindButton, &QPushButton::clicked, this, &QgsFindFilesByPatternWidget::cancel );
connect( mFindButton, &QPushButton::clicked, this, &QgsFindFilesByPatternWidget::find );

emit filesFound( mFiles );
}

void QgsFindFilesByPatternWidget::cancel()
{
mCanceled = true;
}


//
// QgsFindFilesByPatternDialog
//

QgsFindFilesByPatternDialog::QgsFindFilesByPatternDialog( QWidget *parent )
: QDialog( parent )
{
setWindowTitle( tr( "Find Files by Pattern" ) );
setObjectName( "QgsFindFilesByPatternDialog" );

QgsGui::enableAutoGeometryRestore( this );

QVBoxLayout *vLayout = new QVBoxLayout();
mWidget = new QgsFindFilesByPatternWidget();

vLayout->addWidget( mWidget );
mButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal );
connect( mButtonBox, &QDialogButtonBox::accepted, this, &QDialog::accept );
connect( mButtonBox, &QDialogButtonBox::rejected, this, &QDialog::reject );
vLayout->addWidget( mButtonBox );
setLayout( vLayout );

mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( false );
connect( mWidget, &QgsFindFilesByPatternWidget::filesFound, this, [ = ]( const QStringList & files )
{
mButtonBox->button( QDialogButtonBox::Ok )->setEnabled( !files.empty() );
} );
}

QStringList QgsFindFilesByPatternDialog::files() const
{
return mWidget->files();
}
99 changes: 99 additions & 0 deletions src/gui/qgsfindfilesbypatternwidget.h
@@ -0,0 +1,99 @@
/***************************************************************************
qgsfindfilesbypatternwidget.h
-----------------------------
begin : April 2019
copyright : (C) 2019 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSFINDFILESBYPATTERNWIDGET_H
#define QGSFINDFILESBYPATTERNWIDGET_H

#include "ui_qgsfindfilesbypatternwidget.h"
#include "qgis_gui.h"

#include <QDialog>

class QDialogButtonBox;

/**
* \class QgsFindFilesByPatternWidget
* \ingroup gui
* A reusable widget for finding files (recursively) by file pattern.
* \since QGIS 3.8
*/
class GUI_EXPORT QgsFindFilesByPatternWidget : public QWidget, private Ui::QgsFindFilesByPatternWidgetBase
{
Q_OBJECT

public:

/**
* Constructor for QgsFindFilesByPatternWidget, with the specified \a parent widget.
*/
QgsFindFilesByPatternWidget( QWidget *parent SIP_TRANSFERTHIS = nullptr );

/**
* Returns the list of files found by the dialog.
* \see filesFound()
*/
QStringList files() const { return mFiles; }

signals:

/**
* Emitted after files are found in the dialog.
*
* \see files()
*/
void filesFound( const QStringList &files );

private slots:

void find();
void cancel();

private:

bool mCanceled = false;
QStringList mFiles;
};

/**
* \class QgsFindFilesByPatternDialog
* \ingroup gui
* A dialog for finding files (recursively) by file pattern.
* \since QGIS 3.8
*/
class GUI_EXPORT QgsFindFilesByPatternDialog : public QDialog
{
Q_OBJECT

public:

/**
* Constructor for QgsFindFilesByPatternDialog, with the specified \a parent widget.
*/
QgsFindFilesByPatternDialog( QWidget *parent SIP_TRANSFERTHIS = nullptr );

/**
* Returns the list of files found by the dialog.
* \see filesFound()
*/
QStringList files() const;

private:

QgsFindFilesByPatternWidget *mWidget = nullptr;
QDialogButtonBox *mButtonBox = nullptr;

};

#endif // QGSFINDFILESBYPATTERNWIDGET_H

0 comments on commit 3f4c3d0

Please sign in to comment.