Skip to content

Commit d1fb249

Browse files
committed
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.
1 parent c606abc commit d1fb249

File tree

5 files changed

+95
-23
lines changed

5 files changed

+95
-23
lines changed

python/gui/qgsfilewidget.sip

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ class QgsFileWidget : QWidget
3030
enum StorageMode
3131
{
3232
GetFile,
33-
GetDirectory
33+
GetDirectory,
34+
GetMultipleFiles,
3435
};
3536

3637
enum RelativeStorage
@@ -72,7 +73,7 @@ returns the open file dialog title
7273
setDialogTitle defines the open file dialog title
7374
.. note::
7475

75-
if not defined, the title is "Select a file" or "Select a directory" depending on the configuration.
76+
if not defined, the title is "Select a file" or "Select a directory" or "Select one or more files" depending on the configuration.
7677
%End
7778

7879
QString filter() const;

src/gui/qgsfilewidget.cpp

+57-14
Original file line numberDiff line numberDiff line change
@@ -231,25 +231,40 @@ void QgsFileWidget::openFileDialog()
231231

232232
// Handle Storage
233233
QString fileName;
234+
QStringList fileNames;
234235
QString title;
235236
if ( mStorageMode == GetFile )
236237
{
237238
title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select a file" );
238239
fileName = QFileDialog::getOpenFileName( this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter );
239240
}
241+
else if ( mStorageMode == GetMultipleFiles )
242+
{
243+
title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select one ore more files" );
244+
fileNames = QFileDialog::getOpenFileNames( this, title, QFileInfo( oldPath ).absoluteFilePath(), mFilter );
245+
}
240246
else if ( mStorageMode == GetDirectory )
241247
{
242248
title = !mDialogTitle.isEmpty() ? mDialogTitle : tr( "Select a directory" );
243249
fileName = QFileDialog::getExistingDirectory( this, title, QFileInfo( oldPath ).absoluteFilePath(), QFileDialog::ShowDirsOnly );
244250
}
245251

246-
if ( fileName.isEmpty() )
252+
if ( fileName.isEmpty() && fileNames.isEmpty( ) )
247253
return;
248254

255+
if ( mStorageMode != GetMultipleFiles )
256+
{
257+
fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
258+
}
259+
else
260+
{
261+
for ( int i = 0; i < fileNames.length(); i++ )
262+
{
263+
fileNames.replace( i, QDir::cleanPath( QFileInfo( fileNames.at( i ) ).absoluteFilePath() ) ) ;
264+
}
265+
}
249266

250-
fileName = QDir::toNativeSeparators( QDir::cleanPath( QFileInfo( fileName ).absoluteFilePath() ) );
251267
// Store the last used path:
252-
253268
if ( mStorageMode == GetFile )
254269
{
255270
settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), QFileInfo( fileName ).absolutePath() );
@@ -258,12 +273,26 @@ void QgsFileWidget::openFileDialog()
258273
{
259274
settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), fileName );
260275
}
276+
else if ( mStorageMode == GetMultipleFiles )
277+
{
278+
settings.setValue( QStringLiteral( "UI/lastFileNameWidgetDir" ), fileNames.first( ) );
279+
}
261280

262281
// Handle relative Path storage
263-
fileName = relativePath( fileName, true );
264-
265-
// Keep the new value
266-
setFilePath( fileName );
282+
if ( mStorageMode != GetMultipleFiles )
283+
{
284+
fileName = relativePath( fileName, true );
285+
// Keep the new value
286+
setFilePath( fileName );
287+
}
288+
else
289+
{
290+
for ( int i = 0; i < fileNames.length(); i++ )
291+
{
292+
fileNames.replace( i, relativePath( fileNames.at( i ), true ) );
293+
}
294+
setFilePath( QStringLiteral( "\"%1\"" ).arg( fileNames.join( "\" \"" ) ) );
295+
}
267296
}
268297

269298

@@ -359,16 +388,30 @@ void QgsFileDropEdit::setFilters( const QString &filters )
359388

360389
QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event ) const
361390
{
362-
QString path;
391+
QStringList paths;
363392
if ( event->mimeData()->hasUrls() )
364393
{
365-
QFileInfo file( event->mimeData()->urls().first().toLocalFile() );
366-
if ( ( mStorageMode == QgsFileWidget::GetFile && file.isFile() &&
367-
( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
368-
|| ( mStorageMode == QgsFileWidget::GetDirectory && file.isDir() ) )
369-
path = file.filePath();
394+
for ( const auto url : event->mimeData()->urls() )
395+
{
396+
QFileInfo file( url.toLocalFile() );
397+
if ( ( mStorageMode != QgsFileWidget::GetDirectory && file.isFile() &&
398+
( mAcceptableExtensions.isEmpty() || mAcceptableExtensions.contains( file.suffix(), Qt::CaseInsensitive ) ) )
399+
|| ( mStorageMode == QgsFileWidget::GetDirectory && file.isDir() ) )
400+
paths.append( file.filePath() );
401+
}
402+
}
403+
if ( paths.size() > 1 )
404+
{
405+
return QStringLiteral( "\"%1\"" ).arg( paths.join( "\" \"" ) );
406+
}
407+
else if ( paths.size() == 1 )
408+
{
409+
return paths.first();
410+
}
411+
else
412+
{
413+
return QString();
370414
}
371-
return path;
372415
}
373416

374417
void QgsFileDropEdit::dragEnterEvent( QDragEnterEvent *event )

src/gui/qgsfilewidget.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ class GUI_EXPORT QgsFileWidget : public QWidget
6161
*/
6262
enum StorageMode
6363
{
64-
GetFile,
65-
GetDirectory
64+
GetFile, //! Select a single file
65+
GetDirectory, //! Select a directory
66+
GetMultipleFiles, //! Select multiple files
6667
};
6768

6869
/**
@@ -94,7 +95,7 @@ class GUI_EXPORT QgsFileWidget : public QWidget
9495

9596
/**
9697
* \brief setDialogTitle defines the open file dialog title
97-
* \note if not defined, the title is "Select a file" or "Select a directory" depending on the configuration.
98+
* \note if not defined, the title is "Select a file" or "Select a directory" or "Select one or more files" depending on the configuration.
9899
*/
99100
void setDialogTitle( const QString &title );
100101

src/providers/gdal/qgsgdalsourceselect.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ QgsGdalSourceSelect::QgsGdalSourceSelect( QWidget *parent, Qt::WindowFlags fl, Q
2424
setupUi( this );
2525
setupButtons( buttonBox );
2626
mQgsFileWidget->setFilter( QgsProviderRegistry::instance()->fileRasterFilters() );
27+
mQgsFileWidget->setStorageMode( QgsFileWidget::GetMultipleFiles );
2728
connect( mQgsFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
2829
{
2930
mRasterPath = path;
@@ -38,8 +39,19 @@ QgsGdalSourceSelect::~QgsGdalSourceSelect()
3839

3940
void QgsGdalSourceSelect::addButtonClicked()
4041
{
41-
QFileInfo baseName( mRasterPath );
42-
emit addRasterLayer( mRasterPath, baseName.baseName(), QStringLiteral( "gdal" ) );
42+
// Check if multiple files where selected
43+
if ( mRasterPath.startsWith( '"' ) )
44+
{
45+
for ( QString path : mRasterPath.split( QRegExp( "\"\\s+\"" ), QString::SkipEmptyParts ) )
46+
{
47+
QString cleanPath( path.remove( '"' ) );
48+
emit addRasterLayer( cleanPath, QFileInfo( cleanPath ).baseName(), QStringLiteral( "gdal" ) );
49+
}
50+
}
51+
else
52+
{
53+
emit addRasterLayer( mRasterPath, QFileInfo( mRasterPath ).baseName(), QStringLiteral( "gdal" ) );
54+
}
4355
}
4456

4557
QGISEXTERN QgsGdalSourceSelect *selectWidget( QWidget *parent, Qt::WindowFlags fl, QgsProviderRegistry::WidgetMode widgetMode )

tests/src/gui/testqgsfilewidget.cpp

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/***************************************************************************
2-
testqgsdoublespinbox.cpp
2+
testqgsfilewidget.cpp
33
--------------------------------------
44
Date : December 2014
55
Copyright : (C) 2014 Nyall Dawson
@@ -27,10 +27,10 @@ class TestQgsFileWidget: public QObject
2727
void cleanupTestCase(); // will be called after the last testfunction was executed.
2828
void init(); // will be called before each testfunction is executed.
2929
void cleanup(); // will be called after every testfunction.
30-
3130
void relativePath();
3231
void toUrl();
3332
void testDroppedFiles();
33+
void testMultipleFiles();
3434

3535
};
3636

@@ -140,5 +140,20 @@ void TestQgsFileWidget::testDroppedFiles()
140140

141141
}
142142

143+
void TestQgsFileWidget::testMultipleFiles()
144+
{
145+
QgsFileWidget *w = new QgsFileWidget();
146+
w->setStorageMode( QgsFileWidget::GetFile );
147+
148+
std::unique_ptr< QMimeData > mime( new QMimeData() );
149+
mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) )
150+
<< QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
151+
std::unique_ptr< QDropEvent > event( new QDropEvent( QPointF( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
152+
153+
qobject_cast< QgsFileDropEdit * >( w->lineEdit() )->dropEvent( event.get() );
154+
QCOMPARE( w->lineEdit()->text(), QStringLiteral( "\"%1\" \"%1\"" ).arg( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );
155+
}
156+
157+
143158
QGSTEST_MAIN( TestQgsFileWidget )
144159
#include "testqgsfilewidget.moc"

0 commit comments

Comments
 (0)