[processing] Accept drag and dropped paths for output parameter values

from either explorer or browser (if you want to write to an existing
path, it's a great shortcut!)
This commit is contained in:
Nyall Dawson 2020-03-26 11:56:16 +10:00
parent c12590f87e
commit b106e723e2
4 changed files with 136 additions and 1 deletions

View File

@ -65,6 +65,14 @@ Emitted whenever the "skip output" option is toggled in the widget.
%Docstring
Emitted whenever the destination value is changed in the widget.
%End
protected:
virtual void dragEnterEvent( QDragEnterEvent *event );
virtual void dragLeaveEvent( QDragLeaveEvent *event );
virtual void dropEvent( QDropEvent *event );
};

View File

@ -38,6 +38,8 @@ QgsProcessingLayerOutputDestinationWidget::QgsProcessingLayerOutputDestinationWi
setupUi( this );
leText->setClearButtonEnabled( false );
connect( leText, &QLineEdit::textEdited, this, &QgsProcessingLayerOutputDestinationWidget::textChanged );
mMenu = new QMenu( this );
@ -62,6 +64,9 @@ QgsProcessingLayerOutputDestinationWidget::QgsProcessingLayerOutputDestinationWi
}
setToolTip( mParameter->toolTip() );
setAcceptDrops( true );
leText->setAcceptDrops( false );
}
bool QgsProcessingLayerOutputDestinationWidget::outputIsSkipped() const
@ -447,5 +452,113 @@ void QgsProcessingLayerOutputDestinationWidget::textChanged( const QString &text
emit destinationChanged();
}
QString QgsProcessingLayerOutputDestinationWidget::mimeDataToPath( const QMimeData *data )
{
const QgsMimeDataUtils::UriList uriList = QgsMimeDataUtils::decodeUriList( data );
for ( const QgsMimeDataUtils::Uri &u : uriList )
{
if ( ( mParameter->type() == QgsProcessingParameterFeatureSink::typeName()
|| mParameter->type() == QgsProcessingParameterVectorDestination::typeName()
|| mParameter->type() == QgsProcessingParameterFileDestination::typeName() )
&& u.layerType == QLatin1String( "vector" ) && u.providerKey == QLatin1String( "ogr" ) )
{
return u.uri;
}
else if ( ( mParameter->type() == QgsProcessingParameterRasterDestination::typeName()
|| mParameter->type() == QgsProcessingParameterFileDestination::typeName() )
&& u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) )
return u.uri;
#if 0
else if ( ( mParameter->type() == QgsProcessingParameterMeshDestination::typeName()
|| mParameter->type() == QgsProcessingParameterFileDestination::typeName() )
&& u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) )
return u.uri;
#endif
else if ( mParameter->type() == QgsProcessingParameterFolderDestination::typeName()
&& u.layerType == QLatin1String( "directory" ) )
{
return u.uri;
}
}
if ( !uriList.isEmpty() )
return QString();
// files dragged from file explorer, outside of QGIS
QStringList rawPaths;
if ( data->hasUrls() )
{
const QList< QUrl > urls = data->urls();
rawPaths.reserve( urls.count() );
for ( const QUrl &url : urls )
{
const QString local = url.toLocalFile();
if ( !rawPaths.contains( local ) )
rawPaths.append( local );
}
}
if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
rawPaths.append( data->text() );
for ( const QString &path : qgis::as_const( rawPaths ) )
{
QFileInfo file( path );
if ( file.isFile() && ( mParameter->type() == QgsProcessingParameterFeatureSink::typeName()
|| mParameter->type() == QgsProcessingParameterVectorDestination::typeName()
|| mParameter->type() == QgsProcessingParameterRasterDestination::typeName()
|| mParameter->type() == QgsProcessingParameterVectorDestination::typeName()
|| mParameter->type() == QgsProcessingParameterFileDestination::typeName() ) )
{
// TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
return path;
}
else if ( file.isDir() && ( mParameter->type() == QgsProcessingParameterFolderDestination::typeName() ) )
return path;
}
return QString();
}
void QgsProcessingLayerOutputDestinationWidget::dragEnterEvent( QDragEnterEvent *event )
{
if ( !( event->possibleActions() & Qt::CopyAction ) )
return;
const QString path = mimeDataToPath( event->mimeData() );
if ( !path.isEmpty() )
{
// dragged an acceptable path, phew
event->setDropAction( Qt::CopyAction );
event->accept();
leText->setHighlighted( true );
}
}
void QgsProcessingLayerOutputDestinationWidget::dragLeaveEvent( QDragLeaveEvent *event )
{
QWidget::dragLeaveEvent( event );
if ( leText->isHighlighted() )
{
event->accept();
leText->setHighlighted( false );
}
}
void QgsProcessingLayerOutputDestinationWidget::dropEvent( QDropEvent *event )
{
if ( !( event->possibleActions() & Qt::CopyAction ) )
return;
const QString path = mimeDataToPath( event->mimeData() );
if ( !path.isEmpty() )
{
// dropped an acceptable path, phew
setFocus( Qt::MouseFocusReason );
event->setDropAction( Qt::CopyAction );
event->accept();
setValue( path );
}
leText->setHighlighted( false );
}
///@endcond

View File

@ -77,6 +77,11 @@ class GUI_EXPORT QgsProcessingLayerOutputDestinationWidget : public QWidget, pri
* Emitted whenever the destination value is changed in the widget.
*/
void destinationChanged();
protected:
void dragEnterEvent( QDragEnterEvent *event ) override;
void dragLeaveEvent( QDragLeaveEvent *event ) override;
void dropEvent( QDropEvent *event ) override;
private slots:
@ -92,6 +97,8 @@ class GUI_EXPORT QgsProcessingLayerOutputDestinationWidget : public QWidget, pri
private:
QString mimeDataToPath( const QMimeData *data );
const QgsProcessingDestinationParameter *mParameter = nullptr;
QMenu *mMenu = nullptr;

View File

@ -30,7 +30,7 @@
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="leText">
<widget class="QgsHighlightableLineEdit" name="leText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
@ -54,6 +54,13 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsHighlightableLineEdit</class>
<extends>QLineEdit</extends>
<header>qgshighlightablelineedit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>