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