QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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 
39 
40 QgsProcessingMapLayerComboBox::QgsProcessingMapLayerComboBox( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
41  : QWidget( parent )
42  , mParameter( parameter->clone() )
43 {
44  QHBoxLayout *layout = new QHBoxLayout();
45  layout->setMargin( 0 );
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() )
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->setMargin( 0 );
110  vl->setContentsMargins( 0, 0, 0, 0 );
111  vl->setSpacing( 6 );
112  vl->addLayout( layout );
113 
114  QgsMapLayerProxyModel::Filters filters = nullptr;
115 
116  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() && type == QgsProcessingGui::Standard )
117  {
118  mUseSelectionCheckBox = new QCheckBox( tr( "Selected features only" ) );
119  mUseSelectionCheckBox->setChecked( false );
120  mUseSelectionCheckBox->setEnabled( false );
121  vl->addWidget( mUseSelectionCheckBox );
122  }
123 
124  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
125  {
126  QList<int> dataTypes;
127  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
128  dataTypes = static_cast< QgsProcessingParameterFeatureSource *>( mParameter.get() )->dataTypes();
129  else if ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
130  dataTypes = static_cast< QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes();
131 
132  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.isEmpty() )
134  if ( dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
136  if ( dataTypes.contains( QgsProcessing::TypeVectorLine ) )
138  if ( dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
140  if ( !filters )
142  }
143  else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName() )
144  {
146  }
147  else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName() )
148  {
150  }
151  else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
152  {
153  QList<int> dataTypes;
154  dataTypes = static_cast< QgsProcessingParameterMapLayer *>( mParameter.get() )->dataTypes();
155 
156  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) )
158  if ( dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
160  if ( dataTypes.contains( QgsProcessing::TypeVectorLine ) )
162  if ( dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
164  if ( dataTypes.contains( QgsProcessing::TypeRaster ) )
166  if ( dataTypes.contains( QgsProcessing::TypeMesh ) )
168  if ( !filters )
169  filters = QgsMapLayerProxyModel::All;
170  }
171 
172  QgsSettings settings;
173  if ( settings.value( QStringLiteral( "Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
174  mCombo->setShowCrs( true );
175 
176  if ( filters )
177  mCombo->setFilters( filters );
178  mCombo->setExcludedProviders( QStringList() << QStringLiteral( "grass" ) ); // not sure if this is still required...
179 
180  if ( mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
181  {
182  mCombo->setAllowEmptyLayer( true );
183  mCombo->setLayer( nullptr );
184  }
185 
186  connect( mCombo, &QgsMapLayerComboBox::layerChanged, this, &QgsProcessingMapLayerComboBox::onLayerChanged );
187  if ( mUseSelectionCheckBox )
188  connect( mUseSelectionCheckBox, &QCheckBox::toggled, this, [ = ]
189  {
190  if ( !mBlockChangedSignal )
191  emit valueChanged();
192  } );
193 
194  setLayout( vl );
195 
196  setAcceptDrops( true );
197 
198  onLayerChanged( mCombo->currentLayer() );
199 }
200 
201 QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() = default;
202 
203 void QgsProcessingMapLayerComboBox::setLayer( QgsMapLayer *layer )
204 {
205  if ( layer || mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
206  mCombo->setLayer( layer );
207 }
208 
209 QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
210 {
211  return mCombo->currentLayer();
212 }
213 
214 QString QgsProcessingMapLayerComboBox::currentText()
215 {
216  return mCombo->currentText();
217 }
218 
219 void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessingContext &context )
220 {
221  if ( !value.isValid() && mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
222  {
223  setLayer( nullptr );
224  return;
225  }
226 
227  QVariant val = value;
228  bool found = false;
229  bool selectedOnly = false;
230  bool iterate = false;
231  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
232  {
233  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
234  val = fromVar.source;
235  selectedOnly = fromVar.selectedFeaturesOnly;
236  iterate = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature;
237  mFeatureLimit = fromVar.featureLimit;
238  mIsOverridingDefaultGeometryCheck = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
239  mGeometryCheck = fromVar.geometryCheck;
240  }
241  else
242  {
243  mFeatureLimit = -1;
244  mIsOverridingDefaultGeometryCheck = false;
246  }
247 
248  if ( val.canConvert<QgsProperty>() )
249  {
250  if ( val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
251  {
252  val = val.value< QgsProperty >().staticValue();
253  }
254  else
255  {
256  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), mParameter->defaultValue().toString() );
257  }
258  }
259 
260  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
261  if ( !layer && val.type() == QVariant::String )
262  {
263  layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false );
264  }
265 
266  if ( layer )
267  {
268  mBlockChangedSignal++;
269  QgsMapLayer *prevLayer = currentLayer();
270  setLayer( layer );
271  found = static_cast< bool >( currentLayer() );
272  bool changed = found && ( currentLayer() != prevLayer );
273  if ( found && mUseSelectionCheckBox )
274  {
275  const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
276  changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
277  if ( hasSelection )
278  {
279  mUseSelectionCheckBox->setEnabled( true );
280  mUseSelectionCheckBox->setChecked( selectedOnly );
281  }
282  else
283  {
284  mUseSelectionCheckBox->setChecked( false );
285  mUseSelectionCheckBox->setEnabled( false );
286  }
287 
288  if ( mIterateButton )
289  {
290  mIterateButton->setChecked( iterate );
291  }
292  }
293  mBlockChangedSignal--;
294  if ( changed )
295  emit valueChanged(); // and ensure we only ever raise one
296  }
297 
298  if ( !found )
299  {
300  const QString string = val.toString();
301  if ( mIterateButton )
302  mIterateButton->setChecked( iterate );
303 
304  if ( !string.isEmpty() )
305  {
306  mBlockChangedSignal++;
307  if ( mCombo->findText( string ) < 0 )
308  {
309  QStringList additional = mCombo->additionalItems();
310  additional.append( string );
311  mCombo->setAdditionalItems( additional );
312  }
313  mCombo->setCurrentIndex( mCombo->findText( string ) ); // this may or may not throw a signal, so let's block it..
314  if ( mUseSelectionCheckBox )
315  {
316  mUseSelectionCheckBox->setChecked( false );
317  mUseSelectionCheckBox->setEnabled( false );
318  }
319  mBlockChangedSignal--;
320  if ( !mBlockChangedSignal )
321  emit valueChanged(); // and ensure we only ever raise one
322  }
323  else if ( mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
324  {
325  mCombo->setLayer( nullptr );
326  if ( mUseSelectionCheckBox )
327  {
328  mUseSelectionCheckBox->setChecked( false );
329  mUseSelectionCheckBox->setEnabled( false );
330  }
331  }
332  }
333 }
334 
335 QVariant QgsProcessingMapLayerComboBox::value() const
336 {
337  if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
338  return mCombo->currentText();
339 
340  const bool iterate = mIterateButton && mIterateButton->isChecked();
341  const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
342  if ( QgsMapLayer *layer = mCombo->currentLayer() )
343  {
344  if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
345  return QgsProcessingFeatureSourceDefinition( layer->id(), selectedOnly, mFeatureLimit,
346  ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
347  | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
348  mGeometryCheck );
349  else
350  return layer->id();
351  }
352  else
353  {
354  if ( !mCombo->currentText().isEmpty() )
355  {
356  if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
357  return QgsProcessingFeatureSourceDefinition( mCombo->currentText(), selectedOnly, mFeatureLimit,
358  ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
359  | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
360  mGeometryCheck );
361  else
362  return mCombo->currentText();
363  }
364  }
365  return QVariant();
366 }
367 
368 void QgsProcessingMapLayerComboBox::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
369 {
370  mBrowserModel = context.browserModel();
371 }
372 
373 void QgsProcessingMapLayerComboBox::setEditable( bool editable )
374 {
375  mCombo->setEditable( editable );
376 }
377 
378 bool QgsProcessingMapLayerComboBox::isEditable() const
379 {
380  return mCombo->isEditable();
381 }
382 
383 QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData( const QMimeData *data, bool &incompatibleLayerSelected ) const
384 {
385  incompatibleLayerSelected = false;
387  for ( const QgsMimeDataUtils::Uri &u : uriList )
388  {
389  // is this uri from the current project?
390  if ( QgsMapLayer *layer = u.mapLayer() )
391  {
392  if ( mCombo->mProxyModel->acceptsLayer( layer ) )
393  return layer;
394  else
395  {
396  incompatibleLayerSelected = true;
397  return nullptr;
398  }
399  }
400  }
401  return nullptr;
402 }
403 
404 
405 QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData( const QMimeData *data ) const
406 {
408  for ( const QgsMimeDataUtils::Uri &u : uriList )
409  {
410  if ( ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName()
411  || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
412  && u.layerType == QLatin1String( "vector" ) )
413  {
414  QList< int > dataTypes = mParameter->type() == QgsProcessingParameterFeatureSource::typeName() ? static_cast< QgsProcessingParameterFeatureSource * >( mParameter.get() )->dataTypes()
415  : ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() ? static_cast<QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes()
416  : QList< int >() );
417  bool acceptable = false;
418  switch ( QgsWkbTypes::geometryType( u.wkbType ) )
419  {
421  acceptable = true;
422  break;
423 
425  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
426  acceptable = true;
427  break;
428 
430  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorLine ) )
431  acceptable = true;
432  break;
433 
435  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
436  acceptable = true;
437  break;
438 
440  if ( dataTypes.contains( QgsProcessing::TypeVector ) )
441  acceptable = true;
442  break;
443  }
444  if ( acceptable )
445  return u.providerKey != QLatin1String( "ogr" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri;
446  }
447  else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName()
448  && u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) )
449  return u.uri;
450  else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName()
451  && u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) )
452  return u.uri;
453  else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
454  {
455  QList< int > dataTypes = static_cast< QgsProcessingParameterMapLayer * >( mParameter.get() )->dataTypes();
456  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeMapLayer ) )
457  {
458  return u.uri;
459  }
460 
461  if ( u.layerType == QLatin1String( "vector" ) && u.providerKey == QLatin1String( "ogr" ) )
462  {
463  switch ( QgsWkbTypes::geometryType( u.wkbType ) )
464  {
466  return u.uri;
467 
469  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
470  return u.uri;
471  break;
472 
474  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorLine ) )
475  return u.uri;
476  break;
477 
479  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
480  return u.uri;
481  break;
482 
484  return u.uri;
485  }
486  }
487  else if ( u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" )
488  && dataTypes.contains( QgsProcessing::TypeRaster ) )
489  return u.uri;
490  else if ( u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" )
491  && dataTypes.contains( QgsProcessing::TypeMesh ) )
492  return u.uri;
493  }
494  }
495  if ( !uriList.isEmpty() )
496  return QString();
497 
498  // second chance -- files dragged from file explorer, outside of QGIS
499  QStringList rawPaths;
500  if ( data->hasUrls() )
501  {
502  const QList< QUrl > urls = data->urls();
503  rawPaths.reserve( urls.count() );
504  for ( const QUrl &url : urls )
505  {
506  const QString local = url.toLocalFile();
507  if ( !rawPaths.contains( local ) )
508  rawPaths.append( local );
509  }
510  }
511  if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
512  rawPaths.append( data->text() );
513 
514  for ( const QString &path : qgis::as_const( rawPaths ) )
515  {
516  QFileInfo file( path );
517  if ( file.isFile() )
518  {
519  // TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
520  return path;
521  }
522  }
523 
524  return QString();
525 }
526 
527 void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
528 {
529  if ( !( event->possibleActions() & Qt::CopyAction ) )
530  return;
531 
532  bool incompatibleLayerSelected = false;
533  QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
534  const QString uri = compatibleUriFromMimeData( event->mimeData() );
535  if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
536  {
537  // dragged an acceptable layer, phew
538  event->setDropAction( Qt::CopyAction );
539  event->accept();
540  mDragActive = true;
541  mCombo->mHighlight = true;
542  update();
543  }
544 }
545 
546 void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
547 {
548  QWidget::dragLeaveEvent( event );
549  if ( mDragActive )
550  {
551  event->accept();
552  mDragActive = false;
553  mCombo->mHighlight = false;
554  update();
555  }
556 }
557 
558 void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
559 {
560  if ( !( event->possibleActions() & Qt::CopyAction ) )
561  return;
562 
563  bool incompatibleLayerSelected = false;
564  QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
565  const QString uri = compatibleUriFromMimeData( event->mimeData() );
566  if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
567  {
568  // dropped an acceptable layer, phew
569  setFocus( Qt::MouseFocusReason );
570  event->setDropAction( Qt::CopyAction );
571  event->accept();
572  QgsProcessingContext context;
573  setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
574  }
575  mDragActive = false;
576  mCombo->mHighlight = false;
577  update();
578 }
579 
580 void QgsProcessingMapLayerComboBox::onLayerChanged( QgsMapLayer *layer )
581 {
582  if ( mUseSelectionCheckBox && mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
583  {
584  if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
585  {
586  if ( QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
587  {
588  disconnect( prevLayer, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
589  }
590  if ( vl->selectedFeatureCount() == 0 )
591  mUseSelectionCheckBox->setChecked( false );
592  mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
593  connect( vl, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
594  }
595  }
596 
597  mPrevLayer = layer;
598  if ( !mBlockChangedSignal )
599  emit valueChanged();
600 }
601 
602 void QgsProcessingMapLayerComboBox::selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &, bool )
603 {
604  if ( selected.isEmpty() )
605  mUseSelectionCheckBox->setChecked( false );
606  mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
607 }
608 
609 void QgsProcessingMapLayerComboBox::showSourceOptions()
610 {
611  if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
612  {
613  QgsProcessingFeatureSourceOptionsWidget *widget = new QgsProcessingFeatureSourceOptionsWidget();
614  widget->setPanelTitle( tr( "%1 Options" ).arg( mParameter->description() ) );
615 
616  widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
617  widget->setFeatureLimit( mFeatureLimit );
618 
619  panel->openPanel( widget );
620 
621  connect( widget, &QgsPanelWidget::widgetChanged, this, [ = ]
622  {
623  bool changed = false;
624  changed = changed | ( widget->featureLimit() != mFeatureLimit );
625  changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
626  changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
627 
628  mFeatureLimit = widget->featureLimit();
629  mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
630  mGeometryCheck = widget->geometryCheckMethod();
631 
632  if ( changed )
633  emit valueChanged();
634  } );
635  }
636 }
637 
638 void QgsProcessingMapLayerComboBox::selectFromFile()
639 {
640  QgsSettings settings;
641  const QString initialValue = currentText();
642  QString path;
643 
644  if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
645  path = initialValue;
646  else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() != '.' )
647  path = QFileInfo( initialValue ).path();
648  else if ( settings.contains( QStringLiteral( "/Processing/LastInputPath" ) ) )
649  path = settings.value( QStringLiteral( "/Processing/LastInputPath" ) ).toString();
650 
651  QString filter;
652  if ( const QgsFileFilterGenerator *generator = dynamic_cast< const QgsFileFilterGenerator * >( mParameter.get() ) )
653  filter = generator->createFileFilter();
654  else
655  filter = QObject::tr( "All files (*.*)" );
656 
657  const QString filename = QFileDialog::getOpenFileName( this, tr( "Select File" ), path, filter );
658  if ( filename.isEmpty() )
659  return;
660 
661  settings.setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( filename ).path() );
662  QgsProcessingContext context;
663  setValue( filename, context );
664 }
665 
666 void QgsProcessingMapLayerComboBox::browseForLayer()
667 {
668  if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
669  {
671  widget->setPanelTitle( tr( "Browse for \"%1\"" ).arg( mParameter->description() ) );
672 
673  panel->openPanel( widget );
674 
675  connect( widget, &QgsDataSourceSelectWidget::itemTriggered, this, [ = ]( const QgsMimeDataUtils::Uri & )
676  {
677  widget->acceptPanel();
678  } );
679  connect( widget, &QgsPanelWidget::panelAccepted, this, [ = ]()
680  {
681  QgsProcessingContext context;
682  if ( widget->uri().uri.isEmpty() )
683  setValue( QVariant(), context );
684  else if ( widget->uri().providerKey == QLatin1String( "ogr" ) )
685  setValue( widget->uri().uri, context );
686  else
687  setValue( QgsProcessingUtils::encodeProviderKeyAndUri( widget->uri().providerKey, widget->uri().uri ), context );
688  } );
689  }
690 }
691 
692 
693 
QgsProcessingFeatureSourceDefinition::selectedFeaturesOnly
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
Definition: qgsprocessingparameters.h:122
QgsProcessingParameterWidgetContext
Definition: qgsprocessingwidgetwrapper.h:99
QgsMimeDataUtils::Uri::uri
QString uri
Identifier of the data source recognized by its providerKey.
Definition: qgsmimedatautils.h:123
QgsProperty
A store for object properties.
Definition: qgsproperty.h:231
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsFeatureRequest::GeometryAbortOnInvalid
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Definition: qgsfeaturerequest.h:116
QgsSettings::value
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Definition: qgssettings.cpp:174
QgsMapLayerProxyModel::RasterLayer
@ RasterLayer
Definition: qgsmaplayerproxymodel.h:44
QgsWkbTypes::NullGeometry
@ NullGeometry
Definition: qgswkbtypes.h:145
QgsMapLayerType::VectorLayer
@ VectorLayer
qgsprocessingmaplayercombobox.h
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:49
QgsMapLayerProxyModel::PolygonLayer
@ PolygonLayer
Definition: qgsmaplayerproxymodel.h:48
QgsMapLayerProxyModel::MeshLayer
@ MeshLayer
QgsMeshLayer.
Definition: qgsmaplayerproxymodel.h:53
QgsProcessing::TypeVectorPolygon
@ TypeVectorPolygon
Vector polygon layers.
Definition: qgsprocessing.h:50
QgsProcessingFeatureSourceDefinition::flags
Flags flags
Flags which dictate source behavior.
Definition: qgsprocessingparameters.h:137
QgsProcessingParameterDefinition
Definition: qgsprocessingparameters.h:330
QgsProcessing::TypeVectorLine
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:49
QgsSettings
Definition: qgssettings.h:61
QgsProcessingParameterFeatureSource
Definition: qgsprocessingparameters.h:2612
qgsfeatureid.h
QgsProcessingParameterMapLayer
Definition: qgsprocessingparameters.h:2456
QgsProcessingFeatureSourceDefinition::geometryCheck
QgsFeatureRequest::InvalidGeometryCheck geometryCheck
Geometry check method to apply to this source.
Definition: qgsprocessingparameters.h:147
qgsmimedatautils.h
QgsMimeDataUtils::UriList
QList< QgsMimeDataUtils::Uri > UriList
Definition: qgsmimedatautils.h:156
QgsProperty::propertyType
Type propertyType() const
Returns the property type.
Definition: qgsproperty.cpp:261
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:137
QgsProcessing::TypeVectorPoint
@ TypeVectorPoint
Vector point layers.
Definition: qgsprocessing.h:48
QgsProcessingFeatureSourceDefinition::source
QgsProperty source
Source definition.
Definition: qgsprocessingparameters.h:117
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:143
QgsProcessingParameterMeshLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2437
QgsMapLayerProxyModel::PointLayer
@ PointLayer
Definition: qgsmaplayerproxymodel.h:46
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:50
qgsapplication.h
QgsDataSourceSelectWidget::itemTriggered
void itemTriggered(const QgsMimeDataUtils::Uri &uri)
Emitted when an item is triggered, e.g.
QgsProcessingFeatureSourceDefinition
Definition: qgsprocessingparameters.h:55
QgsProcessing::TypeMapLayer
@ TypeMapLayer
Any map layer type (raster or vector or mesh)
Definition: qgsprocessing.h:46
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:270
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:53
QgsProcessingParameterRasterLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2114
QgsMapLayerProxyModel::HasGeometry
@ HasGeometry
Definition: qgsmaplayerproxymodel.h:49
QgsFileFilterGenerator
Definition: qgsfilefiltergenerator.h:33
QgsProcessingContext
Definition: qgsprocessingcontext.h:43
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:54
QgsPanelWidget::panelAccepted
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
QgsProcessing::TypeRaster
@ TypeRaster
Raster layers.
Definition: qgsprocessing.h:51
QgsPanelWidget::acceptPanel
void acceptPanel()
Accept the panel.
Definition: qgspanelwidget.cpp:107
QgsProcessing::TypeVectorAnyGeometry
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:47
QgsDataSourceSelectWidget
Definition: qgsdatasourceselectdialog.h:46
qgsprocessingwidgetwrapper.h
QgsPanelWidget::widgetChanged
void widgetChanged()
Emitted when the widget state changes.
QgsWkbTypes::geometryType
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:937
QgsMapLayer::id
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
Definition: qgsmaplayer.cpp:148
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:289
QgsProcessingParameterVectorLayer
Definition: qgsprocessingparameters.h:2382
QgsProcessingParameterFeatureSource::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2626
QgsMimeDataUtils::Uri
Definition: qgsmimedatautils.h:40
QgsFeatureIds
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
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:118
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:130
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:142
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:141
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:210
QgsVectorLayer
Definition: qgsvectorlayer.h:385
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsProcessingContext::expressionContext
QgsExpressionContext & expressionContext()
Returns the expression context.
Definition: qgsprocessingcontext.h:119
qgssettings.h
QgsMapLayerProxyModel::All
@ All
Definition: qgsmaplayerproxymodel.h:55
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:144
QgsMapLayerProxyModel::LineLayer
@ LineLayer
Definition: qgsmaplayerproxymodel.h:47
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:314
QgsProcessingParameterVectorLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2398
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:188
qgsdatasourceselectdialog.h
qgsguiutils.h
QgsProcessingParameterDefinition::FlagOptional
@ FlagOptional
Parameter is optional.
Definition: qgsprocessingparameters.h:421
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:257
qgspanelwidget.h
QgsProperty::StaticProperty
@ StaticProperty
Static property (QgsStaticProperty)
Definition: qgsproperty.h:239
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:2470