Skip to content

Commit

Permalink
Add external storage file widget drag'n drop support
Browse files Browse the repository at this point in the history
  • Loading branch information
troopa81 authored and nyalldawson committed Aug 30, 2021
1 parent be7926e commit 5c35b1c
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 8 deletions.
9 changes: 9 additions & 0 deletions python/gui/auto_generated/qgsexternalstoragefilewidget.sip.in
Expand Up @@ -155,6 +155,9 @@ It defines the variable containing the user selected file name
.. versionadded:: 3.22
%End

virtual void setReadOnly( bool readOnly );


protected:

virtual void updateLayout();
Expand All @@ -168,6 +171,12 @@ It defines the variable containing the user selected file name
Add file widget specific scope to expression context
%End

virtual void dragEnterEvent( QDragEnterEvent *event );


virtual void dropEvent( QDropEvent *event );


};

/************************************************************************
Expand Down
2 changes: 1 addition & 1 deletion python/gui/auto_generated/qgsfilewidget.sip.in
Expand Up @@ -74,7 +74,7 @@ Sets the current file ``path``.
.. seealso:: :py:func:`filePath`
%End

void setReadOnly( bool readOnly );
virtual void setReadOnly( bool readOnly );
%Docstring
Sets whether the widget should be read only.
%End
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgsexternalresourcewidget.cpp
Expand Up @@ -55,6 +55,7 @@ QgsExternalResourceWidget::QgsExternalResourceWidget( QWidget *parent )

#ifdef WITH_QTWEBKIT
mWebView = new QWebView( this );
mWebView->setAcceptDrops( false );
layout->addWidget( mWebView, 2, 0 );
#endif

Expand Down
43 changes: 40 additions & 3 deletions src/gui/qgsexternalstoragefilewidget.cpp
Expand Up @@ -54,7 +54,7 @@ QgsExternalStorageFileWidget::QgsExternalStorageFileWidget( QWidget *parent )
mCancelButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mTaskCancel.svg" ) ) );
mCancelButton->hide();

setLayout( mLayout );
updateAcceptDrops();
}

void QgsExternalStorageFileWidget::setStorageType( const QString &storageType )
Expand All @@ -68,10 +68,25 @@ void QgsExternalStorageFileWidget::setStorageType( const QString &storageType )
if ( !mExternalStorage )
{
QgsDebugMsg( QStringLiteral( "Invalid storage type: %1" ).arg( storageType ) );
return;
}
addFileWidgetScope();
else
{
addFileWidgetScope();
}
}

updateAcceptDrops();
}

void QgsExternalStorageFileWidget::setReadOnly( bool readOnly )
{
QgsFileWidget::setReadOnly( readOnly );
updateAcceptDrops();
}

void QgsExternalStorageFileWidget::updateAcceptDrops()
{
setAcceptDrops( !mReadOnly && mExternalStorage );
}

QString QgsExternalStorageFileWidget::storageType() const
Expand Down Expand Up @@ -201,6 +216,9 @@ void QgsExternalStorageFileWidget::setSelectedFileNames( QStringList fileNames )

void QgsExternalStorageFileWidget::storeExternalFiles( QStringList fileNames, QStringList storedUrls )
{
if ( fileNames.isEmpty() )
return;

const QString filePath = fileNames.takeFirst();

mProgressLabel->setText( tr( "Storing file %1 ..." ).arg( QFileInfo( filePath ).fileName() ) );
Expand Down Expand Up @@ -264,3 +282,22 @@ void QgsExternalStorageFileWidget::storeExternalFiles( QStringList fileNames, QS

storedContent->store();
}

void QgsExternalStorageFileWidget::dragEnterEvent( QDragEnterEvent *event )
{
const QStringList filePaths = mLineEdit->acceptableFilePaths( event );
if ( !filePaths.isEmpty() )
{
event->acceptProposedAction();
}
else
{
event->ignore();
}
}

void QgsExternalStorageFileWidget::dropEvent( QDropEvent *event )
{
storeExternalFiles( mLineEdit->acceptableFilePaths( event ) );
event->acceptProposedAction();
}
9 changes: 9 additions & 0 deletions src/gui/qgsexternalstoragefilewidget.h
Expand Up @@ -159,6 +159,8 @@ class GUI_EXPORT QgsExternalStorageFileWidget : public QgsFileWidget
*/
static QgsExpressionContextScope *createFileWidgetScope();

void setReadOnly( bool readOnly ) override;

protected:

void updateLayout() override;
Expand All @@ -170,6 +172,10 @@ class GUI_EXPORT QgsExternalStorageFileWidget : public QgsFileWidget
*/
void addFileWidgetScope();

void dragEnterEvent( QDragEnterEvent *event ) override;

void dropEvent( QDropEvent *event ) override;

private:

// stores \a fileNames files using current external storage.
Expand All @@ -178,6 +184,9 @@ class GUI_EXPORT QgsExternalStorageFileWidget : public QgsFileWidget
// is updated
void storeExternalFiles( QStringList fileNames, QStringList storedUrls = QStringList() );

//! Update whether the widget accept drop or not
void updateAcceptDrops();

bool mStoreInProgress = false;

QgsExternalStorage *mExternalStorage = nullptr;
Expand Down
8 changes: 7 additions & 1 deletion src/gui/qgsfilewidget.cpp
Expand Up @@ -496,7 +496,7 @@ void QgsFileDropEdit::setFilters( const QString &filters )
}
}

QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event ) const
QStringList QgsFileDropEdit::acceptableFilePaths( QDropEvent *event ) const
{
QStringList rawPaths;
QStringList paths;
Expand Down Expand Up @@ -553,6 +553,12 @@ QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event ) const
}
}

return paths;
}

QString QgsFileDropEdit::acceptableFilePath( QDropEvent *event ) const
{
const QStringList paths = acceptableFilePaths( event );
if ( paths.size() > 1 )
{
return QStringLiteral( "\"%1\"" ).arg( paths.join( QLatin1String( "\" \"" ) ) );
Expand Down
10 changes: 7 additions & 3 deletions src/gui/qgsfilewidget.h
Expand Up @@ -116,7 +116,7 @@ class GUI_EXPORT QgsFileWidget : public QWidget
/**
* Sets whether the widget should be read only.
*/
void setReadOnly( bool readOnly );
virtual void setReadOnly( bool readOnly );

/**
* Returns the open file dialog title.
Expand Down Expand Up @@ -380,6 +380,9 @@ class GUI_EXPORT QgsFileDropEdit: public QgsHighlightableLineEdit

void setFilters( const QString &filters );

//! Returns file names if object meets drop criteria.
QStringList acceptableFilePaths( QDropEvent *event ) const;

signals:

/**
Expand All @@ -389,14 +392,15 @@ class GUI_EXPORT QgsFileDropEdit: public QgsHighlightableLineEdit

protected:

//! Returns file name if object meets drop criteria.
QString acceptableFilePath( QDropEvent *event ) const;

void dragEnterEvent( QDragEnterEvent *event ) override;
void dragLeaveEvent( QDragLeaveEvent *event ) override;
void dropEvent( QDropEvent *event ) override;

private:

//! Returns file name if object meets drop criteria.
QString acceptableFilePath( QDropEvent *event ) const;

QStringList mAcceptableExtensions;
QgsFileWidget::StorageMode mStorageMode = QgsFileWidget::GetFile;
Expand Down
76 changes: 76 additions & 0 deletions tests/src/gui/testqgsexternalstoragefilewidget.cpp
Expand Up @@ -55,6 +55,7 @@ class TestQgsExternalStorageFileWidget: public QObject
void testStoringChangeFeature();
void testStoringBadExpression_data();
void testStoringBadExpression();
void testDragAndDrop();
};

class QgsTestExternalStorageStoredContent : public QgsExternalStorageStoredContent
Expand Down Expand Up @@ -800,5 +801,80 @@ void TestQgsExternalStorageFileWidget::testStoringDirectory()
QVERIFY( !QgsTestExternalStorage::sCurrentStoredContent );
}

void TestQgsExternalStorageFileWidget::testDragAndDrop()
{
// test widget when drag and droping urls with an external storage
QEventLoop loop;

QgsExternalStorageFileWidget w;
w.show();

std::unique_ptr<QMimeData> mime( new QMimeData() );
mime->setUrls( QList<QUrl>() << QUrl::fromLocalFile( TEST_DATA_DIR + QStringLiteral( "/bug5598.shp" ) ) );

QIcon editIcon = QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) );

QVERIFY( !w.acceptDrops() );

w.setReadOnly( true );
w.setStorageType( "test" );
w.setStorageUrlExpression( "'http://test.url.com/test/' || file_name(@selected_file_path)" );
w.setStorageMode( QgsFileWidget::GetFile );
QVERIFY( !w.acceptDrops() );

// start edit mode
w.setUseLink( true );
w.setReadOnly( false );

QVERIFY( w.mLinkLabel->isVisible() );
QVERIFY( w.mLinkEditButton->isVisible() );
QCOMPARE( w.mLinkEditButton->icon(), editIcon );
QVERIFY( !w.mLineEdit->isVisible() );
QVERIFY( w.mFileWidgetButton->isVisible() );
QVERIFY( w.mFileWidgetButton->isEnabled() );
QVERIFY( !w.mProgressLabel->isVisible() );
QVERIFY( !w.mProgressBar->isVisible() );
QVERIFY( !w.mCancelButton->isVisible() );
QVERIFY( w.acceptDrops() );

std::unique_ptr<QDragEnterEvent> dragEvent( new QDragEnterEvent( QPoint( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
w.dragEnterEvent( dragEvent.get() );
QVERIFY( dragEvent->isAccepted() );

std::unique_ptr<QDropEvent> dropEvent( new QDropEvent( QPoint( 1, 1 ), Qt::CopyAction, mime.get(), Qt::LeftButton, Qt::NoModifier ) );
w.dropEvent( dropEvent.get() );
QVERIFY( dropEvent->isAccepted() );

QVERIFY( QgsTestExternalStorage::sCurrentStoredContent );

QVERIFY( !w.mLinkLabel->isVisible() );
QVERIFY( !w.mLinkEditButton->isVisible() );
QVERIFY( !w.mLineEdit->isVisible() );
QVERIFY( !w.mFileWidgetButton->isVisible() );
QVERIFY( w.mProgressLabel->isVisible() );
QVERIFY( w.mProgressBar->isVisible() );
QVERIFY( w.mCancelButton->isVisible() );
QVERIFY( w.mLinkLabel->text().isEmpty() );

QgsTestExternalStorage::sCurrentStoredContent->finish();

QVERIFY( w.mLinkLabel->isVisible() );
QVERIFY( w.mLinkEditButton->isVisible() );
QCOMPARE( w.mLinkEditButton->icon(), editIcon );
QVERIFY( !w.mLineEdit->isVisible() );
QVERIFY( w.mFileWidgetButton->isVisible() );
QVERIFY( w.mFileWidgetButton->isEnabled() );
QVERIFY( !w.mProgressLabel->isVisible() );
QVERIFY( !w.mProgressBar->isVisible() );
QVERIFY( !w.mCancelButton->isVisible() );
QCOMPARE( w.mLinkLabel->text(), QStringLiteral( "<a href=\"http://test.url.com/test/bug5598.shp\">bug5598.shp</a>" ) );

// wait for file content to be destroyed
connect( QgsTestExternalStorage::sCurrentStoredContent, &QObject::destroyed, &loop, &QEventLoop::quit );
loop.exec();
QVERIFY( !QgsTestExternalStorage::sCurrentStoredContent );
}


QGSTEST_MAIN( TestQgsExternalStorageFileWidget )
#include "testqgsexternalstoragefilewidget.moc"

0 comments on commit 5c35b1c

Please sign in to comment.