20 #include "qgssettings.h"
29 #include <QHBoxLayout>
30 #include <QVBoxLayout>
31 #include <QToolButton>
33 #include <QDragEnterEvent>
36 #include <QFileDialog>
43 , mParameter( parameter->clone() )
45 QHBoxLayout *layout =
new QHBoxLayout();
46 layout->setContentsMargins( 0, 0, 0, 0 );
47 layout->setSpacing( 6 );
50 layout->addWidget( mCombo );
51 layout->setAlignment( mCombo, Qt::AlignTop );
56 mIterateButton =
new QToolButton();
58 mIterateButton->setToolTip( tr(
"Iterate over this layer, creating a separate output for every feature in the layer" ) );
59 mIterateButton->setCheckable(
true );
60 mIterateButton->setAutoRaise(
true );
63 mIterateButton->setFixedSize( 2 *
static_cast< int >( 1.25 *
iconSize / 2.0 ), 2 *
static_cast< int >(
iconSize * 1.1 / 2.0 ) );
66 layout->addWidget( mIterateButton );
67 layout->setAlignment( mIterateButton, Qt::AlignTop );
72 mSettingsButton =
new QToolButton();
74 mSettingsButton->setToolTip( tr(
"Advanced options" ) );
77 mSettingsButton->setFixedSize( 2 *
static_cast< int >( 1.25 *
iconSize / 2.0 ), 2 *
static_cast< int >(
iconSize * 1.1 / 2.0 ) );
79 mSettingsButton->setAutoRaise(
true );
81 connect( mSettingsButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::showSourceOptions );
82 layout->addWidget( mSettingsButton );
83 layout->setAlignment( mSettingsButton, Qt::AlignTop );
86 mSelectButton =
new QToolButton();
87 mSelectButton->setText( QString( QChar( 0x2026 ) ) );
88 mSelectButton->setToolTip( tr(
"Select input" ) );
89 layout->addWidget( mSelectButton );
90 layout->setAlignment( mSelectButton, Qt::AlignTop );
93 mFeatureSourceMenu =
new QMenu(
this );
94 QAction *selectFromFileAction =
new QAction( tr(
"Select File…" ), mFeatureSourceMenu );
95 connect( selectFromFileAction, &QAction::triggered,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
96 mFeatureSourceMenu->addAction( selectFromFileAction );
97 QAction *browseForLayerAction =
new QAction( tr(
"Browse for Layer…" ), mFeatureSourceMenu );
98 connect( browseForLayerAction, &QAction::triggered,
this, &QgsProcessingMapLayerComboBox::browseForLayer );
99 mFeatureSourceMenu->addAction( browseForLayerAction );
100 mSelectButton->setMenu( mFeatureSourceMenu );
101 mSelectButton->setPopupMode( QToolButton::InstantPopup );
105 connect( mSelectButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
108 QVBoxLayout *vl =
new QVBoxLayout();
109 vl->setContentsMargins( 0, 0, 0, 0 );
111 vl->addLayout( layout );
113 QgsMapLayerProxyModel::Filters filters = QgsMapLayerProxyModel::Filters();
117 mUseSelectionCheckBox =
new QCheckBox( tr(
"Selected features only" ) );
118 mUseSelectionCheckBox->setChecked(
false );
119 mUseSelectionCheckBox->setEnabled(
false );
120 vl->addWidget( mUseSelectionCheckBox );
125 QList<int> dataTypes;
152 QList<int> dataTypes;
171 QgsSettings settings;
172 if ( settings.value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
173 mCombo->setShowCrs(
true );
176 mCombo->setFilters( filters );
177 mCombo->setExcludedProviders( QStringList() << QStringLiteral(
"grass" ) );
181 mCombo->setAllowEmptyLayer(
true );
182 mCombo->setLayer(
nullptr );
186 if ( mUseSelectionCheckBox )
187 connect( mUseSelectionCheckBox, &QCheckBox::toggled,
this, [ = ]
189 if ( !mBlockChangedSignal )
195 setAcceptDrops(
true );
197 onLayerChanged( mCombo->currentLayer() );
200 QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() =
default;
202 void QgsProcessingMapLayerComboBox::setLayer(
QgsMapLayer *layer )
205 mCombo->setLayer( layer );
208 QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
210 return mCombo->currentLayer();
213 QString QgsProcessingMapLayerComboBox::currentText()
215 return mCombo->currentText();
218 void QgsProcessingMapLayerComboBox::setValue(
const QVariant &value,
QgsProcessingContext &context )
226 QVariant val = value;
228 bool selectedOnly =
false;
229 bool iterate =
false;
235 iterate = fromVar.
flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature;
237 mIsOverridingDefaultGeometryCheck = fromVar.
flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
243 mIsOverridingDefaultGeometryCheck =
false;
259 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
260 if ( !layer && val.type() == QVariant::String )
267 mBlockChangedSignal++;
270 found =
static_cast< bool >( currentLayer() );
271 bool changed = found && ( currentLayer() != prevLayer );
272 if ( found && mUseSelectionCheckBox )
274 const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
275 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
278 mUseSelectionCheckBox->setEnabled(
true );
279 mUseSelectionCheckBox->setChecked( selectedOnly );
283 mUseSelectionCheckBox->setChecked(
false );
284 mUseSelectionCheckBox->setEnabled(
false );
287 if ( mIterateButton )
289 mIterateButton->setChecked( iterate );
292 mBlockChangedSignal--;
299 const QString
string = val.toString();
300 if ( mIterateButton )
301 mIterateButton->setChecked( iterate );
303 if ( !
string.isEmpty() )
305 mBlockChangedSignal++;
306 if ( mCombo->findText(
string ) < 0 )
308 QStringList additional = mCombo->additionalItems();
309 additional.append(
string );
310 mCombo->setAdditionalItems( additional );
312 mCombo->setCurrentIndex( mCombo->findText(
string ) );
313 if ( mUseSelectionCheckBox )
315 mUseSelectionCheckBox->setChecked(
false );
316 mUseSelectionCheckBox->setEnabled(
false );
318 mBlockChangedSignal--;
319 if ( !mBlockChangedSignal )
324 mCombo->setLayer(
nullptr );
325 if ( mUseSelectionCheckBox )
327 mUseSelectionCheckBox->setChecked(
false );
328 mUseSelectionCheckBox->setEnabled(
false );
334 QVariant QgsProcessingMapLayerComboBox::value()
const
336 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
337 return mCombo->currentText();
339 const bool iterate = mIterateButton && mIterateButton->isChecked();
340 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
343 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
345 ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
346 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
353 if ( !mCombo->currentText().isEmpty() )
355 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
357 ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
358 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
361 return mCombo->currentText();
372 void QgsProcessingMapLayerComboBox::setEditable(
bool editable )
374 mCombo->setEditable( editable );
377 bool QgsProcessingMapLayerComboBox::isEditable()
const
379 return mCombo->isEditable();
382 QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData(
const QMimeData *data,
bool &incompatibleLayerSelected )
const
384 incompatibleLayerSelected =
false;
391 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
395 incompatibleLayerSelected =
true;
404 QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData(
const QMimeData *data )
const
411 && u.layerType == QLatin1String(
"vector" ) )
416 bool acceptable =
false;
447 && u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" ) )
450 && u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" ) )
460 if ( u.layerType == QLatin1String(
"vector" ) && u.providerKey == QLatin1String(
"ogr" ) )
486 else if ( u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" )
489 else if ( u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" )
494 if ( !uriList.isEmpty() )
498 QStringList rawPaths;
499 if ( data->hasUrls() )
501 const QList< QUrl > urls = data->urls();
502 rawPaths.reserve( urls.count() );
503 for (
const QUrl &url : urls )
505 const QString local = url.toLocalFile();
506 if ( !rawPaths.contains( local ) )
507 rawPaths.append( local );
510 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
511 rawPaths.append( data->text() );
513 for (
const QString &path : std::as_const( rawPaths ) )
515 QFileInfo file( path );
526 void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
528 if ( !( event->possibleActions() & Qt::CopyAction ) )
531 bool incompatibleLayerSelected =
false;
532 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
533 const QString uri = compatibleUriFromMimeData( event->mimeData() );
534 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
537 event->setDropAction( Qt::CopyAction );
540 mCombo->mHighlight =
true;
545 void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
547 QWidget::dragLeaveEvent( event );
552 mCombo->mHighlight =
false;
557 void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
559 if ( !( event->possibleActions() & Qt::CopyAction ) )
562 bool incompatibleLayerSelected =
false;
563 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
564 const QString uri = compatibleUriFromMimeData( event->mimeData() );
565 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
568 setFocus( Qt::MouseFocusReason );
569 event->setDropAction( Qt::CopyAction );
572 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
575 mCombo->mHighlight =
false;
579 void QgsProcessingMapLayerComboBox::onLayerChanged(
QgsMapLayer *layer )
583 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
585 if (
QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
589 if ( vl->selectedFeatureCount() == 0 )
590 mUseSelectionCheckBox->setChecked(
false );
591 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
597 if ( !mBlockChangedSignal )
603 if ( selected.isEmpty() )
604 mUseSelectionCheckBox->setChecked(
false );
605 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
608 void QgsProcessingMapLayerComboBox::showSourceOptions()
612 QgsProcessingFeatureSourceOptionsWidget *widget =
new QgsProcessingFeatureSourceOptionsWidget();
613 widget->setPanelTitle( tr(
"%1 Options" ).arg( mParameter->description() ) );
615 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
616 widget->setFeatureLimit( mFeatureLimit );
618 panel->openPanel( widget );
622 bool changed =
false;
623 changed = changed | ( widget->featureLimit() != mFeatureLimit );
624 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
625 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
627 mFeatureLimit = widget->featureLimit();
628 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
629 mGeometryCheck = widget->geometryCheckMethod();
637 void QgsProcessingMapLayerComboBox::selectFromFile()
639 QgsSettings settings;
640 const QString initialValue = currentText();
643 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
645 else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() !=
'.' )
646 path = QFileInfo( initialValue ).path();
647 else if ( settings.contains( QStringLiteral(
"/Processing/LastInputPath" ) ) )
648 path = settings.value( QStringLiteral(
"/Processing/LastInputPath" ) ).toString();
652 filter = generator->createFileFilter();
654 filter = QObject::tr(
"All files (*.*)" );
656 const QString filename = QFileDialog::getOpenFileName(
this, tr(
"Select File" ), path, filter );
657 if ( filename.isEmpty() )
660 settings.setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filename ).path() );
662 setValue( filename, context );
665 void QgsProcessingMapLayerComboBox::browseForLayer()
670 widget->
setPanelTitle( tr(
"Browse for \"%1\"" ).arg( mParameter->description() ) );
672 panel->openPanel( widget );
681 if ( widget->
uri().
uri.isEmpty() )
682 setValue( QVariant(), context );
684 setValue( widget->
uri().
uri, context );
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
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.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
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.
Flags flags
Flags which dictate source behavior.
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
QgsFeatureRequest::InvalidGeometryCheck geometryCheck
Geometry check method to apply to this source.
QgsProperty source
Source definition.
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...
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Standard
Standard algorithm dialog.
Base class for the definition of processing parameters.
@ FlagOptional
Parameter is optional.
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.
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,...
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)
Interprets a string as a map layer within the supplied context.
@ TypeVectorLine
Vector line layers.
@ TypeMapLayer
Any map layer type (raster or vector or mesh)
@ TypeVectorPolygon
Vector polygon layers.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ TypeRaster
Raster layers.
@ TypeVectorPoint
Vector point layers.
@ TypeVectorAnyGeometry
Any vector layer with geometry.
A store for object properties.
@ StaticProperty
Static property (QgsStaticProperty)
Type propertyType() const
Returns the property type.
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 GeometryType geometryType(Type type) SIP_HOLDGIL
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.