29#include <QInputDialog> 
   37QgsProcessingLayerOutputDestinationWidget::QgsProcessingLayerOutputDestinationWidget( 
const QgsProcessingDestinationParameter *param, 
bool defaultSelection, QWidget *parent )
 
   40  , mDefaultSelection( defaultSelection )
 
   42  Q_ASSERT( mParameter );
 
   46  leText->setClearButtonEnabled( 
false );
 
   48  connect( leText, &QLineEdit::textEdited, 
this, &QgsProcessingLayerOutputDestinationWidget::textChanged );
 
   50  mMenu = 
new QMenu( 
this );
 
   51  connect( mMenu, &QMenu::aboutToShow, 
this, &QgsProcessingLayerOutputDestinationWidget::menuAboutToShow );
 
   52  mSelectButton->setMenu( mMenu );
 
   53  mSelectButton->setPopupMode( QToolButton::InstantPopup );
 
   57  settings.
setValue( QStringLiteral( 
"/Processing/encoding" ), mEncoding );
 
   59  if ( !mParameter->defaultValueForGui().isValid() )
 
   63      setValue( QVariant() );
 
   69    setValue( mParameter->defaultValueForGui() );
 
   72  setToolTip( mParameter->toolTip() );
 
   74  setAcceptDrops( 
true );
 
   75  leText->setAcceptDrops( 
false );
 
   78bool QgsProcessingLayerOutputDestinationWidget::outputIsSkipped()
 const 
   80  return leText->text().isEmpty() && !mUseTemporary;
 
   83void QgsProcessingLayerOutputDestinationWidget::setValue( 
const QVariant &value )
 
   85  const bool prevSkip = outputIsSkipped();
 
   86  mUseRemapping = 
false;
 
   87  if ( !value.isValid() || ( value.userType() == QMetaType::Type::QString && value.toString().isEmpty() ) )
 
  100    else if ( value.userType() == QMetaType::type( 
"QgsProcessingOutputLayerDefinition" ) )
 
  109        const QVariant prev = QgsProcessingLayerOutputDestinationWidget::value();
 
  111        mUseTemporary = 
false;
 
  113          emit skipOutputChanged( 
false );
 
  114        if ( prev != QgsProcessingLayerOutputDestinationWidget::value() )
 
  115          emit destinationChanged();
 
  119      mEncoding = def.
createOptions.value( QStringLiteral( 
"fileEncoding" ) ).toString();
 
  123      const QVariant prev = QgsProcessingLayerOutputDestinationWidget::value();
 
  124      leText->setText( value.toString() );
 
  125      mUseTemporary = 
false;
 
  127        emit skipOutputChanged( 
false );
 
  131        if ( prev.toString() != QgsProcessingLayerOutputDestinationWidget::value().toString() )
 
  132          emit destinationChanged();
 
  136        if ( prev.userType() != QMetaType::type( 
"QgsProcessingOutputLayerDefinition" ) ||
 
  138          emit destinationChanged();
 
  144QVariant QgsProcessingLayerOutputDestinationWidget::value()
 const 
  152  else if ( mUseTemporary && !mDefaultSelection )
 
  158    key = leText->text();
 
  167       && !key.startsWith( QLatin1String( 
"memory:" ) )
 
  168       && !key.startsWith( QLatin1String( 
"ogr:" ) )
 
  169       && !key.startsWith( QLatin1String( 
"postgres:" ) )
 
  170       && !key.startsWith( QLatin1String( 
"postgis:" ) )
 
  174    QString folder = QFileInfo( key ).path();
 
  178      QString defaultFolder = settings.
value( QStringLiteral( 
"/Processing/Configuration/OUTPUTS_FOLDER" ) ).toString();
 
  179      key = QDir( defaultFolder ).filePath( key );
 
  189  value.createOptions.insert( QStringLiteral( 
"fileEncoding" ), mEncoding );
 
  191    value.setRemappingDefinition( mRemapDefinition );
 
  207  mParametersGenerator = generator;
 
  210void QgsProcessingLayerOutputDestinationWidget::addOpenAfterRunningOption()
 
  212  Q_ASSERT( mOpenAfterRunningCheck == 
nullptr );
 
  213  mOpenAfterRunningCheck = 
new QCheckBox( tr( 
"Open output file after running algorithm" ) );
 
  214  mOpenAfterRunningCheck->setChecked( !outputIsSkipped() );
 
  215  mOpenAfterRunningCheck->setEnabled( !outputIsSkipped() );
 
  216  gridLayout->addWidget( mOpenAfterRunningCheck, 1, 0, 1, 2 );
 
  218  connect( 
this, &QgsProcessingLayerOutputDestinationWidget::skipOutputChanged, 
this, [ = ]( 
bool skipped )
 
  220    bool enabled = !skipped;
 
  221    mOpenAfterRunningCheck->setEnabled( enabled );
 
  222    mOpenAfterRunningCheck->setChecked( enabled );
 
  226bool QgsProcessingLayerOutputDestinationWidget::openAfterRunning()
 const 
  228  return mOpenAfterRunningCheck && mOpenAfterRunningCheck->isChecked();
 
  231void QgsProcessingLayerOutputDestinationWidget::menuAboutToShow()
 
  235  if ( !mDefaultSelection )
 
  239      QAction *actionSkipOutput = 
new QAction( tr( 
"Skip Output" ), 
this );
 
  240      connect( actionSkipOutput, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::skipOutput );
 
  241      mMenu->addAction( actionSkipOutput );
 
  244    QAction *actionSaveToTemp = 
nullptr;
 
  248      actionSaveToTemp = 
new QAction( tr( 
"Create Temporary Layer" ), 
this );
 
  252      actionSaveToTemp = 
new QAction( tr( 
"Save to a Temporary Directory" ), 
this );
 
  256      actionSaveToTemp = 
new QAction( tr( 
"Save to a Temporary File" ), 
this );
 
  259    connect( actionSaveToTemp, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::saveToTemporary );
 
  260    mMenu->addAction( actionSaveToTemp );
 
  263  QAction *actionSaveToFile = 
nullptr;
 
  266    actionSaveToFile = 
new QAction( tr( 
"Save to Directory…" ), 
this );
 
  267    connect( actionSaveToFile, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::selectDirectory );
 
  271    actionSaveToFile = 
new QAction( tr( 
"Save to File…" ), 
this );
 
  272    connect( actionSaveToFile, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::selectFile );
 
  274  mMenu->addAction( actionSaveToFile );
 
  278    QAction *actionSaveToGpkg = 
new QAction( tr( 
"Save to GeoPackage…" ), 
this );
 
  279    connect( actionSaveToGpkg, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::saveToGeopackage );
 
  280    mMenu->addAction( actionSaveToGpkg );
 
  282    QAction *actionSaveToDatabase = 
new QAction( tr( 
"Save to Database Table…" ), 
this );
 
  283    connect( actionSaveToDatabase, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::saveToDatabase );
 
  284    mMenu->addAction( actionSaveToDatabase );
 
  286    if ( mParameter->algorithm() && qgis::down_cast< const QgsProcessingParameterFeatureSink * >( mParameter )->supportsAppend() )
 
  288      mMenu->addSeparator();
 
  289      QAction *actionAppendToLayer = 
new QAction( tr( 
"Append to Layer…" ), 
this );
 
  290      connect( actionAppendToLayer, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::appendToLayer );
 
  291      mMenu->addAction( actionAppendToLayer );
 
  294        QAction *editMappingAction = 
new QAction( tr( 
"Edit Field Mapping…" ), 
this );
 
  295        connect( editMappingAction, &QAction::triggered, 
this, [ = ]
 
  297          setAppendDestination( value().value< QgsProcessingOutputLayerDefinition >().sink.staticValue().toString(), mRemapDefinition.destinationFields() );
 
  299        mMenu->addAction( editMappingAction );
 
  306    mMenu->addSeparator();
 
  307    QAction *actionSetEncoding = 
new QAction( tr( 
"Change File Encoding (%1)…" ).arg( mEncoding ), 
this );
 
  308    connect( actionSetEncoding, &QAction::triggered, 
this, &QgsProcessingLayerOutputDestinationWidget::selectEncoding );
 
  309    mMenu->addAction( actionSetEncoding );
 
  313void QgsProcessingLayerOutputDestinationWidget::skipOutput()
 
  315  leText->setPlaceholderText( tr( 
"[Skip output]" ) );
 
  317  mUseTemporary = 
false;
 
  318  mUseRemapping = 
false;
 
  320  emit skipOutputChanged( 
true );
 
  321  emit destinationChanged();
 
  324void QgsProcessingLayerOutputDestinationWidget::saveToTemporary()
 
  326  const bool prevSkip = outputIsSkipped();
 
  330    leText->setPlaceholderText( tr( 
"[Create temporary layer]" ) );
 
  334    leText->setPlaceholderText( tr( 
"[Save to temporary folder]" ) );
 
  338    leText->setPlaceholderText( tr( 
"[Save to temporary file]" ) );
 
  345  mUseTemporary = 
true;
 
  346  mUseRemapping = 
false;
 
  348    emit skipOutputChanged( 
false );
 
  349  emit destinationChanged();
 
  352void QgsProcessingLayerOutputDestinationWidget::selectDirectory()
 
  354  QString lastDir = leText->text();
 
  356  if ( lastDir.isEmpty() )
 
  357    lastDir = settings.
value( QStringLiteral( 
"/Processing/LastOutputPath" ), QDir::homePath() ).toString();
 
  359  const QString dirName = QFileDialog::getExistingDirectory( 
this, tr( 
"Select Directory" ), lastDir, QFileDialog::Options() );
 
  360  if ( !dirName.isEmpty() )
 
  362    leText->setText( QDir::toNativeSeparators( dirName ) );
 
  363    settings.
setValue( QStringLiteral( 
"/Processing/LastOutputPath" ), dirName );
 
  364    mUseTemporary = 
false;
 
  365    mUseRemapping = 
false;
 
  366    emit skipOutputChanged( 
false );
 
  367    emit destinationChanged();
 
  371void QgsProcessingLayerOutputDestinationWidget::selectFile()
 
  373  const QString fileFilter = mParameter->createFileFilter();
 
  381    lastExtPath = QStringLiteral( 
"/Processing/LastVectorOutputExt" );
 
  382    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString() ;
 
  386    lastExtPath = QStringLiteral( 
"/Processing/LastRasterOutputExt" );
 
  387    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
 
  391    lastExtPath = QStringLiteral( 
"/Processing/LastPointCloudOutputExt" );
 
  392    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
 
  396    lastExtPath = QStringLiteral( 
"/Processing/LastVectorTileOutputExt" );
 
  397    lastExt = settings.
value( lastExtPath, QStringLiteral( 
".%1" ).arg( mParameter->defaultFileExtension() ) ).toString();
 
  401  const QStringList filters = fileFilter.split( QStringLiteral( 
";;" ) );
 
  403  for ( 
const QString &f : filters )
 
  405    if ( f.contains( QStringLiteral( 
"*.%1" ).arg( lastExt ), Qt::CaseInsensitive ) )
 
  413  if ( settings.
contains( QStringLiteral( 
"/Processing/LastOutputPath" ) ) )
 
  414    path = settings.
value( QStringLiteral( 
"/Processing/LastOutputPath" ) ).toString();
 
  416    path = settings.
value( QStringLiteral( 
"/Processing/Configuration/OUTPUTS_FOLDER" ) ).toString();
 
  418  const bool dontConfirmOverwrite = mParameter->metadata().value( QStringLiteral( 
"widget_wrapper" ) ).toMap().value( QStringLiteral( 
"dontconfirmoverwrite" ), 
false ).toBool();
 
  420  QString filename = QFileDialog::getSaveFileName( 
this, tr( 
"Save file" ), path, fileFilter, &lastFilter, dontConfirmOverwrite ? QFileDialog::Options( QFileDialog::DontConfirmOverwrite ) : QFileDialog::Options() );
 
  421  if ( !filename.isEmpty() )
 
  423    mUseTemporary = 
false;
 
  424    mUseRemapping = 
false;
 
  427    leText->setText( filename );
 
  428    settings.
setValue( QStringLiteral( 
"/Processing/LastOutputPath" ), QFileInfo( filename ).path() );
 
  429    if ( !lastExtPath.isEmpty() )
 
  430      settings.
setValue( lastExtPath, QFileInfo( filename ).suffix().toLower() );
 
  432    emit skipOutputChanged( 
false );
 
  433    emit destinationChanged();
 
  440void QgsProcessingLayerOutputDestinationWidget::saveToGeopackage()
 
  443  QString lastPath = settings.
value( QStringLiteral( 
"/Processing/LastOutputPath" ), QString() ).toString();
 
  444  if ( lastPath.isEmpty() )
 
  445    lastPath = settings.
value( QStringLiteral( 
"/Processing/Configuration/OUTPUTS_FOLDER" ), QString() ).toString();
 
  447  QString filename =  QFileDialog::getSaveFileName( 
this, tr( 
"Save to GeoPackage" ), lastPath, tr( 
"GeoPackage files (*.gpkg);;All files (*.*)" ), 
nullptr, QFileDialog::DontConfirmOverwrite );
 
  452  if ( filename.isEmpty() )
 
  455  const QString layerName = QInputDialog::getText( 
this, tr( 
"Save to GeoPackage" ), tr( 
"Layer name" ), QLineEdit::Normal, mParameter->name().toLower() );
 
  456  if ( layerName.isEmpty() )
 
  459  mUseTemporary = 
false;
 
  460  mUseRemapping = 
false;
 
  464  settings.
setValue( QStringLiteral( 
"/Processing/LastOutputPath" ), QFileInfo( filename ).path() );
 
  473    if ( sink->hasGeometry() )
 
  474      geomColumn = QStringLiteral( 
"geom" );
 
  478  leText->setText( QStringLiteral( 
"ogr:%1" ).arg( uri.
uri() ) );
 
  480  emit skipOutputChanged( 
false );
 
  481  emit destinationChanged();
 
  484void QgsProcessingLayerOutputDestinationWidget::saveToDatabase()
 
  490        << QStringLiteral( 
"mssql" )
 
  491        << QStringLiteral( 
"ogr" )
 
  492        << QStringLiteral( 
"hana" )
 
  493        << QStringLiteral( 
"spatialite" )
 
  494        << QStringLiteral( 
"oracle" ), 
this );
 
  495    widget->
setPanelTitle( tr( 
"Save “%1” to Database Table" ).arg( mParameter->description() ) );
 
  498    panel->openPanel( widget );
 
  502      mUseTemporary = 
false;
 
  503      mUseRemapping = 
false;
 
  508        if ( sink->hasGeometry() )
 
  509          geomColumn = widget->
dataProviderKey() == QLatin1String( 
"oracle" ) ? QStringLiteral( 
"GEOM" ) : QStringLiteral( 
"geom" );
 
  518        leText->setText( QStringLiteral( 
"ogr:%1" ).arg( uri.
uri() ) );
 
  527      emit skipOutputChanged( 
false );
 
  528      emit destinationChanged();
 
  543void QgsProcessingLayerOutputDestinationWidget::appendToLayer()
 
  548    widget->
setPanelTitle( tr( 
"Append \"%1\" to Layer" ).arg( mParameter->description() ) );
 
  550    panel->openPanel( widget );
 
  558      if ( widget->
uri().
uri.isEmpty() )
 
  559        setValue( QVariant() );
 
  563        std::unique_ptr< QgsVectorLayer > dest = std::make_unique< QgsVectorLayer >( widget->
uri().
uri, QString(), widget->
uri().
providerKey );
 
  565          setAppendDestination( widget->
uri().
uri, dest->fields() );
 
  574void QgsProcessingLayerOutputDestinationWidget::setAppendDestination( 
const QString &uri, 
const QgsFields &destFields )
 
  578  if ( mParametersGenerator )
 
  579    props = mParametersGenerator->createProcessingParameters();
 
  580  props.insert( mParameter->name(), uri );
 
  589      widget->
setPanelTitle( tr( 
"Append \"%1\" to Layer" ).arg( mParameter->description() ) );
 
  590      if ( !mRemapDefinition.fieldMap().isEmpty() )
 
  593      panel->openPanel( widget );
 
  609void QgsProcessingLayerOutputDestinationWidget::selectEncoding()
 
  617    settings.
setValue( QStringLiteral( 
"/Processing/encoding" ), mEncoding );
 
  619    emit destinationChanged();
 
  623void QgsProcessingLayerOutputDestinationWidget::textChanged( 
const QString &text )
 
  625  mUseTemporary = text.isEmpty();
 
  626  mUseRemapping = 
false;
 
  627  emit destinationChanged();
 
  631QString QgsProcessingLayerOutputDestinationWidget::mimeDataToPath( 
const QMimeData *data )
 
  639         && u.layerType == QLatin1String( 
"vector" ) && u.providerKey == QLatin1String( 
"ogr" ) )
 
  645              && u.layerType == QLatin1String( 
"raster" ) && u.providerKey == QLatin1String( 
"gdal" ) )
 
  651              && u.layerType == QLatin1String( 
"pointcloud" ) && ( u.providerKey == QLatin1String( 
"ept" ) || u.providerKey == QLatin1String( 
"pdal" ) ) )
 
  656    else if ( ( mParameter->type() == QgsProcessingParameterMeshDestination::typeName()
 
  658              && u.layerType == QLatin1String( 
"mesh" ) && u.providerKey == QLatin1String( 
"mdal" ) )
 
  663              && u.layerType == QLatin1String( 
"directory" ) )
 
  668  if ( !uriList.isEmpty() )
 
  672  QStringList rawPaths;
 
  673  if ( data->hasUrls() )
 
  675    const QList< QUrl > urls = data->urls();
 
  676    rawPaths.reserve( urls.count() );
 
  677    for ( 
const QUrl &url : urls )
 
  679      const QString local =  url.toLocalFile();
 
  680      if ( !rawPaths.contains( local ) )
 
  681        rawPaths.append( local );
 
  684  if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
 
  685    rawPaths.append( data->text() );
 
  687  for ( 
const QString &path : std::as_const( rawPaths ) )
 
  689    QFileInfo file( path );
 
  707void QgsProcessingLayerOutputDestinationWidget::dragEnterEvent( QDragEnterEvent *event )
 
  709  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  712  const QString path = mimeDataToPath( event->mimeData() );
 
  713  if ( !path.isEmpty() )
 
  716    event->setDropAction( Qt::CopyAction );
 
  718    leText->setHighlighted( 
true );
 
  722void QgsProcessingLayerOutputDestinationWidget::dragLeaveEvent( QDragLeaveEvent *event )
 
  724  QWidget::dragLeaveEvent( event );
 
  725  if ( leText->isHighlighted() )
 
  728    leText->setHighlighted( 
false );
 
  732void QgsProcessingLayerOutputDestinationWidget::dropEvent( QDropEvent *event )
 
  734  if ( !( event->possibleActions() & Qt::CopyAction ) )
 
  737  const QString path = mimeDataToPath( event->mimeData() );
 
  738  if ( !path.isEmpty() )
 
  741    setFocus( Qt::MouseFocusReason );
 
  742    event->setDropAction( Qt::CopyAction );
 
  746  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.