29#include <QInputDialog> 
   35QgsProcessingLayerOutputDestinationWidget::QgsProcessingLayerOutputDestinationWidget( 
const QgsProcessingDestinationParameter *param, 
bool defaultSelection, QWidget *parent )
 
   38  , mDefaultSelection( defaultSelection )
 
   40  Q_ASSERT( mParameter );
 
   44  leText->setClearButtonEnabled( 
false );
 
   46  connect( leText, &QLineEdit::textEdited, 
this, &QgsProcessingLayerOutputDestinationWidget::textChanged );
 
   48  mMenu = 
new QMenu( 
this );
 
   49  connect( mMenu, &QMenu::aboutToShow, 
this, &QgsProcessingLayerOutputDestinationWidget::menuAboutToShow );
 
   50  mSelectButton->setMenu( mMenu );
 
   51  mSelectButton->setPopupMode( QToolButton::InstantPopup );
 
   54  mEncoding = settings.
value( QStringLiteral( 
"/Processing/encoding" ), QStringLiteral( 
"System" ) ).toString();
 
   56  if ( !mParameter->defaultValueForGui().isValid() )
 
   60      setValue( QVariant() );
 
   66    setValue( mParameter->defaultValueForGui() );
 
   69  setToolTip( mParameter->toolTip() );
 
   71  setAcceptDrops( 
true );
 
   72  leText->setAcceptDrops( 
false );
 
   75bool QgsProcessingLayerOutputDestinationWidget::outputIsSkipped()
 const 
   77  return leText->text().isEmpty() && !mUseTemporary;
 
   80void QgsProcessingLayerOutputDestinationWidget::setValue( 
const QVariant &value )
 
   82  const bool prevSkip = outputIsSkipped();
 
   83  mUseRemapping = 
false;
 
   84  if ( !value.isValid() || ( value.type() == QVariant::String && value.toString().isEmpty() ) )
 
   97    else if ( value.userType() == QMetaType::type( 
"QgsProcessingOutputLayerDefinition" ) )
 
  106        const QVariant prev = QgsProcessingLayerOutputDestinationWidget::value();
 
  108        mUseTemporary = 
false;
 
  110          emit skipOutputChanged( 
false );
 
  111        if ( prev != QgsProcessingLayerOutputDestinationWidget::value() )
 
  112          emit destinationChanged();
 
  116      mEncoding = def.
createOptions.value( QStringLiteral( 
"fileEncoding" ) ).toString();
 
  120      const QVariant prev = QgsProcessingLayerOutputDestinationWidget::value();
 
  121      leText->setText( value.toString() );
 
  122      mUseTemporary = 
false;
 
  124        emit skipOutputChanged( 
false );
 
  128        if ( prev.toString() != QgsProcessingLayerOutputDestinationWidget::value().toString() )
 
  129          emit destinationChanged();
 
  133        if ( prev.userType() != QMetaType::type( 
"QgsProcessingOutputLayerDefinition" ) ||
 
  135          emit destinationChanged();
 
  141QVariant QgsProcessingLayerOutputDestinationWidget::value()
 const 
  149  else if ( mUseTemporary && !mDefaultSelection )
 
  155    key = leText->text();
 
  164       && !key.startsWith( QLatin1String( 
"memory:" ) )
 
  165       && !key.startsWith( QLatin1String( 
"ogr:" ) )
 
  166       && !key.startsWith( QLatin1String( 
"postgres:" ) )
 
  167       && !key.startsWith( QLatin1String( 
"postgis:" ) )
 
  171    QString folder = QFileInfo( key ).path();
 
  175      QString defaultFolder = settings.
value( QStringLiteral( 
"/Processing/Configuration/OUTPUTS_FOLDER" ) ).toString();
 
  176      key = QDir( defaultFolder ).filePath( key );
 
  186  value.createOptions.insert( QStringLiteral( 
"fileEncoding" ), mEncoding );
 
  188    value.setRemappingDefinition( mRemapDefinition );
 
  204  mParametersGenerator = generator;
 
  207void QgsProcessingLayerOutputDestinationWidget::addOpenAfterRunningOption()
 
  209  Q_ASSERT( mOpenAfterRunningCheck == 
nullptr );
 
  210  mOpenAfterRunningCheck = 
new QCheckBox( tr( 
"Open output file after running algorithm" ) );
 
  211  mOpenAfterRunningCheck->setChecked( !outputIsSkipped() );
 
  212  mOpenAfterRunningCheck->setEnabled( !outputIsSkipped() );
 
  213  gridLayout->addWidget( mOpenAfterRunningCheck, 1, 0, 1, 2 );
 
  215  connect( 
this, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged, 
this, [ = ]( 
bool skipped )
 
  217    bool enabled = !skipped;
 
  218    mOpenAfterRunningCheck->setEnabled( enabled );
 
  219    mOpenAfterRunningCheck->setChecked( enabled );
 
  223bool QgsProcessingLayerOutputDestinationWidget::openAfterRunning()
 const 
  225  return mOpenAfterRunningCheck && mOpenAfterRunningCheck->isChecked();
 
  228void QgsProcessingLayerOutputDestinationWidget::menuAboutToShow()
 
  232  if ( !mDefaultSelection )
 
  236      QAction *actionSkipOutput = 
new QAction( tr( 
"Skip Output" ), 
this );
 
  237      connect( actionSkipOutput, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::skipOutput );
 
  238      mMenu->addAction( actionSkipOutput );
 
  241    QAction *actionSaveToTemp = 
nullptr;
 
  245      actionSaveToTemp = 
new QAction( tr( 
"Create Temporary Layer" ), 
this );
 
  249      actionSaveToTemp = 
new QAction( tr( 
"Save to a Temporary Directory" ), 
this );
 
  253      actionSaveToTemp = 
new QAction( tr( 
"Save to a Temporary File" ), 
this );
 
  256    connect( actionSaveToTemp, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::saveToTemporary );
 
  257    mMenu->addAction( actionSaveToTemp );
 
  260  QAction *actionSaveToFile = 
nullptr;
 
  263    actionSaveToFile = 
new QAction( tr( 
"Save to Directory…" ), 
this );
 
  264    connect( actionSaveToFile, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::selectDirectory );
 
  268    actionSaveToFile = 
new QAction( tr( 
"Save to File…" ), 
this );
 
  269    connect( actionSaveToFile, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::selectFile );
 
  271  mMenu->addAction( actionSaveToFile );
 
  275    QAction *actionSaveToGpkg = 
new QAction( tr( 
"Save to GeoPackage…" ), 
this );
 
  276    connect( actionSaveToGpkg, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::saveToGeopackage );
 
  277    mMenu->addAction( actionSaveToGpkg );
 
  279    QAction *actionSaveToDatabase = 
new QAction( tr( 
"Save to Database Table…" ), 
this );
 
  280    connect( actionSaveToDatabase, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::saveToDatabase );
 
  281    mMenu->addAction( actionSaveToDatabase );
 
  283    if ( mParameter->algorithm() && qgis::down_cast< const QgsProcessingParameterFeatureSink * >( mParameter )->supportsAppend() )
 
  285      mMenu->addSeparator();
 
  286      QAction *actionAppendToLayer = 
new QAction( tr( 
"Append to Layer…" ), 
this );
 
  287      connect( actionAppendToLayer, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::appendToLayer );
 
  288      mMenu->addAction( actionAppendToLayer );
 
  291        QAction *editMappingAction = 
new QAction( tr( 
"Edit Field Mapping…" ), 
this );
 
  292        connect( editMappingAction, &QAction::triggered, 
this, [ = ]
 
  294          setAppendDestination( value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), mRemapDefinition.destinationFields() );
 
  296        mMenu->addAction( editMappingAction );
 
  303    mMenu->addSeparator();
 
  304    QAction *actionSetEncoding = 
new QAction( tr( 
"Change File Encoding (%1)…" ).arg( mEncoding ), 
this );
 
  305    connect( actionSetEncoding, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::selectEncoding );
 
  306    mMenu->addAction( actionSetEncoding );
 
  310void QgsProcessingLayerOutputDestinationWidget::skipOutput()
 
  312  leText->setPlaceholderText( tr( 
"[Skip output]" ) );
 
  314  mUseTemporary = 
false;
 
  315  mUseRemapping = 
false;
 
  317  emit skipOutputChanged( 
true );
 
  318  emit destinationChanged();
 
  321void QgsProcessingLayerOutputDestinationWidget::saveToTemporary()
 
  323  const bool prevSkip = outputIsSkipped();
 
  327    leText->setPlaceholderText( tr( 
"[Create temporary layer]" ) );
 
  331    leText->setPlaceholderText( tr( 
"[Save to temporary folder]" ) );
 
  335    leText->setPlaceholderText( tr( 
"[Save to temporary file]" ) );
 
  342  mUseTemporary = 
true;
 
  343  mUseRemapping = 
false;
 
  345    emit skipOutputChanged( 
false );
 
  346  emit destinationChanged();
 
  349void QgsProcessingLayerOutputDestinationWidget::selectDirectory()
 
  351  QString lastDir = leText->text();
 
  353  if ( lastDir.isEmpty() )
 
  354    lastDir = settings.
value( QStringLiteral( 
"/Processing/LastOutputPath" ), QDir::homePath() ).toString();
 
  356  const QString dirName = QFileDialog::getExistingDirectory( 
this, tr( 
"Select Directory" ), lastDir, QFileDialog::Options() );
 
  357  if ( !dirName.isEmpty() )
 
  359    leText->setText( QDir::toNativeSeparators( dirName ) );
 
  360    settings.
setValue( QStringLiteral( 
"/Processing/LastOutputPath" ), dirName );
 
  361    mUseTemporary = 
false;
 
  362    mUseRemapping = 
false;
 
  363    emit skipOutputChanged( 
false );
 
  364    emit destinationChanged();
 
  368void QgsProcessingLayerOutputDestinationWidget::selectFile()
 
  370  const QString fileFilter = mParameter->createFileFilter();
 
  378    lastExtPath = QStringLiteral( 
"/Processing/LastVectorOutputExt" );
 
  379    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString() ;
 
  383    lastExtPath = QStringLiteral( 
"/Processing/LastRasterOutputExt" );
 
  384    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
 
  388    lastExtPath = QStringLiteral( 
"/Processing/LastPointCloudOutputExt" );
 
  389    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
 
  393    lastExtPath = QStringLiteral( 
"/Processing/LastVectorTileOutputExt" );
 
  394    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
 
  398  const QStringList filters = fileFilter.split( QStringLiteral( 
";;" ) );
 
  400  for ( 
const QString &f : filters )
 
  402    if ( f.contains( QStringLiteral( 
"*.%1" ).arg( lastExt ), Qt::CaseInsensitive ) )
 
  410  if ( settings.
contains( QStringLiteral( 
"/Processing/LastOutputPath" ) ) )
 
  411    path = settings.
value( QStringLiteral( 
"/Processing/LastOutputPath" ) ).toString();
 
  413    path = settings.
value( QStringLiteral( 
"/Processing/Configuration/OUTPUTS_FOLDER" ) ).toString();
 
  415  const bool dontConfirmOverwrite = mParameter->metadata().value( QStringLiteral( 
"widget_wrapper" ) ).toMap().value( QStringLiteral( 
"dontconfirmoverwrite" ), 
false ).toBool();
 
  417  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save file" ), path, fileFilter, &lastFilter, dontConfirmOverwrite ? QFileDialog::Options( QFileDialog::DontConfirmOverwrite ) : QFileDialog::Options() );
 
  418  if ( !filename.isEmpty() )
 
  420    mUseTemporary = 
false;
 
  421    mUseRemapping = 
false;
 
  424    leText->setText( filename );
 
  425    settings.
setValue( QStringLiteral( 
"/Processing/LastOutputPath" ), QFileInfo( filename ).path() );
 
  426    if ( !lastExtPath.isEmpty() )
 
  427      settings.
setValue( lastExtPath, QFileInfo( filename ).suffix().toLower() );
 
  429    emit skipOutputChanged( 
false );
 
  430    emit destinationChanged();
 
  434void QgsProcessingLayerOutputDestinationWidget::saveToGeopackage()
 
  437  QString lastPath = settings.
value( QStringLiteral( 
"/Processing/LastOutputPath" ), QString() ).toString();
 
  438  if ( lastPath.isEmpty() )
 
  439    lastPath = settings.
value( QStringLiteral( 
"/Processing/Configuration/OUTPUTS_FOLDER" ), QString() ).toString();
 
  441  QString filename =  QFileDialog::getSaveFileName( 
this, tr( 
"Save to GeoPackage" ), lastPath, tr( 
"GeoPackage files (*.gpkg);;All files (*.*)" ), 
nullptr, QFileDialog::DontConfirmOverwrite );
 
  443  if ( filename.isEmpty() )
 
  446  const QString layerName = QInputDialog::getText( 
this, tr( 
"Save to GeoPackage" ), tr( 
"Layer name" ), QLineEdit::Normal, mParameter->name().toLower() );
 
  447  if ( layerName.isEmpty() )
 
  450  mUseTemporary = 
false;
 
  451  mUseRemapping = 
false;
 
  455  settings.
setValue( QStringLiteral( 
"/Processing/LastOutputPath" ), QFileInfo( filename ).path() );
 
  464    if ( sink->hasGeometry() )
 
  465      geomColumn = QStringLiteral( 
"geom" );
 
  469  leText->setText( QStringLiteral( 
"ogr:%1" ).arg( uri.
uri() ) );
 
  471  emit skipOutputChanged( 
false );
 
  472  emit destinationChanged();
 
  475void QgsProcessingLayerOutputDestinationWidget::saveToDatabase()
 
  481        << QStringLiteral( 
"mssql" )
 
  482        << QStringLiteral( 
"ogr" )
 
  483        << QStringLiteral( 
"hana" )
 
  484        << QStringLiteral( 
"spatialite" )
 
  485        << QStringLiteral( 
"oracle" ), 
this );
 
  486    widget->
setPanelTitle( tr( 
"Save “%1” to Database Table" ).arg( mParameter->description() ) );
 
  489    panel->openPanel( widget );
 
  493      mUseTemporary = 
false;
 
  494      mUseRemapping = 
false;
 
  499        if ( sink->hasGeometry() )
 
  500          geomColumn = widget->
dataProviderKey() == QLatin1String( 
"oracle" ) ? QStringLiteral( 
"GEOM" ) : QStringLiteral( 
"geom" );
 
  509        leText->setText( QStringLiteral( 
"ogr:%1" ).arg( uri.
uri() ) );
 
  518      emit skipOutputChanged( 
false );
 
  519      emit destinationChanged();
 
  534void QgsProcessingLayerOutputDestinationWidget::appendToLayer()
 
  539    widget->
setPanelTitle( tr( 
"Append \"%1\" to Layer" ).arg( mParameter->description() ) );
 
  541    panel->openPanel( widget );
 
  549      if ( widget->
uri().
uri.isEmpty() )
 
  550        setValue( QVariant() );
 
  554        std::unique_ptr< QgsVectorLayer > dest = std::make_unique< QgsVectorLayer >( widget->
uri().
uri, QString(), widget->
uri().
providerKey );
 
  556          setAppendDestination( widget->
uri().
uri, dest->fields() );
 
  565void QgsProcessingLayerOutputDestinationWidget::setAppendDestination( 
const QString &uri, 
const QgsFields &destFields )
 
  569  if ( mParametersGenerator )
 
  570    props = mParametersGenerator->createProcessingParameters();
 
  571  props.insert( mParameter->name(), uri );
 
  580      widget->
setPanelTitle( tr( 
"Append \"%1\" to Layer" ).arg( mParameter->description() ) );
 
  581      if ( !mRemapDefinition.fieldMap().isEmpty() )
 
  584      panel->openPanel( widget );
 
  600void QgsProcessingLayerOutputDestinationWidget::selectEncoding()
 
  605    mEncoding = dialog.encoding();
 
  607    settings.
setValue( QStringLiteral( 
"/Processing/encoding" ), mEncoding );
 
  608    emit destinationChanged();
 
  612void QgsProcessingLayerOutputDestinationWidget::textChanged( 
const QString &text )
 
  614  mUseTemporary = text.isEmpty();
 
  615  mUseRemapping = 
false;
 
  616  emit destinationChanged();
 
  620QString QgsProcessingLayerOutputDestinationWidget::mimeDataToPath( 
const QMimeData *data )
 
  628         && u.layerType == QLatin1String( 
"vector" ) && u.providerKey == QLatin1String( 
"ogr" ) )
 
  634              && u.layerType == QLatin1String( 
"raster" ) && u.providerKey == QLatin1String( 
"gdal" ) )
 
  640              && u.layerType == QLatin1String( 
"pointcloud" ) && ( u.providerKey == QLatin1String( 
"ept" ) || u.providerKey == QLatin1String( 
"pdal" ) ) )
 
  647              && u.layerType == QLatin1String( 
"mesh" ) && u.providerKey == QLatin1String( 
"mdal" ) )
 
  652              && u.layerType == QLatin1String( 
"directory" ) )
 
  657  if ( !uriList.isEmpty() )
 
  661  QStringList rawPaths;
 
  662  if ( data->hasUrls() )
 
  664    const QList< QUrl > urls = data->urls();
 
  665    rawPaths.reserve( urls.count() );
 
  666    for ( 
const QUrl &url : urls )
 
  668      const QString local =  url.toLocalFile();
 
  669      if ( !rawPaths.contains( local ) )
 
  670        rawPaths.append( local );
 
  673  if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
 
  674    rawPaths.append( data->text() );
 
  676  for ( 
const QString &path : std::as_const( rawPaths ) )
 
  678    QFileInfo file( path );
 
  696void QgsProcessingLayerOutputDestinationWidget::dragEnterEvent( QDragEnterEvent *event )
 
  698  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  701  const QString path = mimeDataToPath( event->mimeData() );
 
  702  if ( !path.isEmpty() )
 
  705    event->setDropAction( Qt::CopyAction );
 
  707    leText->setHighlighted( 
true );
 
  711void QgsProcessingLayerOutputDestinationWidget::dragLeaveEvent( QDragLeaveEvent *event )
 
  713  QWidget::dragLeaveEvent( event );
 
  714  if ( leText->isHighlighted() )
 
  717    leText->setHighlighted( 
false );
 
  721void QgsProcessingLayerOutputDestinationWidget::dropEvent( QDropEvent *event )
 
  723  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  726  const QString path = mimeDataToPath( event->mimeData() );
 
  727  if ( !path.isEmpty() )
 
  730    setFocus( Qt::MouseFocusReason );
 
  731    event->setDropAction( Qt::CopyAction );
 
  735  leText->setHighlighted( 
false );
 
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.
 
@ Available
Properties are available.
 
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.
 
@ FlagOptional
Parameter is optional.
 
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 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.
 
QgsProcessingAlgorithm::PropertyAvailability availability
Availability of the properties. By default properties are not available.