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