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