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