QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
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#include "qgsmaplayercombobox.h"
18#include "qgsmimedatautils.h"
20#include "qgssettings.h"
21#include "qgsvectorlayer.h"
22#include "qgsfeatureid.h"
23#include "qgsapplication.h"
24#include "qgsguiutils.h"
25#include "qgspanelwidget.h"
29#include <QHBoxLayout>
30#include <QVBoxLayout>
31#include <QToolButton>
32#include <QCheckBox>
33#include <QDragEnterEvent>
34#include <QMenu>
35#include <QAction>
36#include <QFileDialog>
37#include <QUrl>
38
40
41QgsProcessingMapLayerComboBox::QgsProcessingMapLayerComboBox( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
42 : QWidget( parent )
43 , mParameter( parameter->clone() )
44{
45 QHBoxLayout *layout = new QHBoxLayout();
46 layout->setContentsMargins( 0, 0, 0, 0 );
47 layout->setSpacing( 6 );
48
49 mCombo = new QgsMapLayerComboBox();
50 layout->addWidget( mCombo );
51 layout->setAlignment( mCombo, Qt::AlignTop );
52
55 {
56 mIterateButton = new QToolButton();
57 mIterateButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconIterate.svg" ) ) );
58 mIterateButton->setToolTip( tr( "Iterate over this layer, creating a separate output for every feature in the layer" ) );
59 mIterateButton->setCheckable( true );
60 mIterateButton->setAutoRaise( true );
61
62 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
63 mIterateButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
64 mIterateButton->setIconSize( QSize( iconSize, iconSize ) );
65
66 layout->addWidget( mIterateButton );
67 layout->setAlignment( mIterateButton, Qt::AlignTop );
68 }
69
70 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
71 {
72 mSettingsButton = new QToolButton();
73 mSettingsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionOptions.svg" ) ) );
74 mSettingsButton->setToolTip( tr( "Advanced options" ) );
75
76 // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
77 mSettingsButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
78 mSettingsButton->setIconSize( QSize( iconSize, iconSize ) );
79 mSettingsButton->setAutoRaise( true );
80
81 connect( mSettingsButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::showSourceOptions );
82 layout->addWidget( mSettingsButton );
83 layout->setAlignment( mSettingsButton, Qt::AlignTop );
84 }
85
86 mSelectButton = new QToolButton();
87 mSelectButton->setText( QString( QChar( 0x2026 ) ) );
88 mSelectButton->setToolTip( tr( "Select input" ) );
89 layout->addWidget( mSelectButton );
90 layout->setAlignment( mSelectButton, Qt::AlignTop );
91 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
92 {
93 mFeatureSourceMenu = new QMenu( this );
94 QAction *selectFromFileAction = new QAction( tr( "Select File…" ), mFeatureSourceMenu );
95 connect( selectFromFileAction, &QAction::triggered, this, &QgsProcessingMapLayerComboBox::selectFromFile );
96 mFeatureSourceMenu->addAction( selectFromFileAction );
97 QAction *browseForLayerAction = new QAction( tr( "Browse for Layer…" ), mFeatureSourceMenu );
98 connect( browseForLayerAction, &QAction::triggered, this, &QgsProcessingMapLayerComboBox::browseForLayer );
99 mFeatureSourceMenu->addAction( browseForLayerAction );
100 mSelectButton->setMenu( mFeatureSourceMenu );
101 mSelectButton->setPopupMode( QToolButton::InstantPopup );
102 }
103 else
104 {
105 connect( mSelectButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::selectFromFile );
106 }
107
108 QVBoxLayout *vl = new QVBoxLayout();
109 vl->setContentsMargins( 0, 0, 0, 0 );
110 vl->setSpacing( 6 );
111 vl->addLayout( layout );
112
113 Qgis::LayerFilters filters = Qgis::LayerFilters();
114
115 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() && type == QgsProcessingGui::Standard )
116 {
117 mUseSelectionCheckBox = new QCheckBox( tr( "Selected features only" ) );
118 mUseSelectionCheckBox->setChecked( false );
119 mUseSelectionCheckBox->setEnabled( false );
120 vl->addWidget( mUseSelectionCheckBox );
121 }
122
123 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
124 {
125 QList<int> dataTypes;
126 if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
127 dataTypes = static_cast< QgsProcessingParameterFeatureSource *>( mParameter.get() )->dataTypes();
128 else if ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
129 dataTypes = static_cast< QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes();
130
131 if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.isEmpty() )
133 if ( dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
135 if ( dataTypes.contains( QgsProcessing::TypeVectorLine ) )
137 if ( dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
139 if ( !filters )
141 }
142 else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName() )
143 {
145 }
146 else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName() )
147 {
149 }
150 else if ( mParameter->type() == QgsProcessingParameterPointCloudLayer::typeName() )
151 {
153 }
154 else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
155 {
156 QList<int> dataTypes;
157 dataTypes = static_cast< QgsProcessingParameterMapLayer *>( mParameter.get() )->dataTypes();
158
159 if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) )
161 if ( dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
163 if ( dataTypes.contains( QgsProcessing::TypeVectorLine ) )
165 if ( dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
167 if ( dataTypes.contains( QgsProcessing::TypeRaster ) )
169 if ( dataTypes.contains( QgsProcessing::TypeMesh ) )
171 if ( dataTypes.contains( QgsProcessing::TypePointCloud ) )
173 if ( !filters )
174 filters = Qgis::LayerFilter::All;
175 }
176
177 QgsSettings settings;
178 if ( settings.value( QStringLiteral( "Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
179 mCombo->setShowCrs( true );
180
181 if ( filters )
182 mCombo->setFilters( filters );
183 mCombo->setExcludedProviders( QStringList() << QStringLiteral( "grass" ) ); // not sure if this is still required...
184
185 if ( mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
186 {
187 mCombo->setAllowEmptyLayer( true );
188 mCombo->setLayer( nullptr );
189 }
190
191 connect( mCombo, &QgsMapLayerComboBox::layerChanged, this, &QgsProcessingMapLayerComboBox::onLayerChanged );
192 if ( mUseSelectionCheckBox )
193 connect( mUseSelectionCheckBox, &QCheckBox::toggled, this, [ = ]
194 {
195 if ( !mBlockChangedSignal )
196 emit valueChanged();
197 } );
198
199 setLayout( vl );
200
201 setAcceptDrops( true );
202
203 onLayerChanged( mCombo->currentLayer() );
204}
205
206QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() = default;
207
208void QgsProcessingMapLayerComboBox::setLayer( QgsMapLayer *layer )
209{
210 if ( layer || mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
211 mCombo->setLayer( layer );
212}
213
214QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
215{
216 return mCombo->currentLayer();
217}
218
219QString QgsProcessingMapLayerComboBox::currentText()
220{
221 return mCombo->currentText();
222}
223
224void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessingContext &context )
225{
226 if ( !value.isValid() && mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
227 {
228 setLayer( nullptr );
229 return;
230 }
231
232 QVariant val = value;
233 bool found = false;
234 bool selectedOnly = false;
235 bool iterate = false;
236 if ( val.userType() == QMetaType::type( "QgsProcessingFeatureSourceDefinition" ) )
237 {
238 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
239 val = fromVar.source;
240 selectedOnly = fromVar.selectedFeaturesOnly;
242 mFeatureLimit = fromVar.featureLimit;
243 mFilterExpression = fromVar.filterExpression;
245 mGeometryCheck = fromVar.geometryCheck;
246 }
247 else
248 {
249 mFeatureLimit = -1;
250 mFilterExpression.clear();
251 mIsOverridingDefaultGeometryCheck = false;
253 }
254
255 if ( val.userType() == QMetaType::type( "QgsProperty" ) )
256 {
257 if ( val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
258 {
259 val = val.value< QgsProperty >().staticValue();
260 }
261 else
262 {
263 val = val.value< QgsProperty >().valueAsString( context.expressionContext(), mParameter->defaultValueForGui().toString() );
264 }
265 }
266
267 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
268 if ( !layer && val.type() == QVariant::String )
269 {
270 layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false );
271 }
272
273 if ( layer )
274 {
275 mBlockChangedSignal++;
276 QgsMapLayer *prevLayer = currentLayer();
277 setLayer( layer );
278 found = static_cast< bool >( currentLayer() );
279 bool changed = found && ( currentLayer() != prevLayer );
280 if ( found && mUseSelectionCheckBox )
281 {
282 const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
283 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
284 if ( hasSelection )
285 {
286 mUseSelectionCheckBox->setEnabled( true );
287 mUseSelectionCheckBox->setChecked( selectedOnly );
288 }
289 else
290 {
291 mUseSelectionCheckBox->setChecked( false );
292 mUseSelectionCheckBox->setEnabled( false );
293 }
294
295 if ( mIterateButton )
296 {
297 mIterateButton->setChecked( iterate );
298 }
299 }
300 mBlockChangedSignal--;
301 if ( changed )
302 emit valueChanged(); // and ensure we only ever raise one
303 }
304
305 if ( !found )
306 {
307 const QString string = val.toString();
308 if ( mIterateButton )
309 mIterateButton->setChecked( iterate );
310
311 if ( !string.isEmpty() )
312 {
313 mBlockChangedSignal++;
314 if ( mCombo->findText( string ) < 0 )
315 {
316 QStringList additional = mCombo->additionalItems();
317 additional.append( string );
318 mCombo->setAdditionalItems( additional );
319 }
320 mCombo->setCurrentIndex( mCombo->findText( string ) ); // this may or may not throw a signal, so let's block it..
321 if ( mUseSelectionCheckBox )
322 {
323 mUseSelectionCheckBox->setChecked( false );
324 mUseSelectionCheckBox->setEnabled( false );
325 }
326 mBlockChangedSignal--;
327 if ( !mBlockChangedSignal )
328 emit valueChanged(); // and ensure we only ever raise one
329 }
330 else if ( mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
331 {
332 mCombo->setLayer( nullptr );
333 if ( mUseSelectionCheckBox )
334 {
335 mUseSelectionCheckBox->setChecked( false );
336 mUseSelectionCheckBox->setEnabled( false );
337 }
338 }
339 }
340}
341
342QVariant QgsProcessingMapLayerComboBox::value() const
343{
344 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
345 return mCombo->currentText();
346
347 const bool iterate = mIterateButton && mIterateButton->isChecked();
348 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
349 if ( QgsMapLayer *layer = mCombo->currentLayer() )
350 {
351 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
352 return QgsProcessingFeatureSourceDefinition( layer->id(), selectedOnly, mFeatureLimit,
354 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
355 mGeometryCheck, mFilterExpression );
356 else
357 return layer->id();
358 }
359 else
360 {
361 if ( !mCombo->currentText().isEmpty() )
362 {
363 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
364 return QgsProcessingFeatureSourceDefinition( mCombo->currentText(), selectedOnly, mFeatureLimit,
366 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
367 mGeometryCheck, mFilterExpression );
368 else
369 return mCombo->currentText();
370 }
371 }
372 return QVariant();
373}
374
375void QgsProcessingMapLayerComboBox::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
376{
377 mBrowserModel = context.browserModel();
378 mCombo->setProject( context.project() );
379}
380
381void QgsProcessingMapLayerComboBox::setEditable( bool editable )
382{
383 mCombo->setEditable( editable );
384}
385
386bool QgsProcessingMapLayerComboBox::isEditable() const
387{
388 return mCombo->isEditable();
389}
390
391QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData( const QMimeData *data, bool &incompatibleLayerSelected ) const
392{
393 incompatibleLayerSelected = false;
395 for ( const QgsMimeDataUtils::Uri &u : uriList )
396 {
397 // is this uri from the current project?
398 if ( QgsMapLayer *layer = u.mapLayer() )
399 {
400 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
401 return layer;
402 else
403 {
404 incompatibleLayerSelected = true;
405 return nullptr;
406 }
407 }
408 }
409 return nullptr;
410}
411
412
413QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData( const QMimeData *data ) const
414{
416 for ( const QgsMimeDataUtils::Uri &u : uriList )
417 {
418 if ( ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName()
419 || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
420 && u.layerType == QLatin1String( "vector" ) )
421 {
422 QList< int > dataTypes = mParameter->type() == QgsProcessingParameterFeatureSource::typeName() ? static_cast< QgsProcessingParameterFeatureSource * >( mParameter.get() )->dataTypes()
423 : ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() ? static_cast<QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes()
424 : QList< int >() );
425 bool acceptable = false;
426 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
427 {
429 acceptable = true;
430 break;
431
433 if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
434 acceptable = true;
435 break;
436
438 if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorLine ) )
439 acceptable = true;
440 break;
441
443 if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
444 acceptable = true;
445 break;
446
448 if ( dataTypes.contains( QgsProcessing::TypeVector ) )
449 acceptable = true;
450 break;
451 }
452 if ( acceptable )
453 return u.providerKey != QLatin1String( "ogr" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri;
454 }
455 else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName()
456 && u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) )
457 return u.uri;
458 else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName()
459 && u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) )
460 return u.uri;
461 else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
462 {
463 QList< int > dataTypes = static_cast< QgsProcessingParameterMapLayer * >( mParameter.get() )->dataTypes();
464 if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeMapLayer ) )
465 {
466 return u.uri;
467 }
468
469 if ( u.layerType == QLatin1String( "vector" ) && u.providerKey == QLatin1String( "ogr" ) )
470 {
471 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
472 {
474 return u.uri;
475
477 if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
478 return u.uri;
479 break;
480
482 if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorLine ) )
483 return u.uri;
484 break;
485
487 if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
488 return u.uri;
489 break;
490
492 return u.uri;
493 }
494 }
495 else if ( u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" )
496 && dataTypes.contains( QgsProcessing::TypeRaster ) )
497 return u.uri;
498 else if ( u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" )
499 && dataTypes.contains( QgsProcessing::TypeMesh ) )
500 return u.uri;
501 }
502 }
503 if ( !uriList.isEmpty() )
504 return QString();
505
506 // second chance -- files dragged from file explorer, outside of QGIS
507 QStringList rawPaths;
508 if ( data->hasUrls() )
509 {
510 const QList< QUrl > urls = data->urls();
511 rawPaths.reserve( urls.count() );
512 for ( const QUrl &url : urls )
513 {
514 const QString local = url.toLocalFile();
515 if ( !rawPaths.contains( local ) )
516 rawPaths.append( local );
517 }
518 }
519 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
520 rawPaths.append( data->text() );
521
522 for ( const QString &path : std::as_const( rawPaths ) )
523 {
524 QFileInfo file( path );
525 if ( file.isFile() )
526 {
527 // TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
528 return path;
529 }
530 }
531
532 return QString();
533}
534
535void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
536{
537 if ( !( event->possibleActions() & Qt::CopyAction ) )
538 return;
539
540 bool incompatibleLayerSelected = false;
541 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
542 const QString uri = compatibleUriFromMimeData( event->mimeData() );
543 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
544 {
545 // dragged an acceptable layer, phew
546 event->setDropAction( Qt::CopyAction );
547 event->accept();
548 mDragActive = true;
549 mCombo->mHighlight = true;
550 update();
551 }
552}
553
554void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
555{
556 QWidget::dragLeaveEvent( event );
557 if ( mDragActive )
558 {
559 event->accept();
560 mDragActive = false;
561 mCombo->mHighlight = false;
562 update();
563 }
564}
565
566void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
567{
568 if ( !( event->possibleActions() & Qt::CopyAction ) )
569 return;
570
571 bool incompatibleLayerSelected = false;
572 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
573 const QString uri = compatibleUriFromMimeData( event->mimeData() );
574 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
575 {
576 // dropped an acceptable layer, phew
577 setFocus( Qt::MouseFocusReason );
578 event->setDropAction( Qt::CopyAction );
579 event->accept();
580 QgsProcessingContext context;
581 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
582 }
583 mDragActive = false;
584 mCombo->mHighlight = false;
585 update();
586}
587
588void QgsProcessingMapLayerComboBox::onLayerChanged( QgsMapLayer *layer )
589{
590 if ( mUseSelectionCheckBox && mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
591 {
592 if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
593 {
594 if ( QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
595 {
596 disconnect( prevLayer, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
597 }
598 if ( vl->selectedFeatureCount() == 0 )
599 mUseSelectionCheckBox->setChecked( false );
600 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
601 connect( vl, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
602 }
603 }
604
605 mPrevLayer = layer;
606 if ( !mBlockChangedSignal )
607 emit valueChanged();
608}
609
610void QgsProcessingMapLayerComboBox::selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &, bool )
611{
612 if ( selected.isEmpty() )
613 mUseSelectionCheckBox->setChecked( false );
614 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
615}
616
617void QgsProcessingMapLayerComboBox::showSourceOptions()
618{
619 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
620 {
621 QgsProcessingFeatureSourceOptionsWidget *widget = new QgsProcessingFeatureSourceOptionsWidget();
622 widget->setPanelTitle( tr( "%1 Options" ).arg( mParameter->description() ) );
623 widget->setLayer( qobject_cast< QgsVectorLayer * >( mCombo->currentLayer() ) );
624
625 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
626 widget->setFeatureLimit( mFeatureLimit );
627 widget->setFilterExpression( mFilterExpression );
628
629 panel->openPanel( widget );
630
631 connect( widget, &QgsPanelWidget::widgetChanged, this, [ = ]
632 {
633 bool changed = false;
634 changed = changed | ( widget->featureLimit() != mFeatureLimit );
635 changed = changed | ( widget->filterExpression() != mFilterExpression );
636 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
637 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
638
639 mFeatureLimit = widget->featureLimit();
640 mFilterExpression = widget->filterExpression();
641 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
642 mGeometryCheck = widget->geometryCheckMethod();
643
644 if ( changed )
645 emit valueChanged();
646 } );
647 }
648}
649
650void QgsProcessingMapLayerComboBox::selectFromFile()
651{
652 QgsSettings settings;
653 const QString initialValue = currentText();
654 QString path;
655
656 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
657 path = initialValue;
658 else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() != '.' )
659 path = QFileInfo( initialValue ).path();
660 else if ( settings.contains( QStringLiteral( "/Processing/LastInputPath" ) ) )
661 path = settings.value( QStringLiteral( "/Processing/LastInputPath" ) ).toString();
662
663 QString filter;
664 if ( const QgsFileFilterGenerator *generator = dynamic_cast< const QgsFileFilterGenerator * >( mParameter.get() ) )
665 filter = generator->createFileFilter();
666 else
667 filter = QObject::tr( "All files (*.*)" );
668
669 const QString filename = QFileDialog::getOpenFileName( this, tr( "Select File" ), path, filter );
670 if ( filename.isEmpty() )
671 return;
672
673 settings.setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( filename ).path() );
674 QgsProcessingContext context;
675 setValue( filename, context );
676}
677
678void QgsProcessingMapLayerComboBox::browseForLayer()
679{
680 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
681 {
683 widget->setPanelTitle( tr( "Browse for \"%1\"" ).arg( mParameter->description() ) );
684
685 panel->openPanel( widget );
686
687 connect( widget, &QgsDataSourceSelectWidget::itemTriggered, this, [ = ]( const QgsMimeDataUtils::Uri & )
688 {
689 widget->acceptPanel();
690 } );
691 connect( widget, &QgsPanelWidget::panelAccepted, this, [ = ]()
692 {
693 QgsProcessingContext context;
694 if ( widget->uri().uri.isEmpty() )
695 setValue( QVariant(), context );
696 else if ( widget->uri().providerKey == QLatin1String( "ogr" ) )
697 setValue( widget->uri().uri, context );
698 else
699 setValue( QgsProcessingUtils::encodeProviderKeyAndUri( widget->uri().providerKey, widget->uri().uri ), context );
700 } );
701 }
702}
703
704
705
@ PointCloudLayer
QgsPointCloudLayer.
@ MeshLayer
QgsMeshLayer.
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
@ Vector
Vector layer.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
The QgsDataSourceSelectWidget class 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.
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Abstract interface for classes which generate a file filter string.
The QgsMapLayerComboBox class is a combo box which displays the list of layers.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
Definition qgsmaplayer.h:74
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
QList< QgsMimeDataUtils::Uri > UriList
static UriList decodeUriList(const QMimeData *data)
Base class for any widget that can be shown as a 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.
Flags flags
Flags which dictate source behavior.
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
QgsFeatureRequest::InvalidGeometryCheck geometryCheck
Geometry check method to apply to this source.
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...
@ FlagCreateIndividualOutputPerInputFeature
If set, every feature processed from this source will be placed into its own individually created out...
@ FlagOverrideDefaultGeometryCheck
If set, the default geometry check method (as dictated by QgsProcessingContext) will be overridden fo...
QString filterExpression
Optional expression filter to use for filtering features which will be read from the source.
WidgetType
Types of dialogs which Processing widgets can be created for.
@ Standard
Standard algorithm dialog.
Base class for the definition of processing parameters.
An input feature source (such as vector layers) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
A map layer parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
A vector layer (with or without geometry) parameter for processing algorithms.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QgsProject * project() const
Returns the project associated with the widget.
QgsBrowserGuiModel * browserModel() const
Returns the browser model associated with the widget.
static QString encodeProviderKeyAndUri(const QString &providerKey, const QString &uri)
Encodes a provider key and layer uri to a single string, for use with decodeProviderKeyAndUri()
static QgsMapLayer * mapLayerFromString(const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers=true, QgsProcessingUtils::LayerHint typeHint=QgsProcessingUtils::LayerHint::UnknownType, QgsProcessing::LayerOptionsFlags flags=QgsProcessing::LayerOptionsFlags())
Interprets a string as a map layer within the supplied context.
@ TypeVectorLine
Vector line layers.
@ TypeMapLayer
Any map layer type (raster, vector, mesh, point cloud, annotation or plugin layer)
@ TypeVectorPolygon
Vector polygon layers.
@ TypePointCloud
Point cloud layers.
@ TypeMesh
Mesh layers.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ TypeRaster
Raster layers.
@ TypeVectorPoint
Vector point layers.
@ TypeVectorAnyGeometry
Any vector layer with geometry.
A store for object properties.
@ StaticProperty
Static property (QgsStaticProperty)
Type propertyType() const
Returns the property type.
This class is a composition of two QSettings instances:
Definition qgssettings.h:63
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Represents a vector layer which manages a vector based data sets.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, bool clearAndSelect)
Emitted when selection was changed.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QSet< QgsFeatureId > QgsFeatureIds
QString uri
Identifier of the data source recognized by its providerKey.
QString providerKey
For "vector" / "raster" type: provider id.