17#include "moc_qgsprocessingmaplayercombobox.cpp"
35#include <QDragEnterEvent>
45 , mParameter( parameter->clone() )
47 QHBoxLayout *layout =
new QHBoxLayout();
48 layout->setContentsMargins( 0, 0, 0, 0 );
49 layout->setSpacing( 6 );
52 layout->addWidget( mCombo );
53 layout->setAlignment( mCombo, Qt::AlignTop );
58 mIterateButton =
new QToolButton();
60 mIterateButton->setToolTip( tr(
"Iterate over this layer, creating a separate output for every feature in the layer" ) );
61 mIterateButton->setCheckable(
true );
62 mIterateButton->setAutoRaise(
true );
65 mIterateButton->setFixedSize( 2 *
static_cast< int >( 1.25 * iconSize / 2.0 ), 2 *
static_cast< int >( iconSize * 1.1 / 2.0 ) );
66 mIterateButton->setIconSize( QSize( iconSize, iconSize ) );
68 layout->addWidget( mIterateButton );
69 layout->setAlignment( mIterateButton, Qt::AlignTop );
74 mSettingsButton =
new QToolButton();
76 mSettingsButton->setToolTip( tr(
"Advanced options" ) );
79 mSettingsButton->setFixedSize( 2 *
static_cast< int >( 1.25 * iconSize / 2.0 ), 2 *
static_cast< int >( iconSize * 1.1 / 2.0 ) );
80 mSettingsButton->setIconSize( QSize( iconSize, iconSize ) );
81 mSettingsButton->setAutoRaise(
true );
83 connect( mSettingsButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::showSourceOptions );
84 layout->addWidget( mSettingsButton );
85 layout->setAlignment( mSettingsButton, Qt::AlignTop );
88 mSelectButton =
new QToolButton();
89 mSelectButton->setText( QString( QChar( 0x2026 ) ) );
90 mSelectButton->setToolTip( tr(
"Select input" ) );
91 layout->addWidget( mSelectButton );
92 layout->setAlignment( mSelectButton, Qt::AlignTop );
95 mFeatureSourceMenu =
new QMenu(
this );
96 QAction *selectFromFileAction =
new QAction( tr(
"Select File…" ), mFeatureSourceMenu );
97 connect( selectFromFileAction, &QAction::triggered,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
98 mFeatureSourceMenu->addAction( selectFromFileAction );
99 QAction *browseForLayerAction =
new QAction( tr(
"Browse for Layer…" ), mFeatureSourceMenu );
100 connect( browseForLayerAction, &QAction::triggered,
this, &QgsProcessingMapLayerComboBox::browseForLayer );
101 mFeatureSourceMenu->addAction( browseForLayerAction );
102 mSelectButton->setMenu( mFeatureSourceMenu );
103 mSelectButton->setPopupMode( QToolButton::InstantPopup );
107 connect( mSelectButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
110 QVBoxLayout *vl =
new QVBoxLayout();
111 vl->setContentsMargins( 0, 0, 0, 0 );
113 vl->addLayout( layout );
119 mUseSelectionCheckBox =
new QCheckBox( tr(
"Selected features only" ) );
120 mUseSelectionCheckBox->setChecked(
false );
121 mUseSelectionCheckBox->setEnabled(
false );
122 vl->addWidget( mUseSelectionCheckBox );
125 bool mayBeRaster {
false };
129 QList<int> dataTypes;
161 QList<int> dataTypes;
186 if ( settings.
value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
187 mCombo->setShowCrs(
true );
190 mCombo->setFilters( filters );
197 mCombo->setExcludedProviders( mCombo->excludedProviders() << QStringLiteral(
"virtualraster" ) );
202 mCombo->setAllowEmptyLayer(
true );
203 mCombo->setLayer(
nullptr );
207 if ( mUseSelectionCheckBox )
208 connect( mUseSelectionCheckBox, &QCheckBox::toggled,
this, [ = ]
210 if ( !mBlockChangedSignal )
216 setAcceptDrops(
true );
218 onLayerChanged( mCombo->currentLayer() );
221QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() =
default;
223void QgsProcessingMapLayerComboBox::setLayer(
QgsMapLayer *layer )
226 mCombo->setLayer( layer );
229QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
231 return mCombo->currentLayer();
234QString QgsProcessingMapLayerComboBox::currentText()
236 return mCombo->currentText();
239void QgsProcessingMapLayerComboBox::setValue(
const QVariant &value,
QgsProcessingContext &context )
247 QVariant val = value;
249 bool selectedOnly =
false;
250 bool iterate =
false;
251 if ( val.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
265 mFilterExpression.clear();
266 mIsOverridingDefaultGeometryCheck =
false;
270 if ( val.userType() == qMetaTypeId<QgsProperty>() )
282 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
283 if ( !layer && val.userType() == QMetaType::Type::QString )
290 mBlockChangedSignal++;
293 found =
static_cast< bool >( currentLayer() );
294 bool changed = found && ( currentLayer() != prevLayer );
295 if ( found && mUseSelectionCheckBox )
297 const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
298 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
301 mUseSelectionCheckBox->setEnabled(
true );
302 mUseSelectionCheckBox->setChecked( selectedOnly );
306 mUseSelectionCheckBox->setChecked(
false );
307 mUseSelectionCheckBox->setEnabled(
false );
310 if ( mIterateButton )
312 mIterateButton->setChecked( iterate );
315 mBlockChangedSignal--;
322 const QString
string = val.toString();
323 if ( mIterateButton )
324 mIterateButton->setChecked( iterate );
326 if ( !
string.isEmpty() )
328 mBlockChangedSignal++;
329 if ( mCombo->findText(
string ) < 0 )
331 QStringList additional = mCombo->additionalItems();
332 additional.append(
string );
333 mCombo->setAdditionalItems( additional );
335 mCombo->setCurrentIndex( mCombo->findText(
string ) );
336 if ( mUseSelectionCheckBox )
338 mUseSelectionCheckBox->setChecked(
false );
339 mUseSelectionCheckBox->setEnabled(
false );
341 mBlockChangedSignal--;
342 if ( !mBlockChangedSignal )
347 mCombo->setLayer(
nullptr );
348 if ( mUseSelectionCheckBox )
350 mUseSelectionCheckBox->setChecked(
false );
351 mUseSelectionCheckBox->setEnabled(
false );
357QVariant QgsProcessingMapLayerComboBox::value()
const
359 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
360 return mCombo->currentText();
362 const bool iterate = mIterateButton && mIterateButton->isChecked();
363 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
366 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
369 | ( mIsOverridingDefaultGeometryCheck ?
Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck :
Qgis::ProcessingFeatureSourceDefinitionFlags() ),
370 mGeometryCheck, mFilterExpression );
376 if ( !mCombo->currentText().isEmpty() )
378 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
381 | ( mIsOverridingDefaultGeometryCheck ?
Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck :
Qgis::ProcessingFeatureSourceDefinitionFlags() ),
382 mGeometryCheck, mFilterExpression );
384 return mCombo->currentText();
393 mCombo->setProject( context.
project() );
396void QgsProcessingMapLayerComboBox::setEditable(
bool editable )
398 mCombo->setEditable( editable );
401bool QgsProcessingMapLayerComboBox::isEditable()
const
403 return mCombo->isEditable();
406QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData(
const QMimeData *data,
bool &incompatibleLayerSelected )
const
408 incompatibleLayerSelected =
false;
415 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
419 incompatibleLayerSelected =
true;
428QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData(
const QMimeData *data )
const
435 && u.layerType == QLatin1String(
"vector" ) )
440 bool acceptable =
false;
471 && u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" ) )
474 && u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" ) )
484 if ( u.layerType == QLatin1String(
"vector" ) && u.providerKey == QLatin1String(
"ogr" ) )
510 else if ( u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" )
513 else if ( u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" )
518 if ( !uriList.isEmpty() )
522 QStringList rawPaths;
523 if ( data->hasUrls() )
525 const QList< QUrl > urls = data->urls();
526 rawPaths.reserve( urls.count() );
527 for (
const QUrl &url : urls )
529 const QString local = url.toLocalFile();
530 if ( !rawPaths.contains( local ) )
531 rawPaths.append( local );
534 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
535 rawPaths.append( data->text() );
537 for (
const QString &path : std::as_const( rawPaths ) )
539 QFileInfo file( path );
550void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
552 if ( !( event->possibleActions() & Qt::CopyAction ) )
555 bool incompatibleLayerSelected =
false;
556 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
557 const QString uri = compatibleUriFromMimeData( event->mimeData() );
558 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
561 event->setDropAction( Qt::CopyAction );
564 mCombo->mHighlight =
true;
569void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
571 QWidget::dragLeaveEvent( event );
576 mCombo->mHighlight =
false;
581void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
583 if ( !( event->possibleActions() & Qt::CopyAction ) )
586 bool incompatibleLayerSelected =
false;
587 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
588 const QString uri = compatibleUriFromMimeData( event->mimeData() );
589 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
592 setFocus( Qt::MouseFocusReason );
593 event->setDropAction( Qt::CopyAction );
596 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
599 mCombo->mHighlight =
false;
603void QgsProcessingMapLayerComboBox::onLayerChanged(
QgsMapLayer *layer )
607 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
609 if (
QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
613 if ( vl->selectedFeatureCount() == 0 )
614 mUseSelectionCheckBox->setChecked(
false );
615 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
621 if ( !mBlockChangedSignal )
627 if ( selected.isEmpty() )
628 mUseSelectionCheckBox->setChecked(
false );
629 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
632void QgsProcessingMapLayerComboBox::showSourceOptions()
636 QgsProcessingFeatureSourceOptionsWidget *widget =
new QgsProcessingFeatureSourceOptionsWidget();
637 widget->setPanelTitle( tr(
"%1 Options" ).arg( mParameter->description() ) );
638 widget->setLayer( qobject_cast< QgsVectorLayer * >( mCombo->currentLayer() ) );
640 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
641 widget->setFeatureLimit( mFeatureLimit );
642 widget->setFilterExpression( mFilterExpression );
644 panel->openPanel( widget );
648 bool changed =
false;
649 changed = changed | ( widget->featureLimit() != mFeatureLimit );
650 changed = changed | ( widget->filterExpression() != mFilterExpression );
651 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
652 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
654 mFeatureLimit = widget->featureLimit();
655 mFilterExpression = widget->filterExpression();
656 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
657 mGeometryCheck = widget->geometryCheckMethod();
665void QgsProcessingMapLayerComboBox::selectFromFile()
668 const QString initialValue = currentText();
671 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
673 else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() !=
'.' )
674 path = QFileInfo( initialValue ).path();
675 else if ( settings.
contains( QStringLiteral(
"/Processing/LastInputPath" ) ) )
676 path = settings.
value( QStringLiteral(
"/Processing/LastInputPath" ) ).toString();
680 filter = generator->createFileFilter();
682 filter = QObject::tr(
"All files (*.*)" );
684 const QString filename = QFileDialog::getOpenFileName(
this, tr(
"Select File" ), path, filter );
685 if ( filename.isEmpty() )
688 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filename ).path() );
690 setValue( filename, context );
693void QgsProcessingMapLayerComboBox::browseForLayer()
698 widget->
setPanelTitle( tr(
"Browse for \"%1\"" ).arg( mParameter->description() ) );
700 panel->openPanel( widget );
709 if ( widget->
uri().
uri.isEmpty() )
710 setValue( QVariant(), context );
712 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.