17#include "moc_qgsprocessingoutputdestinationwidget.cpp"
30#include <QInputDialog>
38QgsProcessingLayerOutputDestinationWidget::QgsProcessingLayerOutputDestinationWidget(
const QgsProcessingDestinationParameter *param,
bool defaultSelection, QWidget *parent )
41 , mDefaultSelection( defaultSelection )
43 Q_ASSERT( mParameter );
47 leText->setClearButtonEnabled(
false );
49 connect( leText, &QLineEdit::textEdited,
this, &QgsProcessingLayerOutputDestinationWidget::textChanged );
51 mMenu =
new QMenu(
this );
52 connect( mMenu, &QMenu::aboutToShow,
this, &QgsProcessingLayerOutputDestinationWidget::menuAboutToShow );
53 mSelectButton->setMenu( mMenu );
54 mSelectButton->setPopupMode( QToolButton::InstantPopup );
58 settings.
setValue( QStringLiteral(
"/Processing/encoding" ), mEncoding );
60 if ( !mParameter->defaultValueForGui().isValid() )
64 setValue( QVariant() );
70 setValue( mParameter->defaultValueForGui() );
73 setToolTip( mParameter->toolTip() );
75 setAcceptDrops(
true );
76 leText->setAcceptDrops(
false );
79bool QgsProcessingLayerOutputDestinationWidget::outputIsSkipped()
const
81 return leText->text().isEmpty() && !mUseTemporary;
84void QgsProcessingLayerOutputDestinationWidget::setValue(
const QVariant &value )
86 const bool prevSkip = outputIsSkipped();
87 mUseRemapping =
false;
88 if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() ) )
101 else if ( value.userType() == qMetaTypeId<QgsProcessingOutputLayerDefinition>() )
110 const QVariant prev = QgsProcessingLayerOutputDestinationWidget::value();
112 mUseTemporary =
false;
114 emit skipOutputChanged(
false );
115 if ( prev != QgsProcessingLayerOutputDestinationWidget::value() )
116 emit destinationChanged();
120 mEncoding = def.
createOptions.value( QStringLiteral(
"fileEncoding" ) ).toString();
124 const QVariant prev = QgsProcessingLayerOutputDestinationWidget::value();
125 leText->setText( value.toString() );
126 mUseTemporary =
false;
128 emit skipOutputChanged(
false );
132 if ( prev.toString() != QgsProcessingLayerOutputDestinationWidget::value().toString() )
133 emit destinationChanged();
137 if ( prev.userType() != qMetaTypeId<QgsProcessingOutputLayerDefinition>() ||
139 emit destinationChanged();
145QVariant QgsProcessingLayerOutputDestinationWidget::value()
const
153 else if ( mUseTemporary && !mDefaultSelection )
159 key = leText->text();
168 && !key.startsWith( QLatin1String(
"memory:" ) )
169 && !key.startsWith( QLatin1String(
"ogr:" ) )
170 && !key.startsWith( QLatin1String(
"postgres:" ) )
171 && !key.startsWith( QLatin1String(
"postgis:" ) )
175 QString folder = QFileInfo( key ).path();
179 QString defaultFolder = settings.
value( QStringLiteral(
"/Processing/Configuration/OUTPUTS_FOLDER" ) ).toString();
180 key = QDir( defaultFolder ).filePath( key );
190 value.createOptions.insert( QStringLiteral(
"fileEncoding" ), mEncoding );
192 value.setRemappingDefinition( mRemapDefinition );
208 mParametersGenerator = generator;
211void QgsProcessingLayerOutputDestinationWidget::addOpenAfterRunningOption()
213 Q_ASSERT( mOpenAfterRunningCheck ==
nullptr );
214 mOpenAfterRunningCheck =
new QCheckBox( tr(
"Open output file after running algorithm" ) );
215 mOpenAfterRunningCheck->setChecked( !outputIsSkipped() );
216 mOpenAfterRunningCheck->setEnabled( !outputIsSkipped() );
217 gridLayout->addWidget( mOpenAfterRunningCheck, 1, 0, 1, 2 );
219 connect(
this, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged,
this, [ = ](
bool skipped )
221 bool enabled = !skipped;
222 mOpenAfterRunningCheck->setEnabled( enabled );
223 mOpenAfterRunningCheck->setChecked( enabled );
227bool QgsProcessingLayerOutputDestinationWidget::openAfterRunning()
const
229 return mOpenAfterRunningCheck && mOpenAfterRunningCheck->isChecked();
232void QgsProcessingLayerOutputDestinationWidget::menuAboutToShow()
236 if ( !mDefaultSelection )
240 QAction *actionSkipOutput =
new QAction( tr(
"Skip Output" ),
this );
241 connect( actionSkipOutput, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::skipOutput );
242 mMenu->addAction( actionSkipOutput );
245 QAction *actionSaveToTemp =
nullptr;
249 actionSaveToTemp =
new QAction( tr(
"Create Temporary Layer" ),
this );
253 actionSaveToTemp =
new QAction( tr(
"Save to a Temporary Directory" ),
this );
257 actionSaveToTemp =
new QAction( tr(
"Save to a Temporary File" ),
this );
260 connect( actionSaveToTemp, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::saveToTemporary );
261 mMenu->addAction( actionSaveToTemp );
264 QAction *actionSaveToFile =
nullptr;
267 actionSaveToFile =
new QAction( tr(
"Save to Directory…" ),
this );
268 connect( actionSaveToFile, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::selectDirectory );
272 actionSaveToFile =
new QAction( tr(
"Save to File…" ),
this );
273 connect( actionSaveToFile, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::selectFile );
275 mMenu->addAction( actionSaveToFile );
279 QAction *actionSaveToGpkg =
new QAction( tr(
"Save to GeoPackage…" ),
this );
280 connect( actionSaveToGpkg, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::saveToGeopackage );
281 mMenu->addAction( actionSaveToGpkg );
283 QAction *actionSaveToDatabase =
new QAction( tr(
"Save to Database Table…" ),
this );
284 connect( actionSaveToDatabase, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::saveToDatabase );
285 mMenu->addAction( actionSaveToDatabase );
287 if ( mParameter->algorithm() && qgis::down_cast< const QgsProcessingParameterFeatureSink * >( mParameter )->supportsAppend() )
289 mMenu->addSeparator();
290 QAction *actionAppendToLayer =
new QAction( tr(
"Append to Layer…" ),
this );
291 connect( actionAppendToLayer, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::appendToLayer );
292 mMenu->addAction( actionAppendToLayer );
295 QAction *editMappingAction =
new QAction( tr(
"Edit Field Mapping…" ),
this );
296 connect( editMappingAction, &QAction::triggered,
this, [ = ]
298 setAppendDestination( value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), mRemapDefinition.destinationFields() );
300 mMenu->addAction( editMappingAction );
307 mMenu->addSeparator();
308 QAction *actionSetEncoding =
new QAction( tr(
"Change File Encoding (%1)…" ).arg( mEncoding ),
this );
309 connect( actionSetEncoding, &QAction::triggered,
this, &QgsProcessingLayerOutputDestinationWidget::selectEncoding );
310 mMenu->addAction( actionSetEncoding );
314void QgsProcessingLayerOutputDestinationWidget::skipOutput()
316 leText->setPlaceholderText( tr(
"[Skip output]" ) );
318 mUseTemporary =
false;
319 mUseRemapping =
false;
321 emit skipOutputChanged(
true );
322 emit destinationChanged();
325void QgsProcessingLayerOutputDestinationWidget::saveToTemporary()
327 const bool prevSkip = outputIsSkipped();
331 leText->setPlaceholderText( tr(
"[Create temporary layer]" ) );
335 leText->setPlaceholderText( tr(
"[Save to temporary folder]" ) );
339 leText->setPlaceholderText( tr(
"[Save to temporary file]" ) );
346 mUseTemporary =
true;
347 mUseRemapping =
false;
349 emit skipOutputChanged(
false );
350 emit destinationChanged();
353void QgsProcessingLayerOutputDestinationWidget::selectDirectory()
355 QString lastDir = leText->text();
357 if ( lastDir.isEmpty() )
358 lastDir = settings.
value( QStringLiteral(
"/Processing/LastOutputPath" ), QDir::homePath() ).toString();
360 const QString dirName = QFileDialog::getExistingDirectory(
this, tr(
"Select Directory" ), lastDir, QFileDialog::Options() );
361 if ( !dirName.isEmpty() )
363 leText->setText( QDir::toNativeSeparators( dirName ) );
364 settings.
setValue( QStringLiteral(
"/Processing/LastOutputPath" ), dirName );
365 mUseTemporary =
false;
366 mUseRemapping =
false;
367 emit skipOutputChanged(
false );
368 emit destinationChanged();
372void QgsProcessingLayerOutputDestinationWidget::selectFile()
374 const QString fileFilter = mParameter->createFileFilter();
382 lastExtPath = QStringLiteral(
"/Processing/LastVectorOutputExt" );
383 lastExt = settings.
value( lastExtPath, QStringLiteral(
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString() ;
387 lastExtPath = QStringLiteral(
"/Processing/LastRasterOutputExt" );
388 lastExt = settings.
value( lastExtPath, QStringLiteral(
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
392 lastExtPath = QStringLiteral(
"/Processing/LastPointCloudOutputExt" );
393 lastExt = settings.
value( lastExtPath, QStringLiteral(
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
397 lastExtPath = QStringLiteral(
"/Processing/LastVectorTileOutputExt" );
398 lastExt = settings.
value( lastExtPath, QStringLiteral(
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
402 const QStringList filters = fileFilter.split( QStringLiteral(
";;" ) );
404 for (
const QString &f : filters )
406 if ( f.contains( QStringLiteral(
"*.%1" ).arg( lastExt ), Qt::CaseInsensitive ) )
414 if ( settings.
contains( QStringLiteral(
"/Processing/LastOutputPath" ) ) )
415 path = settings.
value( QStringLiteral(
"/Processing/LastOutputPath" ) ).toString();
417 path = settings.
value( QStringLiteral(
"/Processing/Configuration/OUTPUTS_FOLDER" ) ).toString();
419 const bool dontConfirmOverwrite = mParameter->metadata().value( QStringLiteral(
"widget_wrapper" ) ).toMap().value( QStringLiteral(
"dontconfirmoverwrite" ),
false ).toBool();
421 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save file" ), path, fileFilter, &lastFilter, dontConfirmOverwrite ? QFileDialog::Options( QFileDialog::DontConfirmOverwrite ) : QFileDialog::Options() );
422 if ( !filename.isEmpty() )
424 mUseTemporary =
false;
425 mUseRemapping =
false;
428 leText->setText( filename );
429 settings.
setValue( QStringLiteral(
"/Processing/LastOutputPath" ), QFileInfo( filename ).path() );
430 if ( !lastExtPath.isEmpty() )
431 settings.
setValue( lastExtPath, QFileInfo( filename ).suffix().toLower() );
433 emit skipOutputChanged(
false );
434 emit destinationChanged();
441void QgsProcessingLayerOutputDestinationWidget::saveToGeopackage()
444 QString lastPath = settings.
value( QStringLiteral(
"/Processing/LastOutputPath" ), QString() ).toString();
445 if ( lastPath.isEmpty() )
446 lastPath = settings.
value( QStringLiteral(
"/Processing/Configuration/OUTPUTS_FOLDER" ), QString() ).toString();
448 QString filename = QFileDialog::getSaveFileName(
this, tr(
"Save to GeoPackage" ), lastPath, tr(
"GeoPackage files (*.gpkg);;All files (*.*)" ),
nullptr, QFileDialog::DontConfirmOverwrite );
453 if ( filename.isEmpty() )
456 const QString layerName = QInputDialog::getText(
this, tr(
"Save to GeoPackage" ), tr(
"Layer name" ), QLineEdit::Normal, mParameter->name().toLower() );
457 if ( layerName.isEmpty() )
460 mUseTemporary =
false;
461 mUseRemapping =
false;
465 settings.
setValue( QStringLiteral(
"/Processing/LastOutputPath" ), QFileInfo( filename ).path() );
474 if ( sink->hasGeometry() )
475 geomColumn = QStringLiteral(
"geom" );
479 leText->setText( QStringLiteral(
"ogr:%1" ).arg( uri.
uri() ) );
481 emit skipOutputChanged(
false );
482 emit destinationChanged();
485void QgsProcessingLayerOutputDestinationWidget::saveToDatabase()
491 << QStringLiteral(
"mssql" )
492 << QStringLiteral(
"ogr" )
493 << QStringLiteral(
"hana" )
494 << QStringLiteral(
"spatialite" )
495 << QStringLiteral(
"oracle" ),
this );
496 widget->
setPanelTitle( tr(
"Save “%1” to Database Table" ).arg( mParameter->description() ) );
499 panel->openPanel( widget );
503 mUseTemporary =
false;
504 mUseRemapping =
false;
509 if ( sink->hasGeometry() )
510 geomColumn = widget->
dataProviderKey() == QLatin1String(
"oracle" ) ? QStringLiteral(
"GEOM" ) : QStringLiteral(
"geom" );
519 leText->setText( QStringLiteral(
"ogr:%1" ).arg( uri.
uri() ) );
528 emit skipOutputChanged(
false );
529 emit destinationChanged();
544void QgsProcessingLayerOutputDestinationWidget::appendToLayer()
549 widget->
setPanelTitle( tr(
"Append \"%1\" to Layer" ).arg( mParameter->description() ) );
551 panel->openPanel( widget );
559 if ( widget->
uri().
uri.isEmpty() )
560 setValue( QVariant() );
564 std::unique_ptr< QgsVectorLayer > dest = std::make_unique< QgsVectorLayer >( widget->
uri().
uri, QString(), widget->
uri().
providerKey );
566 setAppendDestination( widget->
uri().
uri, dest->fields() );
575void QgsProcessingLayerOutputDestinationWidget::setAppendDestination(
const QString &uri,
const QgsFields &destFields )
579 if ( mParametersGenerator )
580 props = mParametersGenerator->createProcessingParameters();
581 props.insert( mParameter->name(), uri );
590 widget->
setPanelTitle( tr(
"Append \"%1\" to Layer" ).arg( mParameter->description() ) );
591 if ( !mRemapDefinition.fieldMap().isEmpty() )
594 panel->openPanel( widget );
610void QgsProcessingLayerOutputDestinationWidget::selectEncoding()
618 settings.
setValue( QStringLiteral(
"/Processing/encoding" ), mEncoding );
620 emit destinationChanged();
624void QgsProcessingLayerOutputDestinationWidget::textChanged(
const QString &text )
626 mUseTemporary = text.isEmpty();
627 mUseRemapping =
false;
628 emit destinationChanged();
632QString QgsProcessingLayerOutputDestinationWidget::mimeDataToPath(
const QMimeData *data )
640 && u.layerType == QLatin1String(
"vector" ) && u.providerKey == QLatin1String(
"ogr" ) )
646 && u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" ) )
652 && u.layerType == QLatin1String(
"pointcloud" ) && ( u.providerKey == QLatin1String(
"ept" ) || u.providerKey == QLatin1String(
"pdal" ) ) )
657 else if ( ( mParameter->type() == QgsProcessingParameterMeshDestination::typeName()
659 && u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" ) )
664 && u.layerType == QLatin1String(
"directory" ) )
669 if ( !uriList.isEmpty() )
673 QStringList rawPaths;
674 if ( data->hasUrls() )
676 const QList< QUrl > urls = data->urls();
677 rawPaths.reserve( urls.count() );
678 for (
const QUrl &url : urls )
680 const QString local = url.toLocalFile();
681 if ( !rawPaths.contains( local ) )
682 rawPaths.append( local );
685 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
686 rawPaths.append( data->text() );
688 for (
const QString &path : std::as_const( rawPaths ) )
690 QFileInfo file( path );
708void QgsProcessingLayerOutputDestinationWidget::dragEnterEvent( QDragEnterEvent *event )
710 if ( !( event->possibleActions() & Qt::CopyAction ) )
713 const QString path = mimeDataToPath( event->mimeData() );
714 if ( !path.isEmpty() )
717 event->setDropAction( Qt::CopyAction );
719 leText->setHighlighted(
true );
723void QgsProcessingLayerOutputDestinationWidget::dragLeaveEvent( QDragLeaveEvent *event )
725 QWidget::dragLeaveEvent( event );
726 if ( leText->isHighlighted() )
729 leText->setHighlighted(
false );
733void QgsProcessingLayerOutputDestinationWidget::dropEvent( QDropEvent *event )
735 if ( !( event->possibleActions() & Qt::CopyAction ) )
738 const QString path = mimeDataToPath( event->mimeData() );
739 if ( !path.isEmpty() )
742 setFocus( Qt::MouseFocusReason );
743 event->setDropAction( Qt::CopyAction );
747 leText->setHighlighted(
false );
@ Available
Properties are available.
@ Optional
Parameter is optional.
Class for storing the component parts of a RDBMS data source URI (e.g.
void setTable(const QString &table)
Sets table to table.
void setGeometryColumn(const QString &geometryColumn)
Sets geometry column name to geometryColumn.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
void setDatabase(const QString &database)
Sets the URI database name.
A dialog which presents the user with a choice of file encodings.
Container of fields for a vector layer.
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
static QString addExtensionFromFilter(const QString &fileName, const QString &filter)
Ensures that a fileName ends with an extension from the specified filter string.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Abstract base class for processing algorithms.
virtual QgsProcessingAlgorithm::VectorProperties sinkProperties(const QString &sink, const QVariantMap ¶meters, QgsProcessingContext &context, const QMap< QString, QgsProcessingAlgorithm::VectorProperties > &sourceProperties) const
Returns the vector properties which will be used for the sink with matching name.
Contains information about the context in which a processing algorithm is executed.
Base class for all parameter definitions which represent file or layer destinations,...
Encapsulates settings relating to a feature sink or output raster layer for a processing algorithm.
QgsProperty sink
Sink/layer definition.
bool useRemapping() const
Returns true if the output uses a remapping definition.
QgsRemappingSinkDefinition remappingDefinition() const
Returns the output remapping definition, if useRemapping() is true.
QVariantMap createOptions
Map of optional sink/layer creation options, which are passed to the underlying provider when creatin...
void setRemappingDefinition(const QgsRemappingSinkDefinition &definition)
Sets the remapping definition to use when adding features to the output layer.
A feature sink output for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QgsBrowserGuiModel * browserModel() const
Returns the browser model associated with the widget.
An interface for objects which can create sets of parameter values for processing algorithms.
static QString encodeProviderKeyAndUri(const QString &providerKey, const QString &uri)
Encodes a provider key and layer uri to a single string, for use with decodeProviderKeyAndUri()
static QString resolveDefaultEncoding(const QString &defaultEncoding="System")
Returns the default encoding.
static bool decodeProviderKeyAndUri(const QString &string, QString &providerKey, QString &uri)
Decodes a provider key and layer uri from an encoded string, for use with encodeProviderKeyAndUri()
static const QString TEMPORARY_OUTPUT
Constant used to indicate that a Processing algorithm output should be a temporary layer/file.
QVariant staticValue() const
Returns the current static value for the property.
Defines the parameters used to remap features when creating a QgsRemappingProxyFeatureSink.
void setFieldMap(const QMap< QString, QgsProperty > &map)
Sets the field mapping, which defines how to map the values from incoming features to destination fie...
void setDestinationFields(const QgsFields &fields)
Sets the fields for the destination sink.
void setSourceCrs(const QgsCoordinateReferenceSystem &source)
Sets the source crs used for reprojecting incoming features to the sink's destination CRS.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
QString uri
Identifier of the data source recognized by its providerKey.
QString providerKey
For "vector" / "raster" type: provider id.
Properties of a vector source or sink used in an algorithm.
QgsCoordinateReferenceSystem crs
Coordinate Reference System.
Qgis::ProcessingPropertyAvailability availability
Availability of the properties. By default properties are not available.