QGIS API Documentation 3.41.0-Master (af5edcb665c)
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 && ( !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 if ( !mBlockChangedSignal )
209 emit valueChanged();
210 } );
211
212 setLayout( vl );
213
214 setAcceptDrops( true );
215
216 onLayerChanged( mCombo->currentLayer() );
217}
218
219QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() = default;
220
221void QgsProcessingMapLayerComboBox::setLayer( QgsMapLayer *layer )
222{
223 if ( layer || mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
224 mCombo->setLayer( layer );
225}
226
227QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
228{
229 return mCombo->currentLayer();
230}
231
232QString QgsProcessingMapLayerComboBox::currentText()
233{
234 return mCombo->currentText();
235}
236
237void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessingContext &context )
238{
239 if ( !value.isValid() && mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
240 {
241 setLayer( nullptr );
242 return;
243 }
244
245 QVariant val = value;
246 bool found = false;
247 bool selectedOnly = false;
248 bool iterate = false;
249 if ( val.userType() == qMetaTypeId<QgsProcessingFeatureSourceDefinition>() )
250 {
251 QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
252 val = fromVar.source;
253 selectedOnly = fromVar.selectedFeaturesOnly;
255 mFeatureLimit = fromVar.featureLimit;
256 mFilterExpression = fromVar.filterExpression;
257 mIsOverridingDefaultGeometryCheck = fromVar.flags & Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck;
258 mGeometryCheck = fromVar.geometryCheck;
259 }
260 else
261 {
262 mFeatureLimit = -1;
263 mFilterExpression.clear();
264 mIsOverridingDefaultGeometryCheck = false;
266 }
267
268 if ( val.userType() == qMetaTypeId<QgsProperty>() )
269 {
271 {
272 val = val.value<QgsProperty>().staticValue();
273 }
274 else
275 {
276 val = val.value<QgsProperty>().valueAsString( context.expressionContext(), mParameter->defaultValueForGui().toString() );
277 }
278 }
279
280 QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( val.value<QObject *>() );
281 if ( !layer && val.userType() == QMetaType::Type::QString )
282 {
283 layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false );
284 }
285
286 if ( layer )
287 {
288 mBlockChangedSignal++;
289 QgsMapLayer *prevLayer = currentLayer();
290 setLayer( layer );
291 found = static_cast<bool>( currentLayer() );
292 bool changed = found && ( currentLayer() != prevLayer );
293 if ( found && mUseSelectionCheckBox )
294 {
295 const bool hasSelection = qobject_cast<QgsVectorLayer *>( layer ) && qobject_cast<QgsVectorLayer *>( layer )->selectedFeatureCount() > 0;
296 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
297 if ( hasSelection )
298 {
299 mUseSelectionCheckBox->setEnabled( true );
300 mUseSelectionCheckBox->setChecked( selectedOnly );
301 }
302 else
303 {
304 mUseSelectionCheckBox->setChecked( false );
305 mUseSelectionCheckBox->setEnabled( false );
306 }
307
308 if ( mIterateButton )
309 {
310 mIterateButton->setChecked( iterate );
311 }
312 }
313 mBlockChangedSignal--;
314 if ( changed )
315 emit valueChanged(); // and ensure we only ever raise one
316 }
317
318 if ( !found )
319 {
320 const QString string = val.toString();
321 if ( mIterateButton )
322 mIterateButton->setChecked( iterate );
323
324 if ( !string.isEmpty() )
325 {
326 mBlockChangedSignal++;
327 if ( mCombo->findText( string ) < 0 )
328 {
329 QStringList additional = mCombo->additionalItems();
330 additional.append( string );
331 mCombo->setAdditionalItems( additional );
332 }
333 mCombo->setCurrentIndex( mCombo->findText( string ) ); // this may or may not throw a signal, so let's block it..
334 if ( mUseSelectionCheckBox )
335 {
336 mUseSelectionCheckBox->setChecked( false );
337 mUseSelectionCheckBox->setEnabled( false );
338 }
339 mBlockChangedSignal--;
340 if ( !mBlockChangedSignal )
341 emit valueChanged(); // and ensure we only ever raise one
342 }
343 else if ( mParameter->flags() & Qgis::ProcessingParameterFlag::Optional )
344 {
345 mCombo->setLayer( nullptr );
346 if ( mUseSelectionCheckBox )
347 {
348 mUseSelectionCheckBox->setChecked( false );
349 mUseSelectionCheckBox->setEnabled( false );
350 }
351 }
352 }
353}
354
355QVariant QgsProcessingMapLayerComboBox::value() const
356{
357 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
358 return mCombo->currentText();
359
360 const bool iterate = mIterateButton && mIterateButton->isChecked();
361 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
362 if ( QgsMapLayer *layer = mCombo->currentLayer() )
363 {
364 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
365 return QgsProcessingFeatureSourceDefinition( layer->id(), selectedOnly, mFeatureLimit, ( iterate ? Qgis::ProcessingFeatureSourceDefinitionFlag::CreateIndividualOutputPerInputFeature : Qgis::ProcessingFeatureSourceDefinitionFlags() ) | ( mIsOverridingDefaultGeometryCheck ? Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck : Qgis::ProcessingFeatureSourceDefinitionFlags() ), mGeometryCheck, mFilterExpression );
366 else
367 return layer->id();
368 }
369 else
370 {
371 if ( !mCombo->currentText().isEmpty() )
372 {
373 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck || !mFilterExpression.isEmpty() )
374 return QgsProcessingFeatureSourceDefinition( mCombo->currentText(), selectedOnly, mFeatureLimit, ( iterate ? Qgis::ProcessingFeatureSourceDefinitionFlag::CreateIndividualOutputPerInputFeature : Qgis::ProcessingFeatureSourceDefinitionFlags() ) | ( mIsOverridingDefaultGeometryCheck ? Qgis::ProcessingFeatureSourceDefinitionFlag::OverrideDefaultGeometryCheck : Qgis::ProcessingFeatureSourceDefinitionFlags() ), mGeometryCheck, mFilterExpression );
375 else
376 return mCombo->currentText();
377 }
378 }
379 return QVariant();
380}
381
382void QgsProcessingMapLayerComboBox::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
383{
384 mBrowserModel = context.browserModel();
385 mCombo->setProject( context.project() );
386}
387
388void QgsProcessingMapLayerComboBox::setEditable( bool editable )
389{
390 mCombo->setEditable( editable );
391}
392
393bool QgsProcessingMapLayerComboBox::isEditable() const
394{
395 return mCombo->isEditable();
396}
397
398QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData( const QMimeData *data, bool &incompatibleLayerSelected ) const
399{
400 incompatibleLayerSelected = false;
402 for ( const QgsMimeDataUtils::Uri &u : uriList )
403 {
404 // is this uri from the current project?
405 if ( QgsMapLayer *layer = u.mapLayer() )
406 {
407 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
408 return layer;
409 else
410 {
411 incompatibleLayerSelected = true;
412 return nullptr;
413 }
414 }
415 }
416 return nullptr;
417}
418
419
420QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData( const QMimeData *data ) const
421{
423 for ( const QgsMimeDataUtils::Uri &u : uriList )
424 {
425 if ( ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName()
426 || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
427 && u.layerType == QLatin1String( "vector" ) )
428 {
429 QList<int> dataTypes = mParameter->type() == QgsProcessingParameterFeatureSource::typeName() ? static_cast<QgsProcessingParameterFeatureSource *>( mParameter.get() )->dataTypes()
430 : ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() ? static_cast<QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes()
431 : QList<int>() );
432 bool acceptable = false;
433 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
434 {
436 acceptable = true;
437 break;
438
440 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 ) ) )
441 acceptable = true;
442 break;
443
445 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 ) ) )
446 acceptable = true;
447 break;
448
450 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 ) ) )
451 acceptable = true;
452 break;
453
455 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Vector ) ) )
456 acceptable = true;
457 break;
458 }
459 if ( acceptable )
460 return u.providerKey != QLatin1String( "ogr" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri;
461 }
462 else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName()
463 && u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) )
464 return u.uri;
465 else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName()
466 && u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) )
467 return u.uri;
468 else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
469 {
470 QList<int> dataTypes = static_cast<QgsProcessingParameterMapLayer *>( mParameter.get() )->dataTypes();
471 if ( dataTypes.isEmpty() || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::MapLayer ) ) )
472 {
473 return u.uri;
474 }
475
476 if ( u.layerType == QLatin1String( "vector" ) && u.providerKey == QLatin1String( "ogr" ) )
477 {
478 switch ( QgsWkbTypes::geometryType( u.wkbType ) )
479 {
481 return u.uri;
482
484 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPoint ) ) )
485 return u.uri;
486 break;
487
489 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorLine ) ) )
490 return u.uri;
491 break;
492
494 if ( dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorAnyGeometry ) ) || dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::VectorPolygon ) ) )
495 return u.uri;
496 break;
497
499 return u.uri;
500 }
501 }
502 else if ( u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" )
503 && dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Raster ) ) )
504 return u.uri;
505 else if ( u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" )
506 && dataTypes.contains( static_cast<int>( Qgis::ProcessingSourceType::Mesh ) ) )
507 return u.uri;
508 }
509 }
510 if ( !uriList.isEmpty() )
511 return QString();
512
513 // second chance -- files dragged from file explorer, outside of QGIS
514 QStringList rawPaths;
515 if ( data->hasUrls() )
516 {
517 const QList<QUrl> urls = data->urls();
518 rawPaths.reserve( urls.count() );
519 for ( const QUrl &url : urls )
520 {
521 const QString local = url.toLocalFile();
522 if ( !rawPaths.contains( local ) )
523 rawPaths.append( local );
524 }
525 }
526 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
527 rawPaths.append( data->text() );
528
529 for ( const QString &path : std::as_const( rawPaths ) )
530 {
531 QFileInfo file( path );
532 if ( file.isFile() )
533 {
534 // TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
535 return path;
536 }
537 }
538
539 return QString();
540}
541
542void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
543{
544 if ( !( event->possibleActions() & Qt::CopyAction ) )
545 return;
546
547 bool incompatibleLayerSelected = false;
548 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
549 const QString uri = compatibleUriFromMimeData( event->mimeData() );
550 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
551 {
552 // dragged an acceptable layer, phew
553 event->setDropAction( Qt::CopyAction );
554 event->accept();
555 mDragActive = true;
556 mCombo->mHighlight = true;
557 update();
558 }
559}
560
561void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
562{
563 QWidget::dragLeaveEvent( event );
564 if ( mDragActive )
565 {
566 event->accept();
567 mDragActive = false;
568 mCombo->mHighlight = false;
569 update();
570 }
571}
572
573void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
574{
575 if ( !( event->possibleActions() & Qt::CopyAction ) )
576 return;
577
578 bool incompatibleLayerSelected = false;
579 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
580 const QString uri = compatibleUriFromMimeData( event->mimeData() );
581 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
582 {
583 // dropped an acceptable layer, phew
584 setFocus( Qt::MouseFocusReason );
585 event->setDropAction( Qt::CopyAction );
586 event->accept();
587 QgsProcessingContext context;
588 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
589 }
590 mDragActive = false;
591 mCombo->mHighlight = false;
592 update();
593}
594
595void QgsProcessingMapLayerComboBox::onLayerChanged( QgsMapLayer *layer )
596{
597 if ( mUseSelectionCheckBox && mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
598 {
599 if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer ) )
600 {
601 if ( QgsVectorLayer *prevLayer = qobject_cast<QgsVectorLayer *>( mPrevLayer ) )
602 {
603 disconnect( prevLayer, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
604 }
605 if ( vl->selectedFeatureCount() == 0 )
606 mUseSelectionCheckBox->setChecked( false );
607 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
608 connect( vl, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
609 }
610 }
611
612 mPrevLayer = layer;
613 if ( !mBlockChangedSignal )
614 emit valueChanged();
615}
616
617void QgsProcessingMapLayerComboBox::selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &, bool )
618{
619 if ( selected.isEmpty() )
620 mUseSelectionCheckBox->setChecked( false );
621 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
622}
623
624void QgsProcessingMapLayerComboBox::showSourceOptions()
625{
626 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
627 {
628 QgsProcessingFeatureSourceOptionsWidget *widget = new QgsProcessingFeatureSourceOptionsWidget();
629 widget->setPanelTitle( tr( "%1 Options" ).arg( mParameter->description() ) );
630 widget->setLayer( qobject_cast<QgsVectorLayer *>( mCombo->currentLayer() ) );
631
632 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
633 widget->setFeatureLimit( mFeatureLimit );
634 widget->setFilterExpression( mFilterExpression );
635
636 panel->openPanel( widget );
637
638 connect( widget, &QgsPanelWidget::widgetChanged, this, [=] {
639 bool changed = false;
640 changed = changed | ( widget->featureLimit() != mFeatureLimit );
641 changed = changed | ( widget->filterExpression() != mFilterExpression );
642 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
643 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
644
645 mFeatureLimit = widget->featureLimit();
646 mFilterExpression = widget->filterExpression();
647 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
648 mGeometryCheck = widget->geometryCheckMethod();
649
650 if ( changed )
651 emit valueChanged();
652 } );
653 }
654}
655
656void QgsProcessingMapLayerComboBox::selectFromFile()
657{
658 QgsSettings settings;
659 const QString initialValue = currentText();
660 QString path;
661
662 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
663 path = initialValue;
664 else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() != '.' )
665 path = QFileInfo( initialValue ).path();
666 else if ( settings.contains( QStringLiteral( "/Processing/LastInputPath" ) ) )
667 path = settings.value( QStringLiteral( "/Processing/LastInputPath" ) ).toString();
668
669 QString filter;
670 if ( const QgsFileFilterGenerator *generator = dynamic_cast<const QgsFileFilterGenerator *>( mParameter.get() ) )
671 filter = generator->createFileFilter();
672 else
673 filter = QObject::tr( "All files (*.*)" );
674
675 const QString filename = QFileDialog::getOpenFileName( this, tr( "Select File" ), path, filter );
676 if ( filename.isEmpty() )
677 return;
678
679 settings.setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( filename ).path() );
680 QgsProcessingContext context;
681 setValue( filename, context );
682}
683
684void QgsProcessingMapLayerComboBox::browseForLayer()
685{
686 if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
687 {
689 widget->setPanelTitle( tr( "Browse for \"%1\"" ).arg( mParameter->description() ) );
690
691 panel->openPanel( widget );
692
693 connect( widget, &QgsDataSourceSelectWidget::itemTriggered, this, [=]( const QgsMimeDataUtils::Uri & ) {
694 widget->acceptPanel();
695 } );
696 connect( widget, &QgsPanelWidget::panelAccepted, this, [=]() {
697 QgsProcessingContext context;
698 if ( widget->uri().uri.isEmpty() )
699 setValue( QVariant(), context );
700 else if ( widget->uri().providerKey == QLatin1String( "ogr" ) )
701 setValue( widget->uri().uri, context );
702 else
703 setValue( QgsProcessingUtils::encodeProviderKeyAndUri( widget->uri().providerKey, widget->uri().uri ), context );
704 } );
705 }
706}
707
708
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.