Allow multiple raster selection from GDAL source select widget

Since I'm using QgsFileWidget I also added
multiple files support to that widget and
tests for this new behavior.
This commit is contained in:
Alessandro Pasotti 2017-08-23 16:17:15 +02:00
parent c606abc702
commit d1fb2490a7
5 changed files with 95 additions and 23 deletions

View File

@ -30,7 +30,8 @@ class QgsFileWidget : QWidget
enum StorageMode enum StorageMode
{ {
GetFile, GetFile,
GetDirectory GetDirectory,
GetMultipleFiles,
}; };
enum RelativeStorage enum RelativeStorage
@ -72,7 +73,7 @@ returns the open file dialog title
setDialogTitle defines the open file dialog title setDialogTitle defines the open file dialog title
.. note:: .. note::
if not defined, the title is "Select a file" or "Select a directory" depending on the configuration. if not defined, the title is "Select a file" or "Select a directory" or "Select one or more files" depending on the configuration.
%End %End
QString filter() const; QString filter() const;

View File

@ -231,25 +231,40 @@ void QgsFileWidget::openFileDialog()
// Handle Storage // Handle Storage
QString fileName; QString fileName;
QStringList fileNames;
QString title; QString title;
if ( mStorageMode == GetFile ) if ( mStorageMode == GetFile )
{ {
title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select a file" ); title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select a file" );
fileName = QFileDialog::getOpenFileName( this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter ); fileName = QFileDialog::getOpenFileName( this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter );
} }
else if ( mStorageMode == GetMultipleFiles )
{
title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select one ore more files" );
fileNames = QFileDialog::getOpenFileNames( this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter );
}
else if ( mStorageMode == GetDirectory ) else if ( mStorageMode == GetDirectory )
{ {
title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select a directory" ); title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select a directory" );
fileName = QFileDialog::getExistingDirectory( this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly ); fileName = QFileDialog::getExistingDirectory( this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly );
} }
if ( fileName.isEmpty() ) if ( fileName.isEmpty() && fileNames.isEmpty( ) )
return; return;
if ( mStorageMode != GetMultipleFiles )
{
fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) ); fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
// Store the last used path: }
else
{
for ( int i = 0; i < fileNames.length(); i++ )
{
fileNames.replace( i, QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) ;
}
}
// Store the last used path:
if ( mStorageMode == GetFile ) if ( mStorageMode == GetFile )
{ {
settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() ); settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
@ -258,13 +273,27 @@ void QgsFileWidget::openFileDialog()
{ {
settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), fileName ); settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), fileName );
} }
else if ( mStorageMode == GetMultipleFiles )
{
settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), fileNames.first( ) );
}
// Handle relative Path storage // Handle relative Path storage
if ( mStorageMode != GetMultipleFiles )
{
fileName = relativePath( fileName, true ); fileName = relativePath( fileName, true );
// Keep the new value // Keep the new value
setFilePath( fileName ); setFilePath( fileName );
} }
else
{
for ( int i = 0; i < fileNames.length(); i++ )
{
fileNames.replace( i, relativePath( fileNames.at( i ), true ) );
}
setFilePath( QStringLiteral( "\"%1\"" ).arg( fileNames.join( "\" \"" ) ) );
}
}
QString QgsFileWidget::relativePath( const QString &filePath, bool removeRelative ) const QString QgsFileWidget::relativePath( const QString &filePath, bool removeRelative ) const
@ -359,16 +388,30 @@ void QgsFileDropEdit::setFilters( const QString &filters )
QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event ) const QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event ) const
{ {
QString path; QStringList paths;
if ( event->mimeData()->hasUrls() ) if ( event->mimeData()->hasUrls() )
{ {
QFileInfo file( event->mimeData()->urls().first().toLocalFile() ); for ( const auto url : event->mimeData()->urls() )
if ( ( mStorageMode == QgsFileWidget::GetFile && file.isFile() && {
QFileInfo file( url.toLocalFile() );
if ( ( mStorageMode != QgsFileWidget::GetDirectory && file.isFile() &&
( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) ) ( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
|| ( mStorageMode == QgsFileWidget::GetDirectory && file.isDir() ) ) || ( mStorageMode == QgsFileWidget::GetDirectory && file.isDir() ) )
path = file.filePath(); paths.append( file.filePath() );
}
}
if ( paths.size() > 1 )
{
return QStringLiteral( "\"%1\"" ).arg( paths.join( "\" \"" ) );
}
else if ( paths.size() == 1 )
{
return paths.first();
}
else
{
return QString();
} }
return path;
} }
void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event ) void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )

View File

@ -61,8 +61,9 @@ class GUI_EXPORT QgsFileWidget : public QWidget
*/ */
enum StorageMode enum StorageMode
{ {
GetFile, GetFile, //! Select a single file
GetDirectory GetDirectory, //! Select a directory
GetMultipleFiles, //! Select multiple files
}; };
/** /**
@ -94,7 +95,7 @@ class GUI_EXPORT QgsFileWidget : public QWidget
/** /**
* \brief setDialogTitle defines the open file dialog title * \brief setDialogTitle defines the open file dialog title
* \note if not defined, the title is "Select a file" or "Select a directory" depending on the configuration. * \note if not defined, the title is "Select a file" or "Select a directory" or "Select one or more files" depending on the configuration.
*/ */
void setDialogTitle( const QString &title ); void setDialogTitle( const QString &title );

View File

@ -24,6 +24,7 @@ QgsGdalSourceSelect::QgsGdalSourceSelect( QWidget *parent, Qt::WindowFlags fl, Q
setupUi( this ); setupUi( this );
setupButtons( buttonBox ); setupButtons( buttonBox );
mQgsFileWidget->setFilter( QgsProviderRegistry::instance()->fileRasterFilters() ); mQgsFileWidget->setFilter( QgsProviderRegistry::instance()->fileRasterFilters() );
mQgsFileWidget->setStorageMode( QgsFileWidget::GetMultipleFiles );
connect( mQgsFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path ) connect( mQgsFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
{ {
mRasterPath = path; mRasterPath = path;
@ -38,8 +39,19 @@ QgsGdalSourceSelect::~QgsGdalSourceSelect()
void QgsGdalSourceSelect::addButtonClicked() void QgsGdalSourceSelect::addButtonClicked()
{ {
QFileInfo baseName( mRasterPath ); // Check if multiple files where selected
emit addRasterLayer( mRasterPath, baseName.baseName(), QStringLiteral( "gdal" ) ); if ( mRasterPath.startsWith( '"' ) )
{
for ( QString path : mRasterPath.split( QRegExp( "\"\\s+\"" ), QString::SkipEmptyParts ) )
{
QString cleanPath( path.remove( '"' ) );
emit addRasterLayer( cleanPath, QFileInfo( cleanPath ).baseName(), QStringLiteral( "gdal" ) );
}
}
else
{
emit addRasterLayer( mRasterPath, QFileInfo( mRasterPath ).baseName(), QStringLiteral( "gdal" ) );
}
} }
QGISEXTERN QgsGdalSourceSelect *selectWidget( QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode widgetMode ) QGISEXTERN QgsGdalSourceSelect *selectWidget( QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode widgetMode )

View File

@ -1,5 +1,5 @@
/*************************************************************************** /***************************************************************************
testqgsdoublespinbox.cpp testqgsfilewidget.cpp
-------------------------------------- --------------------------------------
Date : December 2014 Date : December 2014
Copyright : (C) 2014 Nyall Dawson Copyright : (C) 2014 Nyall Dawson
@ -27,10 +27,10 @@ class TestQgsFileWidget: public QObject
void cleanupTestCase(); // will be called after the last testfunction was executed. void cleanupTestCase(); // will be called after the last testfunction was executed.
void init(); // will be called before each testfunction is executed. void init(); // will be called before each testfunction is executed.
void cleanup(); // will be called after every testfunction. void cleanup(); // will be called after every testfunction.
void relativePath(); void relativePath();
void toUrl(); void toUrl();
void testDroppedFiles(); void testDroppedFiles();
void testMultipleFiles();
}; };
@ -140,5 +140,20 @@ void TestQgsFileWidget::testDroppedFiles()
} }
void TestQgsFileWidget::testMultipleFiles()
{
QgsFileWidget *w = new QgsFileWidget();
w->setStorageMode( QgsFileWidget::GetFile );
std::unique_ptr< QMimeData > mime( new QMimeData() );
mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) )
<< QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
std::unique_ptr< QDropEvent > event( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
QCOMPARE( w->lineEdit()->text(), QStringLiteral( "\"%1\" \"%1\"" ).arg( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
}
QGSTEST_MAIN( TestQgsFileWidget ) QGSTEST_MAIN( TestQgsFileWidget )
#include "testqgsfilewidget.moc" #include "testqgsfilewidget.moc"