34#include <QDragEnterEvent>
44 , mParameter( parameter->clone() )
46 QHBoxLayout *layout =
new QHBoxLayout();
47 layout->setContentsMargins( 0, 0, 0, 0 );
48 layout->setSpacing( 6 );
51 layout->addWidget( mCombo );
52 layout->setAlignment( mCombo, Qt::AlignTop );
57 mIterateButton =
new QToolButton();
59 mIterateButton->setToolTip( tr(
"Iterate over this layer, creating a separate output for every feature in the layer" ) );
60 mIterateButton->setCheckable(
true );
61 mIterateButton->setAutoRaise(
true );
64 mIterateButton->setFixedSize( 2 *
static_cast< int >( 1.25 * iconSize / 2.0 ), 2 *
static_cast< int >( iconSize * 1.1 / 2.0 ) );
65 mIterateButton->setIconSize( QSize( iconSize, iconSize ) );
67 layout->addWidget( mIterateButton );
68 layout->setAlignment( mIterateButton, Qt::AlignTop );
73 mSettingsButton =
new QToolButton();
75 mSettingsButton->setToolTip( tr(
"Advanced options" ) );
78 mSettingsButton->setFixedSize( 2 *
static_cast< int >( 1.25 * iconSize / 2.0 ), 2 *
static_cast< int >( iconSize * 1.1 / 2.0 ) );
79 mSettingsButton->setIconSize( QSize( iconSize, iconSize ) );
80 mSettingsButton->setAutoRaise(
true );
82 connect( mSettingsButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::showSourceOptions );
83 layout->addWidget( mSettingsButton );
84 layout->setAlignment( mSettingsButton, Qt::AlignTop );
87 mSelectButton =
new QToolButton();
88 mSelectButton->setText( QString( QChar( 0x2026 ) ) );
89 mSelectButton->setToolTip( tr(
"Select input" ) );
90 layout->addWidget( mSelectButton );
91 layout->setAlignment( mSelectButton, Qt::AlignTop );
94 mFeatureSourceMenu =
new QMenu(
this );
95 QAction *selectFromFileAction =
new QAction( tr(
"Select File…" ), mFeatureSourceMenu );
96 connect( selectFromFileAction, &QAction::triggered,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
97 mFeatureSourceMenu->addAction( selectFromFileAction );
98 QAction *browseForLayerAction =
new QAction( tr(
"Browse for Layer…" ), mFeatureSourceMenu );
99 connect( browseForLayerAction, &QAction::triggered,
this, &QgsProcessingMapLayerComboBox::browseForLayer );
100 mFeatureSourceMenu->addAction( browseForLayerAction );
101 mSelectButton->setMenu( mFeatureSourceMenu );
102 mSelectButton->setPopupMode( QToolButton::InstantPopup );
106 connect( mSelectButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
109 QVBoxLayout *vl =
new QVBoxLayout();
110 vl->setContentsMargins( 0, 0, 0, 0 );
112 vl->addLayout( layout );
118 mUseSelectionCheckBox =
new QCheckBox( tr(
"Selected features only" ) );
119 mUseSelectionCheckBox->setChecked(
false );
120 mUseSelectionCheckBox->setEnabled(
false );
121 vl->addWidget( mUseSelectionCheckBox );
124 bool mayBeRaster {
false };
128 QList<int> dataTypes;
160 QList<int> dataTypes;
185 if ( settings.
value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
186 mCombo->setShowCrs(
true );
189 mCombo->setFilters( filters );
191 mCombo->setExcludedProviders( QStringList() << QStringLiteral(
"grass" ) );
198 mCombo->setExcludedProviders( mCombo->excludedProviders() << QStringLiteral(
"virtualraster" ) );
203 mCombo->setAllowEmptyLayer(
true );
204 mCombo->setLayer(
nullptr );
208 if ( mUseSelectionCheckBox )
209 connect( mUseSelectionCheckBox, &QCheckBox::toggled,
this, [ = ]
211 if ( !mBlockChangedSignal )
217 setAcceptDrops(
true );
219 onLayerChanged( mCombo->currentLayer() );
222QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() =
default;
224void QgsProcessingMapLayerComboBox::setLayer(
QgsMapLayer *layer )
227 mCombo->setLayer( layer );
230QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
232 return mCombo->currentLayer();
235QString QgsProcessingMapLayerComboBox::currentText()
237 return mCombo->currentText();
240void QgsProcessingMapLayerComboBox::setValue(
const QVariant &value,
QgsProcessingContext &context )
248 QVariant val = value;
250 bool selectedOnly =
false;
251 bool iterate =
false;
252 if ( val.userType() == QMetaType::type(
"QgsProcessingFeatureSourceDefinition" ) )
266 mFilterExpression.clear();
267 mIsOverridingDefaultGeometryCheck =
false;
271 if ( val.userType() == QMetaType::type(
"QgsProperty" ) )
283 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
284 if ( !layer && val.userType() == QMetaType::Type::QString )
291 mBlockChangedSignal++;
294 found =
static_cast< bool >( currentLayer() );
295 bool changed = found && ( currentLayer() != prevLayer );
296 if ( found && mUseSelectionCheckBox )
298 const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
299 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
302 mUseSelectionCheckBox->setEnabled(
true );
303 mUseSelectionCheckBox->setChecked( selectedOnly );
307 mUseSelectionCheckBox->setChecked(
false );
308 mUseSelectionCheckBox->setEnabled(
false );
311 if ( mIterateButton )
313 mIterateButton->setChecked( iterate );
316 mBlockChangedSignal--;
323 const QString
string = val.toString();
324 if ( mIterateButton )
325 mIterateButton->setChecked( iterate );
327 if ( !
string.isEmpty() )
329 mBlockChangedSignal++;
330 if ( mCombo->findText(
string ) < 0 )
332 QStringList additional = mCombo->additionalItems();
333 additional.append(
string );
334 mCombo->setAdditionalItems( additional );
336 mCombo->setCurrentIndex( mCombo->findText(
string ) );
337 if ( mUseSelectionCheckBox )
339 mUseSelectionCheckBox->setChecked(
false );
340 mUseSelectionCheckBox->setEnabled(
false );
342 mBlockChangedSignal--;
343 if ( !mBlockChangedSignal )
348 mCombo->setLayer(
nullptr );
349 if ( mUseSelectionCheckBox )
351 mUseSelectionCheckBox->setChecked(
false );
352 mUseSelectionCheckBox->setEnabled(
false );
358QVariant QgsProcessingMapLayerComboBox::value()
const
360 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
361 return mCombo->currentText();
363 const bool iterate = mIterateButton && mIterateButton->isChecked();
364 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
367 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
370 | ( mIsOverridingDefaultGeometryCheck ?
Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck :
Qgis::ProcessingFeatureSourceDefinitionFlags() ),
371 mGeometryCheck, mFilterExpression );
377 if ( !mCombo->currentText().isEmpty() )
379 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
382 | ( mIsOverridingDefaultGeometryCheck ?
Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck :
Qgis::ProcessingFeatureSourceDefinitionFlags() ),
383 mGeometryCheck, mFilterExpression );
385 return mCombo->currentText();
394 mCombo->setProject( context.
project() );
397void QgsProcessingMapLayerComboBox::setEditable(
bool editable )
399 mCombo->setEditable( editable );
402bool QgsProcessingMapLayerComboBox::isEditable()
const
404 return mCombo->isEditable();
407QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData(
const QMimeData *data,
bool &incompatibleLayerSelected )
const
409 incompatibleLayerSelected =
false;
416 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
420 incompatibleLayerSelected =
true;
429QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData(
const QMimeData *data )
const
436 && u.layerType == QLatin1String(
"vector" ) )
441 bool acceptable =
false;
472 && u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" ) )
475 && u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" ) )
485 if ( u.layerType == QLatin1String(
"vector" ) && u.providerKey == QLatin1String(
"ogr" ) )
511 else if ( u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" )
514 else if ( u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" )
519 if ( !uriList.isEmpty() )
523 QStringList rawPaths;
524 if ( data->hasUrls() )
526 const QList< QUrl > urls = data->urls();
527 rawPaths.reserve( urls.count() );
528 for (
const QUrl &url : urls )
530 const QString local = url.toLocalFile();
531 if ( !rawPaths.contains( local ) )
532 rawPaths.append( local );
535 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
536 rawPaths.append( data->text() );
538 for (
const QString &path : std::as_const( rawPaths ) )
540 QFileInfo file( path );
551void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
553 if ( !( event->possibleActions() & Qt::CopyAction ) )
556 bool incompatibleLayerSelected =
false;
557 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
558 const QString uri = compatibleUriFromMimeData( event->mimeData() );
559 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
562 event->setDropAction( Qt::CopyAction );
565 mCombo->mHighlight =
true;
570void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
572 QWidget::dragLeaveEvent( event );
577 mCombo->mHighlight =
false;
582void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
584 if ( !( event->possibleActions() & Qt::CopyAction ) )
587 bool incompatibleLayerSelected =
false;
588 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
589 const QString uri = compatibleUriFromMimeData( event->mimeData() );
590 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
593 setFocus( Qt::MouseFocusReason );
594 event->setDropAction( Qt::CopyAction );
597 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
600 mCombo->mHighlight =
false;
604void QgsProcessingMapLayerComboBox::onLayerChanged(
QgsMapLayer *layer )
608 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
610 if (
QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
614 if ( vl->selectedFeatureCount() == 0 )
615 mUseSelectionCheckBox->setChecked(
false );
616 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
622 if ( !mBlockChangedSignal )
628 if ( selected.isEmpty() )
629 mUseSelectionCheckBox->setChecked(
false );
630 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
633void QgsProcessingMapLayerComboBox::showSourceOptions()
637 QgsProcessingFeatureSourceOptionsWidget *widget =
new QgsProcessingFeatureSourceOptionsWidget();
638 widget->setPanelTitle( tr(
"%1 Options" ).arg( mParameter->description() ) );
639 widget->setLayer( qobject_cast< QgsVectorLayer * >( mCombo->currentLayer() ) );
641 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
642 widget->setFeatureLimit( mFeatureLimit );
643 widget->setFilterExpression( mFilterExpression );
645 panel->openPanel( widget );
649 bool changed =
false;
650 changed = changed | ( widget->featureLimit() != mFeatureLimit );
651 changed = changed | ( widget->filterExpression() != mFilterExpression );
652 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
653 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
655 mFeatureLimit = widget->featureLimit();
656 mFilterExpression = widget->filterExpression();
657 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
658 mGeometryCheck = widget->geometryCheckMethod();
666void QgsProcessingMapLayerComboBox::selectFromFile()
669 const QString initialValue = currentText();
672 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
674 else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() !=
'.' )
675 path = QFileInfo( initialValue ).path();
676 else if ( settings.
contains( QStringLiteral(
"/Processing/LastInputPath" ) ) )
677 path = settings.
value( QStringLiteral(
"/Processing/LastInputPath" ) ).toString();
681 filter = generator->createFileFilter();
683 filter = QObject::tr(
"All files (*.*)" );
685 const QString filename = QFileDialog::getOpenFileName(
this, tr(
"Select File" ), path, filter );
686 if ( filename.isEmpty() )
689 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filename ).path() );
691 setValue( filename, context );
694void QgsProcessingMapLayerComboBox::browseForLayer()
699 widget->
setPanelTitle( tr(
"Browse for \"%1\"" ).arg( mParameter->description() ) );
701 panel->openPanel( widget );
710 if ( widget->
uri().
uri.isEmpty() )
711 setValue( QVariant(), context );
713 setValue( widget->
uri().
uri, context );
The Qgis class provides global constants for use throughout the application.
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ MapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
@ VectorAnyGeometry
Any vector layer with geometry.
@ VectorPoint
Vector point layers.
@ VectorPolygon
Vector polygon layers.
@ VectorLine
Vector line layers.
@ PointCloud
Point cloud layers.
@ CompatibleWithVirtualRaster
The processing provider's algorithms can work with QGIS virtualraster data provider....
@ PointCloudLayer
QgsPointCloudLayer.
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
@ CreateIndividualOutputPerInputFeature
If set, every feature processed from this source will be placed into its own individually created out...
@ OverrideDefaultGeometryCheck
If set, the default geometry check method (as dictated by QgsProcessingContext) will be overridden fo...
@ Optional
Parameter is optional.
QFlags< LayerFilter > LayerFilters
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Abstract interface for classes which generate a file filter string.
The QgsMapLayerComboBox class is a combo box which displays the list of layers.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Contains information about the context in which a processing algorithm is executed.
QgsExpressionContext & expressionContext()
Returns the expression context.
Encapsulates settings relating to a feature source input to a processing algorithm.
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
QgsProperty source
Source definition.
Qgis::InvalidGeometryCheck geometryCheck
Geometry check method to apply to this source.
Qgis::ProcessingFeatureSourceDefinitionFlags flags
Flags which dictate source behavior.
long long featureLimit
If set to a value > 0, places a limit on the maximum number of features which will be read from the s...
QString filterExpression
Optional expression filter to use for filtering features which will be read from the source.
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Standard
Standard algorithm dialog.
Base class for the definition of processing parameters.
An input feature source (such as vector layers) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A map layer parameter 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.
A vector layer (with or without geometry) parameter for processing algorithms.
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,...
QgsProject * project() const
Returns the project associated with the widget.
QgsBrowserGuiModel * browserModel() const
Returns the browser model associated with the widget.
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 QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
A store for object properties.
Qgis::PropertyType propertyType() const
Returns the property type.
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.
Represents a vector layer which manages a vector based data sets.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QSet< QgsFeatureId > QgsFeatureIds
QString uri
Identifier of the data source recognized by its providerKey.
QString providerKey
For "vector" / "raster" type: provider id.