QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
qgsprocessingmaplayercombobox.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingmaplayercombobox.cpp
3 -------------------------------
4 begin : June 2019
5 copyright : (C) 2019 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgsapplication.h"
20#include "qgsfeatureid.h"
21#include "qgsguiutils.h"
22#include "qgsmaplayercombobox.h"
23#include "qgsmimedatautils.h"
24#include "qgspanelwidget.h"
30#include "qgsproviderregistry.h"
31#include "qgssettings.h"
32#include "qgsvectorlayer.h"
33#include "qgswmsutils.h"
34
35#include <QAction>
36#include <QCheckBox>
37#include <QDragEnterEvent>
38#include <QFileDialog>
39#include <QHBoxLayout>
40#include <QMenu>
41#include <QString>
42#include <QToolButton>
43#include <QUrl>
44#include <QVBoxLayout>
45
46#include "moc_qgsprocessingmaplayercombobox.cpp"
47
48using namespace Qt::StringLiterals;
49
51
52QgsProcessingMapLayerComboBox::QgsProcessingMapLayerComboBox( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
53 : QWidget( parent )
54 , mParameter( parameter->clone() )
55{
56 QHBoxLayout *layout = new QHBoxLayout();
57 layout->setContentsMargins( 0, 0, 0, 0 );
58 layout->setSpacing( 6 );
59
60 mCombo = new QgsMapLayerComboBox();
61 layout->addWidget( mCombo );
62 layout->setAlignment( mCombo, Qt::AlignTop );
63
66 {
67 mIterateButton = new QToolButton();
68 mIterateButton->setIcon( QgsApplication::getThemeIcon( u"mIconIterate.svg"_s ) );
69 mIterateButton->setToolTip( tr( "Iterate over this layer, creating a separate output for every feature in the layer" ) );
70 mIterateButton->setCheckable( true );
71 mIterateButton->setAutoRaise( true );
72
73 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
74 mIterateButton->setFixedSize( 2 * static_cast<int>( 1.25 * iconSize / 2.0 ), 2 * static_cast<int>( iconSize * 1.1 / 2.0 ) );
75 mIterateButton->setIconSize( QSize( iconSize, iconSize ) );
76
77 layout->addWidget( mIterateButton );
78 layout->setAlignment( mIterateButton, Qt::AlignTop );
79 }
80
81 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
82 {
83 mSettingsButton = new QToolButton();
84 mSettingsButton->setIcon( QgsApplication::getThemeIcon( u"mActionOptions.svg"_s ) );
85 mSettingsButton->setToolTip( tr( "Advanced options" ) );
86
87 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
88 mSettingsButton->setFixedSize( 2 * static_cast<int>( 1.25 * iconSize / 2.0 ), 2 * static_cast<int>( iconSize * 1.1 / 2.0 ) );
89 mSettingsButton->setIconSize( QSize( iconSize, iconSize ) );
90 mSettingsButton->setAutoRaise( true );
91
92 connect( mSettingsButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::showSourceOptions );
93 layout->addWidget( mSettingsButton );
94 layout->setAlignment( mSettingsButton, Qt::AlignTop );
95 }
96 else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName() )
97 {
98 mSettingsButton = new QToolButton();
99 mSettingsButton->setIcon( QgsApplication::getThemeIcon( u"mActionOptions.svg"_s ) );
100 mSettingsButton->setToolTip( tr( "Advanced options" ) );
101 mSettingsButton->setEnabled( false ); // Only WMS layers will access raster advanced options for now
102
103 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
104 mSettingsButton->setFixedSize( 2 * static_cast<int>( 1.25 * iconSize / 2.0 ), 2 * static_cast<int>( iconSize * 1.1 / 2.0 ) );
105 mSettingsButton->setIconSize( QSize( iconSize, iconSize ) );
106 mSettingsButton->setAutoRaise( true );
107
108 connect( mSettingsButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::showRasterSourceOptions );
109 layout->addWidget( mSettingsButton );
110 layout->setAlignment( mSettingsButton, Qt::AlignTop );
111 }
112
113 mSelectButton = new QToolButton();
114 mSelectButton->setText( QString( QChar( 0x2026 ) ) );
115 mSelectButton->setToolTip( tr( "Select input" ) );
116 layout->addWidget( mSelectButton );
117 layout->setAlignment( mSelectButton, Qt::AlignTop );
118 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
119 {
120 mFeatureSourceMenu = new QMenu( this );
121 QAction *selectFromFileAction = new QAction( tr( "Select File…" ), mFeatureSourceMenu );
122 connect( selectFromFileAction, &QAction::triggered, this, &QgsProcessingMapLayerComboBox::selectFromFile );
123 mFeatureSourceMenu->addAction( selectFromFileAction );
124 QAction *browseForLayerAction = new QAction( tr( "Browse for Layer…" ), mFeatureSourceMenu );
125 connect( browseForLayerAction, &QAction::triggered, this, &QgsProcessingMapLayerComboBox::browseForLayer );
126 mFeatureSourceMenu->addAction( browseForLayerAction );
127 mSelectButton->setMenu( mFeatureSourceMenu );
128 mSelectButton->setPopupMode( QToolButton::InstantPopup );
129 }
130 else
131 {
132 connect( mSelectButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::selectFromFile );
133 }
134
135 QVBoxLayout *vl = new QVBoxLayout();
136 vl->setContentsMargins( 0, 0, 0, 0 );
137 vl->setSpacing( 6 );
138 vl->addLayout( layout );
139
141
143 {
144 mUseSelectionCheckBox = new QCheckBox( tr( "Selected features only" ) );
145 mUseSelectionCheckBox->setChecked( false );
146 mUseSelectionCheckBox->setEnabled( false );
147 vl->addWidget( mUseSelectionCheckBox );
148 }
149
150 bool mayBeRaster { false };
151
152 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
153 {
154 QList<int> dataTypes;
155 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
156 dataTypes = static_cast<QgsProcessingParameterFeatureSource *>( mParameter.get() )->dataTypes();
157 else if ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
158 dataTypes = static_cast<QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes();
159
160 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.isEmpty() )
162 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) ) )
164 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) )
166 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) )
168 if ( !filters )
170 }
171 else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName() )
172 {
173 mayBeRaster = true;
175 }
176 else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName() )
177 {
179 }
180 else if ( mParameter->type() == QgsProcessingParameterPointCloudLayer::typeName() )
181 {
183 }
184 else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
185 {
186 QList<int> dataTypes;
187 dataTypes = static_cast<QgsProcessingParameterMapLayer *>( mParameter.get() )->dataTypes();
188
189 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) )
191 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) )
193 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) ) )
195 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) )
197 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) )
199 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Raster ) ) )
200 {
201 mayBeRaster = true;
203 }
204 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Mesh ) ) )
206 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::PointCloud ) ) )
208 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Annotation ) ) )
210 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorTile ) ) )
212 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::TiledScene ) ) )
214 if ( !filters )
215 filters = Qgis::LayerFilter::All;
216 }
217
218 QgsSettings settings;
219 if ( settings.value( u"Processing/Configuration/SHOW_CRS_DEF"_s, true ).toBool() )
220 mCombo->setShowCrs( true );
221
222 if ( filters )
223 mCombo->setFilters( filters );
224
225 // Check compatibility with virtualraster data provider
226 // see https://github.com/qgis/QGIS/issues/55890
227 if ( mayBeRaster && ( !mParameter->provider() || !mParameter->provider()->flags().testFlag( Qgis::ProcessingProviderFlag::CompatibleWithVirtualRaster ) ) )
228 {
229 mCombo->setExcludedProviders( mCombo->excludedProviders() << u"virtualraster"_s );
230 }
231
232 if ( mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
233 {
234 mCombo->setAllowEmptyLayer( true );
235 mCombo->setLayer( nullptr );
236 }
237
238 connect( mCombo, &QgsMapLayerComboBox::layerChanged, this, &QgsProcessingMapLayerComboBox::onLayerChanged );
239 if ( mUseSelectionCheckBox )
240 connect( mUseSelectionCheckBox, &QCheckBox::toggled, this, [this] {
241 if ( !mBlockChangedSignal )
242 emit valueChanged();
243 } );
244
245 setLayout( vl );
246
247 setAcceptDrops( true );
248
249 onLayerChanged( mCombo->currentLayer() );
250}
251
252QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() = default;
253
254void QgsProcessingMapLayerComboBox::setLayer( QgsMapLayer *layer )
255{
256 if ( layer || mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
257 {
258 mCombo->setLayer( layer );
259 }
260}
261
262QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
263{
264 return mCombo->currentLayer();
265}
266
267QString QgsProcessingMapLayerComboBox::currentText()
268{
269 return mCombo->currentText();
270}
271
272void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessingContext &context )
273{
274 if ( !value.isValid() && mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
275 {
276 setLayer( nullptr );
277 return;
278 }
279
280 QVariant val = value;
281 bool found = false;
282 bool selectedOnly = false;
283 bool iterate = false;
284 if ( val.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
285 {
286 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
287 val = fromVar.source;
288 selectedOnly = fromVar.selectedFeaturesOnly;
290 mFeatureLimit = fromVar.featureLimit;
291 mFilterExpression = fromVar.filterExpression;
292 mIsOverridingDefaultGeometryCheck = fromVar.flags & Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck;
293 mGeometryCheck = fromVar.geometryCheck;
294 }
295 else
296 {
297 mFeatureLimit = -1;
298 mFilterExpression.clear();
299 mIsOverridingDefaultGeometryCheck = false;
301 }
302
303 if ( val.userType() == qMetaTypeId<QgsProcessingRasterLayerDefinition>() )
304 {
305 QgsProcessingRasterLayerDefinition fromVar = qvariant_cast<QgsProcessingRasterLayerDefinition>( val );
306 val = fromVar.source;
307 mRasterReferenceScale = fromVar.referenceScale;
308 mRasterDpi = fromVar.dpi;
309 }
310 else
311 {
312 mRasterReferenceScale = 0;
313 mRasterDpi = 96;
314 }
315
316 if ( val.userType() == qMetaTypeId<QgsProperty>() )
317 {
319 {
320 val = val.value<QgsProperty>().staticValue();
321 }
322 else
323 {
324 val = val.value<QgsProperty>().valueAsString( context.expressionContext(), mParameter->defaultValueForGui().toString() );
325 }
326 }
327
328 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( val.value<QObject *>() );
329 if ( !layer && val.userType() == QMetaType::Type::QString )
330 {
331 layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false );
332 }
333
334 if ( layer )
335 {
336 mBlockChangedSignal++;
337 QgsMapLayer *prevLayer = currentLayer();
338 setLayer( layer );
339 found = static_cast<bool>( currentLayer() );
340 bool changed = found && ( currentLayer() != prevLayer );
341 if ( found && mUseSelectionCheckBox )
342 {
343 const bool hasSelection = qobject_cast<QgsVectorLayer *>( layer ) && qobject_cast<QgsVectorLayer *>( layer )->selectedFeatureCount() > 0;
344 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
345 if ( hasSelection )
346 {
347 mUseSelectionCheckBox->setEnabled( true );
348 mUseSelectionCheckBox->setChecked( selectedOnly );
349 }
350 else
351 {
352 mUseSelectionCheckBox->setChecked( false );
353 mUseSelectionCheckBox->setEnabled( false );
354 }
355
356 if ( mIterateButton )
357 {
358 mIterateButton->setChecked( iterate );
359 }
360 }
361 mBlockChangedSignal--;
362 if ( changed )
363 emit valueChanged(); // and ensure we only ever raise one
364 }
365
366 if ( !found )
367 {
368 const QString string = val.toString();
369 if ( mIterateButton )
370 mIterateButton->setChecked( iterate );
371
372 if ( !string.isEmpty() )
373 {
374 mBlockChangedSignal++;
375 if ( mCombo->findText( string ) < 0 )
376 {
377 QStringList additional = mCombo->additionalItems();
378 additional.append( string );
379 mCombo->setAdditionalItems( additional );
380 }
381 mCombo->setCurrentIndex( mCombo->findText( string ) ); // this may or may not throw a signal, so let's block it..
382 if ( mUseSelectionCheckBox )
383 {
384 mUseSelectionCheckBox->setChecked( false );
385 mUseSelectionCheckBox->setEnabled( false );
386 }
387 mBlockChangedSignal--;
388 if ( !mBlockChangedSignal )
389 emit valueChanged(); // and ensure we only ever raise one
390 }
391 else if ( mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
392 {
393 mCombo->setLayer( nullptr );
394 if ( mUseSelectionCheckBox )
395 {
396 mUseSelectionCheckBox->setChecked( false );
397 mUseSelectionCheckBox->setEnabled( false );
398 }
399 }
400 }
401}
402
403QVariant QgsProcessingMapLayerComboBox::value() const
404{
405 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
406 return mCombo->currentText();
407
408 const bool iterate = mIterateButton && mIterateButton->isChecked();
409 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
410 if ( QgsMapLayer *layer = mCombo->currentLayer() )
411 {
412 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
414 else if ( mRasterReferenceScale != 0 )
415 return QgsProcessingRasterLayerDefinition( layer->id(), mRasterReferenceScale, mRasterDpi );
416 else
417 return layer->id();
418 }
419 else
420 {
421 if ( !mCombo->currentText().isEmpty() )
422 {
423 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
425 else if ( mRasterReferenceScale != 0 )
426 return QgsProcessingRasterLayerDefinition( mCombo->currentText(), mRasterReferenceScale, mRasterDpi );
427 else
428 return mCombo->currentText();
429 }
430 }
431 return QVariant();
432}
433
434void QgsProcessingMapLayerComboBox::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
435{
436 mBrowserModel = context.browserModel();
437 mCombo->setProject( context.project() );
438}
439
440void QgsProcessingMapLayerComboBox::setEditable( bool editable )
441{
442 mCombo->setEditable( editable );
443}
444
445bool QgsProcessingMapLayerComboBox::isEditable() const
446{
447 return mCombo->isEditable();
448}
449
450QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData( const QMimeData *data, bool &incompatibleLayerSelected ) const
451{
452 incompatibleLayerSelected = false;
454 for ( const QgsMimeDataUtils::Uri &u : uriList )
455 {
456 // is this uri from the current project?
457 if ( QgsMapLayer *layer = u.mapLayer() )
458 {
459 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
460 return layer;
461 else
462 {
463 incompatibleLayerSelected = true;
464 return nullptr;
465 }
466 }
467 }
468 return nullptr;
469}
470
471
472QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData( const QMimeData *data ) const
473{
475 for ( const QgsMimeDataUtils::Uri &u : uriList )
476 {
477 if ( ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName()
478 || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
479 && u.layerType == "vector"_L1 )
480 {
481 QList<int> dataTypes = mParameter->type() == QgsProcessingParameterFeatureSource::typeName() ? static_cast<QgsProcessingParameterFeatureSource *>( mParameter.get() )->dataTypes()
482 : ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() ? static_cast<QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes()
483 : QList<int>() );
484 bool acceptable = false;
485 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
486 {
488 acceptable = true;
489 break;
490
492 if ( dataTypes.isEmpty() || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) ) )
493 acceptable = true;
494 break;
495
497 if ( dataTypes.isEmpty() || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) )
498 acceptable = true;
499 break;
500
502 if ( dataTypes.isEmpty() || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) )
503 acceptable = true;
504 break;
505
507 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) )
508 acceptable = true;
509 break;
510 }
511 if ( acceptable )
512 return u.providerKey != "ogr"_L1 ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri;
513 }
514 else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName()
515 && u.layerType == "raster"_L1 && u.providerKey == "gdal"_L1 )
516 return u.uri;
517 else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName()
518 && u.layerType == "mesh"_L1 && u.providerKey == "mdal"_L1 )
519 return u.uri;
520 else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
521 {
522 QList<int> dataTypes = static_cast<QgsProcessingParameterMapLayer *>( mParameter.get() )->dataTypes();
523 if ( dataTypes.isEmpty() || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) ) )
524 {
525 return u.uri;
526 }
527
528 if ( u.layerType == "vector"_L1 && u.providerKey == "ogr"_L1 )
529 {
530 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
531 {
533 return u.uri;
534
536 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) ) )
537 return u.uri;
538 break;
539
541 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) )
542 return u.uri;
543 break;
544
546 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) )
547 return u.uri;
548 break;
549
551 return u.uri;
552 }
553 }
554 else if ( u.layerType == "raster"_L1 && u.providerKey == "gdal"_L1
555 && dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Raster ) ) )
556 return u.uri;
557 else if ( u.layerType == "mesh"_L1 && u.providerKey == "mdal"_L1
558 && dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Mesh ) ) )
559 return u.uri;
560 }
561 }
562 if ( !uriList.isEmpty() )
563 return QString();
564
565 // second chance -- files dragged from file explorer, outside of QGIS
566 QStringList rawPaths;
567 if ( data->hasUrls() )
568 {
569 const QList<QUrl> urls = data->urls();
570 rawPaths.reserve( urls.count() );
571 for ( const QUrl &url : urls )
572 {
573 const QString local = url.toLocalFile();
574 if ( !rawPaths.contains( local ) )
575 rawPaths.append( local );
576 }
577 }
578 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
579 rawPaths.append( data->text() );
580
581 for ( const QString &path : std::as_const( rawPaths ) )
582 {
583 QFileInfo file( path );
584 if ( file.isFile() )
585 {
586 // TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
587 return path;
588 }
589 }
590
591 return QString();
592}
593
594void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
595{
596 if ( !( event->possibleActions() & Qt::CopyAction ) )
597 return;
598
599 bool incompatibleLayerSelected = false;
600 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
601 const QString uri = compatibleUriFromMimeData( event->mimeData() );
602 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
603 {
604 // dragged an acceptable layer, phew
605 event->setDropAction( Qt::CopyAction );
606 event->accept();
607 mDragActive = true;
608 mCombo->mHighlight = true;
609 update();
610 }
611}
612
613void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
614{
615 QWidget::dragLeaveEvent( event );
616 if ( mDragActive )
617 {
618 event->accept();
619 mDragActive = false;
620 mCombo->mHighlight = false;
621 update();
622 }
623}
624
625void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
626{
627 if ( !( event->possibleActions() & Qt::CopyAction ) )
628 return;
629
630 bool incompatibleLayerSelected = false;
631 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
632 const QString uri = compatibleUriFromMimeData( event->mimeData() );
633 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
634 {
635 // dropped an acceptable layer, phew
636 setFocus( Qt::MouseFocusReason );
637 event->setDropAction( Qt::CopyAction );
638 event->accept();
639 QgsProcessingContext context;
640 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
641 }
642 mDragActive = false;
643 mCombo->mHighlight = false;
644 update();
645}
646
647void QgsProcessingMapLayerComboBox::onLayerChanged( QgsMapLayer *layer )
648{
649 if ( mUseSelectionCheckBox && mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
650 {
651 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
652 {
653 if ( QgsVectorLayer *prevLayer = qobject_cast<QgsVectorLayer *>( mPrevLayer ) )
654 {
655 disconnect( prevLayer, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
656 }
657 if ( vl->selectedFeatureCount() == 0 )
658 mUseSelectionCheckBox->setChecked( false );
659 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
660 connect( vl, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
661 }
662 }
663
664 if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName() )
665 {
666 // Only WMS layers whose parameter supports WmsScale and WmsDpi will access raster advanced options for now.
667 QgsProcessingParameterRasterLayer *rasterParameter = qgis::down_cast<QgsProcessingParameterRasterLayer *>( mParameter.get() );
668 const bool supportsRasterOptions = rasterParameter->parameterCapabilities().testFlag( Qgis::RasterProcessingParameterCapability::WmsScale ) || rasterParameter->parameterCapabilities().testFlag( Qgis::RasterProcessingParameterCapability::WmsDpi );
669 mSettingsButton->setEnabled( supportsRasterOptions && QgsWmsUtils::isWmsLayer( layer ) );
670 }
671
672 mPrevLayer = layer;
673 if ( !mBlockChangedSignal )
674 emit valueChanged();
675}
676
677void QgsProcessingMapLayerComboBox::selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &, bool )
678{
679 if ( selected.isEmpty() )
680 mUseSelectionCheckBox->setChecked( false );
681 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
682}
683
684void QgsProcessingMapLayerComboBox::showSourceOptions()
685{
686 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
687 {
688 QgsProcessingFeatureSourceOptionsWidget *widget = new QgsProcessingFeatureSourceOptionsWidget();
689 widget->setPanelTitle( tr( "%1 Options" ).arg( mParameter->description() ) );
690 widget->setLayer( qobject_cast<QgsVectorLayer *>( mCombo->currentLayer() ) );
691
692 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
693 widget->setFeatureLimit( mFeatureLimit );
694 widget->setFilterExpression( mFilterExpression );
695
696 panel->openPanel( widget );
697
698 connect( widget, &QgsPanelWidget::widgetChanged, this, [this, widget] {
699 bool changed = false;
700 changed = changed | ( widget->featureLimit() != mFeatureLimit );
701 changed = changed | ( widget->filterExpression() != mFilterExpression );
702 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
703 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
704
705 mFeatureLimit = widget->featureLimit();
706 mFilterExpression = widget->filterExpression();
707 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
708 mGeometryCheck = widget->geometryCheckMethod();
709
710 if ( changed )
711 emit valueChanged();
712 } );
713 }
714}
715
716void QgsProcessingMapLayerComboBox::showRasterSourceOptions()
717{
718 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
719 {
720 QgsProcessingRasterSourceOptionsWidget *widget = new QgsProcessingRasterSourceOptionsWidget();
721 widget->setPanelTitle( tr( "%1 Options" ).arg( mParameter->description() ) );
722 widget->setReferenceScale( mRasterReferenceScale );
723 widget->setDpi( mRasterDpi );
724
725 QgsProcessingParameterRasterLayer *rasterParameter = qgis::down_cast<QgsProcessingParameterRasterLayer *>( mParameter.get() );
726 widget->setWidgetParameterCapabilities( rasterParameter->parameterCapabilities() );
727
728 panel->openPanel( widget );
729
730 connect( widget, &QgsPanelWidget::widgetChanged, this, [this, widget] {
731 bool changed = false;
732 changed = changed | ( widget->referenceScale() != mRasterReferenceScale );
733 changed = changed | ( widget->dpi() != mRasterDpi );
734
735 mRasterReferenceScale = widget->referenceScale();
736 mRasterDpi = widget->dpi();
737
738 if ( changed )
739 emit valueChanged();
740 } );
741 }
742}
743
744void QgsProcessingMapLayerComboBox::selectFromFile()
745{
746 QgsSettings settings;
747 const QString initialValue = currentText();
748 QString path;
749
750 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
751 path = initialValue;
752 else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() != '.' )
753 path = QFileInfo( initialValue ).path();
754 else if ( settings.contains( u"/Processing/LastInputPath"_s ) )
755 path = settings.value( u"/Processing/LastInputPath"_s ).toString();
756
757 QString filter;
758 if ( const QgsFileFilterGenerator *generator = dynamic_cast<const QgsFileFilterGenerator *>( mParameter.get() ) )
759 filter = generator->createFileFilter();
760 else
761 filter = QObject::tr( "All files (*.*)" );
762
763 const QString filename = QFileDialog::getOpenFileName( this, tr( "Select File" ), path, filter );
764 if ( filename.isEmpty() )
765 return;
766
767 settings.setValue( u"/Processing/LastInputPath"_s, QFileInfo( filename ).path() );
768 QgsProcessingContext context;
769 setValue( filename, context );
770}
771
772void QgsProcessingMapLayerComboBox::browseForLayer()
773{
774 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
775 {
777 widget->setPanelTitle( tr( "Browse for \"%1\"" ).arg( mParameter->description() ) );
778
779 panel->openPanel( widget );
780
781 connect( widget, &QgsDataSourceSelectWidget::itemTriggered, this, [widget]( const QgsMimeDataUtils::Uri & ) {
782 widget->acceptPanel();
783 } );
784 connect( widget, &QgsPanelWidget::panelAccepted, this, [this, widget]() {
785 QgsProcessingContext context;
786 if ( widget->uri().uri.isEmpty() )
787 setValue( QVariant(), context );
788 else if ( widget->uri().providerKey == "ogr"_L1 )
789 setValue( widget->uri().uri, context );
790 else
791 setValue( QgsProcessingUtils::encodeProviderKeyAndUri( widget->uri().providerKey, widget->uri().uri ), context );
792 } );
793 }
794}
795
796
@ TiledScene
Tiled scene layers.
Definition qgis.h:3616
@ Annotation
Annotation layers.
Definition qgis.h:3614
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3610
@ VectorTile
Vector tile layers.
Definition qgis.h:3615
@ MapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer).
Definition qgis.h:3603
@ Mesh
Mesh layers.
Definition qgis.h:3611
@ Raster
Raster layers.
Definition qgis.h:3608
@ VectorAnyGeometry
Any vector layer with geometry.
Definition qgis.h:3604
@ VectorPoint
Vector point layers.
Definition qgis.h:3605
@ VectorPolygon
Vector polygon layers.
Definition qgis.h:3607
@ VectorLine
Vector line layers.
Definition qgis.h:3606
@ PointCloud
Point cloud layers.
Definition qgis.h:3613
@ WmsDpi
The parameter supports a server resolution for WMS source layers.
Definition qgis.h:6426
@ WmsScale
The parameter supports a reference scale for WMS source layers.
Definition qgis.h:6425
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3742
@ Standard
Standard (single-run) algorithm mode.
Definition qgis.h:3743
@ CompatibleWithVirtualRaster
The processing provider's algorithms can work with QGIS virtualraster data provider.
Definition qgis.h:3631
@ Static
Static property.
Definition qgis.h:703
@ PointCloudLayer
QgsPointCloudLayer.
Definition qgis.h:224
@ MeshLayer
QgsMeshLayer.
Definition qgis.h:222
@ VectorTileLayer
QgsVectorTileLayer.
Definition qgis.h:223
@ AnnotationLayer
QgsAnnotationLayer.
Definition qgis.h:225
@ All
All layers.
Definition qgis.h:227
@ TiledSceneLayer
QgsTiledSceneLayer.
Definition qgis.h:226
@ Point
Points.
Definition qgis.h:366
@ Line
Lines.
Definition qgis.h:367
@ Polygon
Polygons.
Definition qgis.h:368
@ Unknown
Unknown types.
Definition qgis.h:369
@ Null
No geometry.
Definition qgis.h:370
@ Vector
Vector layer.
Definition qgis.h:194
@ AbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Definition qgis.h:2299
QFlags< ProcessingFeatureSourceDefinitionFlag > ProcessingFeatureSourceDefinitionFlags
Flags which control behavior for a Processing feature source.
Definition qgis.h:3770
@ CreateIndividualOutputPerInputFeature
If set, every feature processed from this source will be placed into its own individually created out...
Definition qgis.h:3759
@ OverrideDefaultGeometryCheck
If set, the default geometry check method (as dictated by QgsProcessingContext) will be overridden fo...
Definition qgis.h:3758
@ Optional
Parameter is optional.
Definition qgis.h:3836
QFlags< LayerFilter > LayerFilters
Definition qgis.h:230
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Embeds the browser view to select an existing data source.
void itemTriggered(const QgsMimeDataUtils::Uri &uri)
Emitted when an item is triggered, e.g.
QgsMimeDataUtils::Uri uri() const
Returns the (possibly invalid) uri of the selected data source.
Abstract interface for classes which generate a file filter string.
A combobox which displays a dynamic list of layers from a QGIS project.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
Definition qgsmaplayer.h:83
QString id
Definition qgsmaplayer.h:86
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Base class for any widget that can be shown as an inline panel.
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
void widgetChanged()
Emitted when the widget state changes.
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
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.
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.
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.
QList< int > dataTypes() const
Returns the geometry types for sources acceptable by the parameter.
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 raster layer parameter for processing algorithms.
Qgis::RasterProcessingParameterCapabilities parameterCapabilities() const
Returns flags containing the supported capabilities of the raster layer parameter.
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.
Encapsulates settings relating to a raster layer input to a processing algorithm.
double referenceScale
If set to a value > 0, sets a scale at which a raster (e.g., a WMS) should be requested or rendered.
int dpi
Indicates the resolution of the raster source (e.g., a WMS server).
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.
Stores settings for use within QGIS.
Definition qgssettings.h:68
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 dataset.
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...
static bool isWmsLayer(QgsMapLayer *layer)
Returns whether a map layer is an OGC WMS layer or not.
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.