QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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->setContentsMargins( 0, 0, 0, 0 );
46  layout->setSpacing( 6 );
47 
48  mCombo = new QgsMapLayerComboBox();
49  layout->addWidget( mCombo );
50  layout->setAlignment( mCombo, Qt::AlignTop );
51 
53  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() && type == QgsProcessingGui::Standard )
54  {
55  mIterateButton = new QToolButton();
56  mIterateButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconIterate.svg" ) ) );
57  mIterateButton->setToolTip( tr( "Iterate over this layer, creating a separate output for every feature in the layer" ) );
58  mIterateButton->setCheckable( true );
59  mIterateButton->setAutoRaise( true );
60 
61  // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
62  mIterateButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
63  mIterateButton->setIconSize( QSize( iconSize, iconSize ) );
64 
65  layout->addWidget( mIterateButton );
66  layout->setAlignment( mIterateButton, Qt::AlignTop );
67  }
68 
69  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
70  {
71  mSettingsButton = new QToolButton();
72  mSettingsButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionOptions.svg" ) ) );
73  mSettingsButton->setToolTip( tr( "Advanced options" ) );
74 
75  // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
76  mSettingsButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
77  mSettingsButton->setIconSize( QSize( iconSize, iconSize ) );
78  mSettingsButton->setAutoRaise( true );
79 
80  connect( mSettingsButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::showSourceOptions );
81  layout->addWidget( mSettingsButton );
82  layout->setAlignment( mSettingsButton, Qt::AlignTop );
83  }
84 
85  mSelectButton = new QToolButton();
86  mSelectButton->setText( QString( QChar( 0x2026 ) ) );
87  mSelectButton->setToolTip( tr( "Select input" ) );
88  layout->addWidget( mSelectButton );
89  layout->setAlignment( mSelectButton, Qt::AlignTop );
90  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
91  {
92  mFeatureSourceMenu = new QMenu( this );
93  QAction *selectFromFileAction = new QAction( tr( "Select File…" ), mFeatureSourceMenu );
94  connect( selectFromFileAction, &QAction::triggered, this, &QgsProcessingMapLayerComboBox::selectFromFile );
95  mFeatureSourceMenu->addAction( selectFromFileAction );
96  QAction *browseForLayerAction = new QAction( tr( "Browse for Layer…" ), mFeatureSourceMenu );
97  connect( browseForLayerAction, &QAction::triggered, this, &QgsProcessingMapLayerComboBox::browseForLayer );
98  mFeatureSourceMenu->addAction( browseForLayerAction );
99  mSelectButton->setMenu( mFeatureSourceMenu );
100  mSelectButton->setPopupMode( QToolButton::InstantPopup );
101  }
102  else
103  {
104  connect( mSelectButton, &QToolButton::clicked, this, &QgsProcessingMapLayerComboBox::selectFromFile );
105  }
106 
107  QVBoxLayout *vl = new QVBoxLayout();
108  vl->setContentsMargins( 0, 0, 0, 0 );
109  vl->setSpacing( 6 );
110  vl->addLayout( layout );
111 
112  QgsMapLayerProxyModel::Filters filters = QgsMapLayerProxyModel::Filters();
113 
114  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() && type == QgsProcessingGui::Standard )
115  {
116  mUseSelectionCheckBox = new QCheckBox( tr( "Selected features only" ) );
117  mUseSelectionCheckBox->setChecked( false );
118  mUseSelectionCheckBox->setEnabled( false );
119  vl->addWidget( mUseSelectionCheckBox );
120  }
121 
122  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
123  {
124  QList<int> dataTypes;
125  if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
126  dataTypes = static_cast< QgsProcessingParameterFeatureSource *>( mParameter.get() )->dataTypes();
127  else if ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
128  dataTypes = static_cast< QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes();
129 
130  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.isEmpty() )
132  if ( dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
134  if ( dataTypes.contains( QgsProcessing::TypeVectorLine ) )
136  if ( dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
138  if ( !filters )
140  }
141  else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName() )
142  {
144  }
145  else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName() )
146  {
148  }
149  else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
150  {
151  QList<int> dataTypes;
152  dataTypes = static_cast< QgsProcessingParameterMapLayer *>( mParameter.get() )->dataTypes();
153 
154  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) )
156  if ( dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
158  if ( dataTypes.contains( QgsProcessing::TypeVectorLine ) )
160  if ( dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
162  if ( dataTypes.contains( QgsProcessing::TypeRaster ) )
164  if ( dataTypes.contains( QgsProcessing::TypeMesh ) )
166  if ( !filters )
167  filters = QgsMapLayerProxyModel::All;
168  }
169 
170  QgsSettings settings;
171  if ( settings.value( QStringLiteral( "Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
172  mCombo->setShowCrs( true );
173 
174  if ( filters )
175  mCombo->setFilters( filters );
176  mCombo->setExcludedProviders( QStringList() << QStringLiteral( "grass" ) ); // not sure if this is still required...
177 
178  if ( mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
179  {
180  mCombo->setAllowEmptyLayer( true );
181  mCombo->setLayer( nullptr );
182  }
183 
184  connect( mCombo, &QgsMapLayerComboBox::layerChanged, this, &QgsProcessingMapLayerComboBox::onLayerChanged );
185  if ( mUseSelectionCheckBox )
186  connect( mUseSelectionCheckBox, &QCheckBox::toggled, this, [ = ]
187  {
188  if ( !mBlockChangedSignal )
189  emit valueChanged();
190  } );
191 
192  setLayout( vl );
193 
194  setAcceptDrops( true );
195 
196  onLayerChanged( mCombo->currentLayer() );
197 }
198 
199 QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() = default;
200 
201 void QgsProcessingMapLayerComboBox::setLayer( QgsMapLayer *layer )
202 {
203  if ( layer || mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
204  mCombo->setLayer( layer );
205 }
206 
207 QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
208 {
209  return mCombo->currentLayer();
210 }
211 
212 QString QgsProcessingMapLayerComboBox::currentText()
213 {
214  return mCombo->currentText();
215 }
216 
217 void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessingContext &context )
218 {
219  if ( !value.isValid() && mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
220  {
221  setLayer( nullptr );
222  return;
223  }
224 
225  QVariant val = value;
226  bool found = false;
227  bool selectedOnly = false;
228  bool iterate = false;
229  if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
230  {
231  QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
232  val = fromVar.source;
233  selectedOnly = fromVar.selectedFeaturesOnly;
234  iterate = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature;
235  mFeatureLimit = fromVar.featureLimit;
236  mIsOverridingDefaultGeometryCheck = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
237  mGeometryCheck = fromVar.geometryCheck;
238  }
239  else
240  {
241  mFeatureLimit = -1;
242  mIsOverridingDefaultGeometryCheck = false;
244  }
245 
246  if ( val.canConvert<QgsProperty>() )
247  {
248  if ( val.value< QgsProperty >().propertyType() == QgsProperty::StaticProperty )
249  {
250  val = val.value< QgsProperty >().staticValue();
251  }
252  else
253  {
254  val = val.value< QgsProperty >().valueAsString( context.expressionContext(), mParameter->defaultValue().toString() );
255  }
256  }
257 
258  QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
259  if ( !layer && val.type() == QVariant::String )
260  {
261  layer = QgsProcessingUtils::mapLayerFromString( val.toString(), context, false );
262  }
263 
264  if ( layer )
265  {
266  mBlockChangedSignal++;
267  QgsMapLayer *prevLayer = currentLayer();
268  setLayer( layer );
269  found = static_cast< bool >( currentLayer() );
270  bool changed = found && ( currentLayer() != prevLayer );
271  if ( found && mUseSelectionCheckBox )
272  {
273  const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
274  changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
275  if ( hasSelection )
276  {
277  mUseSelectionCheckBox->setEnabled( true );
278  mUseSelectionCheckBox->setChecked( selectedOnly );
279  }
280  else
281  {
282  mUseSelectionCheckBox->setChecked( false );
283  mUseSelectionCheckBox->setEnabled( false );
284  }
285 
286  if ( mIterateButton )
287  {
288  mIterateButton->setChecked( iterate );
289  }
290  }
291  mBlockChangedSignal--;
292  if ( changed )
293  emit valueChanged(); // and ensure we only ever raise one
294  }
295 
296  if ( !found )
297  {
298  const QString string = val.toString();
299  if ( mIterateButton )
300  mIterateButton->setChecked( iterate );
301 
302  if ( !string.isEmpty() )
303  {
304  mBlockChangedSignal++;
305  if ( mCombo->findText( string ) < 0 )
306  {
307  QStringList additional = mCombo->additionalItems();
308  additional.append( string );
309  mCombo->setAdditionalItems( additional );
310  }
311  mCombo->setCurrentIndex( mCombo->findText( string ) ); // this may or may not throw a signal, so let's block it..
312  if ( mUseSelectionCheckBox )
313  {
314  mUseSelectionCheckBox->setChecked( false );
315  mUseSelectionCheckBox->setEnabled( false );
316  }
317  mBlockChangedSignal--;
318  if ( !mBlockChangedSignal )
319  emit valueChanged(); // and ensure we only ever raise one
320  }
321  else if ( mParameter->flags() & QgsProcessingParameterDefinition::FlagOptional )
322  {
323  mCombo->setLayer( nullptr );
324  if ( mUseSelectionCheckBox )
325  {
326  mUseSelectionCheckBox->setChecked( false );
327  mUseSelectionCheckBox->setEnabled( false );
328  }
329  }
330  }
331 }
332 
333 QVariant QgsProcessingMapLayerComboBox::value() const
334 {
335  if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
336  return mCombo->currentText();
337 
338  const bool iterate = mIterateButton && mIterateButton->isChecked();
339  const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
340  if ( QgsMapLayer *layer = mCombo->currentLayer() )
341  {
342  if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
343  return QgsProcessingFeatureSourceDefinition( layer->id(), selectedOnly, mFeatureLimit,
344  ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
345  | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
346  mGeometryCheck );
347  else
348  return layer->id();
349  }
350  else
351  {
352  if ( !mCombo->currentText().isEmpty() )
353  {
354  if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
355  return QgsProcessingFeatureSourceDefinition( mCombo->currentText(), selectedOnly, mFeatureLimit,
356  ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
357  | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
358  mGeometryCheck );
359  else
360  return mCombo->currentText();
361  }
362  }
363  return QVariant();
364 }
365 
366 void QgsProcessingMapLayerComboBox::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
367 {
368  mBrowserModel = context.browserModel();
369 }
370 
371 void QgsProcessingMapLayerComboBox::setEditable( bool editable )
372 {
373  mCombo->setEditable( editable );
374 }
375 
376 bool QgsProcessingMapLayerComboBox::isEditable() const
377 {
378  return mCombo->isEditable();
379 }
380 
381 QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData( const QMimeData *data, bool &incompatibleLayerSelected ) const
382 {
383  incompatibleLayerSelected = false;
385  for ( const QgsMimeDataUtils::Uri &u : uriList )
386  {
387  // is this uri from the current project?
388  if ( QgsMapLayer *layer = u.mapLayer() )
389  {
390  if ( mCombo->mProxyModel->acceptsLayer( layer ) )
391  return layer;
392  else
393  {
394  incompatibleLayerSelected = true;
395  return nullptr;
396  }
397  }
398  }
399  return nullptr;
400 }
401 
402 
403 QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData( const QMimeData *data ) const
404 {
406  for ( const QgsMimeDataUtils::Uri &u : uriList )
407  {
408  if ( ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName()
409  || mParameter->type() == QgsProcessingParameterVectorLayer::typeName() )
410  && u.layerType == QLatin1String( "vector" ) )
411  {
412  QList< int > dataTypes = mParameter->type() == QgsProcessingParameterFeatureSource::typeName() ? static_cast< QgsProcessingParameterFeatureSource * >( mParameter.get() )->dataTypes()
413  : ( mParameter->type() == QgsProcessingParameterVectorLayer::typeName() ? static_cast<QgsProcessingParameterVectorLayer *>( mParameter.get() )->dataTypes()
414  : QList< int >() );
415  bool acceptable = false;
416  switch ( QgsWkbTypes::geometryType( u.wkbType ) )
417  {
419  acceptable = true;
420  break;
421 
423  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
424  acceptable = true;
425  break;
426 
428  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorLine ) )
429  acceptable = true;
430  break;
431 
433  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeVector ) || dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
434  acceptable = true;
435  break;
436 
438  if ( dataTypes.contains( QgsProcessing::TypeVector ) )
439  acceptable = true;
440  break;
441  }
442  if ( acceptable )
443  return u.providerKey != QLatin1String( "ogr" ) ? QgsProcessingUtils::encodeProviderKeyAndUri( u.providerKey, u.uri ) : u.uri;
444  }
445  else if ( mParameter->type() == QgsProcessingParameterRasterLayer::typeName()
446  && u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" ) )
447  return u.uri;
448  else if ( mParameter->type() == QgsProcessingParameterMeshLayer::typeName()
449  && u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" ) )
450  return u.uri;
451  else if ( mParameter->type() == QgsProcessingParameterMapLayer::typeName() )
452  {
453  QList< int > dataTypes = static_cast< QgsProcessingParameterMapLayer * >( mParameter.get() )->dataTypes();
454  if ( dataTypes.isEmpty() || dataTypes.contains( QgsProcessing::TypeMapLayer ) )
455  {
456  return u.uri;
457  }
458 
459  if ( u.layerType == QLatin1String( "vector" ) && u.providerKey == QLatin1String( "ogr" ) )
460  {
461  switch ( QgsWkbTypes::geometryType( u.wkbType ) )
462  {
464  return u.uri;
465 
467  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPoint ) )
468  return u.uri;
469  break;
470 
472  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorLine ) )
473  return u.uri;
474  break;
475 
477  if ( dataTypes.contains( QgsProcessing::TypeVectorAnyGeometry ) || dataTypes.contains( QgsProcessing::TypeVectorPolygon ) )
478  return u.uri;
479  break;
480 
482  return u.uri;
483  }
484  }
485  else if ( u.layerType == QLatin1String( "raster" ) && u.providerKey == QLatin1String( "gdal" )
486  && dataTypes.contains( QgsProcessing::TypeRaster ) )
487  return u.uri;
488  else if ( u.layerType == QLatin1String( "mesh" ) && u.providerKey == QLatin1String( "mdal" )
489  && dataTypes.contains( QgsProcessing::TypeMesh ) )
490  return u.uri;
491  }
492  }
493  if ( !uriList.isEmpty() )
494  return QString();
495 
496  // second chance -- files dragged from file explorer, outside of QGIS
497  QStringList rawPaths;
498  if ( data->hasUrls() )
499  {
500  const QList< QUrl > urls = data->urls();
501  rawPaths.reserve( urls.count() );
502  for ( const QUrl &url : urls )
503  {
504  const QString local = url.toLocalFile();
505  if ( !rawPaths.contains( local ) )
506  rawPaths.append( local );
507  }
508  }
509  if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
510  rawPaths.append( data->text() );
511 
512  for ( const QString &path : qgis::as_const( rawPaths ) )
513  {
514  QFileInfo file( path );
515  if ( file.isFile() )
516  {
517  // TODO - we should check to see if it's a valid extension for the parameter, but that's non-trivial
518  return path;
519  }
520  }
521 
522  return QString();
523 }
524 
525 void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
526 {
527  if ( !( event->possibleActions() & Qt::CopyAction ) )
528  return;
529 
530  bool incompatibleLayerSelected = false;
531  QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
532  const QString uri = compatibleUriFromMimeData( event->mimeData() );
533  if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
534  {
535  // dragged an acceptable layer, phew
536  event->setDropAction( Qt::CopyAction );
537  event->accept();
538  mDragActive = true;
539  mCombo->mHighlight = true;
540  update();
541  }
542 }
543 
544 void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
545 {
546  QWidget::dragLeaveEvent( event );
547  if ( mDragActive )
548  {
549  event->accept();
550  mDragActive = false;
551  mCombo->mHighlight = false;
552  update();
553  }
554 }
555 
556 void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
557 {
558  if ( !( event->possibleActions() & Qt::CopyAction ) )
559  return;
560 
561  bool incompatibleLayerSelected = false;
562  QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
563  const QString uri = compatibleUriFromMimeData( event->mimeData() );
564  if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
565  {
566  // dropped an acceptable layer, phew
567  setFocus( Qt::MouseFocusReason );
568  event->setDropAction( Qt::CopyAction );
569  event->accept();
570  QgsProcessingContext context;
571  setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
572  }
573  mDragActive = false;
574  mCombo->mHighlight = false;
575  update();
576 }
577 
578 void QgsProcessingMapLayerComboBox::onLayerChanged( QgsMapLayer *layer )
579 {
580  if ( mUseSelectionCheckBox && mParameter->type() == QgsProcessingParameterFeatureSource::typeName() )
581  {
582  if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
583  {
584  if ( QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
585  {
586  disconnect( prevLayer, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
587  }
588  if ( vl->selectedFeatureCount() == 0 )
589  mUseSelectionCheckBox->setChecked( false );
590  mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
591  connect( vl, &QgsVectorLayer::selectionChanged, this, &QgsProcessingMapLayerComboBox::selectionChanged );
592  }
593  }
594 
595  mPrevLayer = layer;
596  if ( !mBlockChangedSignal )
597  emit valueChanged();
598 }
599 
600 void QgsProcessingMapLayerComboBox::selectionChanged( const QgsFeatureIds &selected, const QgsFeatureIds &, bool )
601 {
602  if ( selected.isEmpty() )
603  mUseSelectionCheckBox->setChecked( false );
604  mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
605 }
606 
607 void QgsProcessingMapLayerComboBox::showSourceOptions()
608 {
609  if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
610  {
611  QgsProcessingFeatureSourceOptionsWidget *widget = new QgsProcessingFeatureSourceOptionsWidget();
612  widget->setPanelTitle( tr( "%1 Options" ).arg( mParameter->description() ) );
613 
614  widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
615  widget->setFeatureLimit( mFeatureLimit );
616 
617  panel->openPanel( widget );
618 
619  connect( widget, &QgsPanelWidget::widgetChanged, this, [ = ]
620  {
621  bool changed = false;
622  changed = changed | ( widget->featureLimit() != mFeatureLimit );
623  changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
624  changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
625 
626  mFeatureLimit = widget->featureLimit();
627  mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
628  mGeometryCheck = widget->geometryCheckMethod();
629 
630  if ( changed )
631  emit valueChanged();
632  } );
633  }
634 }
635 
636 void QgsProcessingMapLayerComboBox::selectFromFile()
637 {
638  QgsSettings settings;
639  const QString initialValue = currentText();
640  QString path;
641 
642  if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( initialValue ) )
643  path = initialValue;
644  else if ( QFileInfo::exists( QFileInfo( initialValue ).path() ) && QFileInfo( initialValue ).path() != '.' )
645  path = QFileInfo( initialValue ).path();
646  else if ( settings.contains( QStringLiteral( "/Processing/LastInputPath" ) ) )
647  path = settings.value( QStringLiteral( "/Processing/LastInputPath" ) ).toString();
648 
649  QString filter;
650  if ( const QgsFileFilterGenerator *generator = dynamic_cast< const QgsFileFilterGenerator * >( mParameter.get() ) )
651  filter = generator->createFileFilter();
652  else
653  filter = QObject::tr( "All files (*.*)" );
654 
655  const QString filename = QFileDialog::getOpenFileName( this, tr( "Select File" ), path, filter );
656  if ( filename.isEmpty() )
657  return;
658 
659  settings.setValue( QStringLiteral( "/Processing/LastInputPath" ), QFileInfo( filename ).path() );
660  QgsProcessingContext context;
661  setValue( filename, context );
662 }
663 
664 void QgsProcessingMapLayerComboBox::browseForLayer()
665 {
666  if ( QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ) )
667  {
669  widget->setPanelTitle( tr( "Browse for \"%1\"" ).arg( mParameter->description() ) );
670 
671  panel->openPanel( widget );
672 
673  connect( widget, &QgsDataSourceSelectWidget::itemTriggered, this, [ = ]( const QgsMimeDataUtils::Uri & )
674  {
675  widget->acceptPanel();
676  } );
677  connect( widget, &QgsPanelWidget::panelAccepted, this, [ = ]()
678  {
679  QgsProcessingContext context;
680  if ( widget->uri().uri.isEmpty() )
681  setValue( QVariant(), context );
682  else if ( widget->uri().providerKey == QLatin1String( "ogr" ) )
683  setValue( widget->uri().uri, context );
684  else
685  setValue( QgsProcessingUtils::encodeProviderKeyAndUri( widget->uri().providerKey, widget->uri().uri ), context );
686  } );
687  }
688 }
689 
690 
691 
QgsProcessingFeatureSourceDefinition::selectedFeaturesOnly
bool selectedFeaturesOnly
true if only selected features in the source should be used by algorithms.
Definition: qgsprocessingparameters.h:122
QgsProcessingParameterWidgetContext
Contains settings which reflect the context in which a Processing parameter widget is shown,...
Definition: qgsprocessingwidgetwrapper.h:100
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:232
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:626
QgsFeatureRequest::GeometryAbortOnInvalid
@ GeometryAbortOnInvalid
Close iterator on encountering any features with invalid geometry. This requires a slow geometry vali...
Definition: qgsfeaturerequest.h:103
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:146
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
Base class for the definition of processing parameters.
Definition: qgsprocessingparameters.h:331
QgsProcessing::TypeVectorLine
@ TypeVectorLine
Vector line layers.
Definition: qgsprocessing.h:49
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QgsProcessingParameterFeatureSource
An input feature source (such as vector layers) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2734
qgsfeatureid.h
QgsProcessingParameterMapLayer
A map layer parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2578
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:144
QgsProcessingParameterMeshLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2558
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:250
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
Encapsulates settings relating to a feature source input to a processing algorithm.
Definition: qgsprocessingparameters.h:56
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:30
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:2235
QgsMapLayerProxyModel::HasGeometry
@ HasGeometry
Definition: qgsmaplayerproxymodel.h:49
QgsFileFilterGenerator
Abstract interface for classes which generate a file filter string.
Definition: qgsfilefiltergenerator.h:34
QgsProcessingContext
Contains information about the context in which a processing algorithm is executed.
Definition: qgsprocessingcontext.h:44
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
The QgsDataSourceSelectWidget class embeds the browser view to select an existing data source.
Definition: qgsdatasourceselectdialog.h:47
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: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
A vector layer (with or without geometry) parameter for processing algorithms.
Definition: qgsprocessingparameters.h:2504
QgsProcessingParameterFeatureSource::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2747
QgsMimeDataUtils::Uri
Definition: qgsmimedatautils.h:41
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:118
qgsvectorlayer.h
QgsMapLayerComboBox
The QgsMapLayerComboBox class is a combo box which displays the list of layers.
Definition: qgsmaplayercombobox.h:35
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:143
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
QgsProcessingGui::WidgetType
WidgetType
Types of dialogs which Processing widgets can be created for.
Definition: qgsprocessinggui.h:39
qgsmaplayercombobox.h
QgsMimeDataUtils::decodeUriList
static UriList decodeUriList(const QMimeData *data)
Definition: qgsmimedatautils.cpp:211
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:387
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
QgsProcessingContext::expressionContext
QgsExpressionContext & expressionContext()
Returns the expression context.
Definition: qgsprocessingcontext.h:133
qgssettings.h
QgsMapLayerProxyModel::All
@ All
Definition: qgsmaplayerproxymodel.h:55
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:145
QgsMapLayerProxyModel::LineLayer
@ LineLayer
Definition: qgsmaplayerproxymodel.h:47
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:938
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:316
QgsProcessingParameterVectorLayer::typeName
static QString typeName()
Returns the type name for the parameter class.
Definition: qgsprocessingparameters.h:2519
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:425
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:245
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:2591