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