29 #include <QHBoxLayout>
30 #include <QVBoxLayout>
31 #include <QToolButton>
33 #include <QDragEnterEvent>
36 #include <QFileDialog>
42 , mParameter( parameter->clone() )
44 QHBoxLayout *layout =
new QHBoxLayout();
45 layout->setMargin( 0 );
46 layout->setContentsMargins( 0, 0, 0, 0 );
47 layout->setSpacing( 6 );
50 layout->addWidget( mCombo );
51 layout->setAlignment( mCombo, Qt::AlignTop );
56 mIterateButton =
new QToolButton();
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 );
63 mIterateButton->setFixedSize( 2 *
static_cast< int >( 1.25 *
iconSize / 2.0 ), 2 *
static_cast< int >(
iconSize * 1.1 / 2.0 ) );
66 layout->addWidget( mIterateButton );
67 layout->setAlignment( mIterateButton, Qt::AlignTop );
72 mSettingsButton =
new QToolButton();
74 mSettingsButton->setToolTip( tr(
"Advanced options" ) );
77 mSettingsButton->setFixedSize( 2 *
static_cast< int >( 1.25 *
iconSize / 2.0 ), 2 *
static_cast< int >(
iconSize * 1.1 / 2.0 ) );
79 mSettingsButton->setAutoRaise(
true );
81 connect( mSettingsButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::showSourceOptions );
82 layout->addWidget( mSettingsButton );
83 layout->setAlignment( mSettingsButton, Qt::AlignTop );
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 );
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 );
105 connect( mSelectButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
108 QVBoxLayout *vl =
new QVBoxLayout();
110 vl->setContentsMargins( 0, 0, 0, 0 );
112 vl->addLayout( layout );
114 QgsMapLayerProxyModel::Filters filters =
nullptr;
118 mUseSelectionCheckBox =
new QCheckBox( tr(
"Selected features only" ) );
119 mUseSelectionCheckBox->setChecked(
false );
120 mUseSelectionCheckBox->setEnabled(
false );
121 vl->addWidget( mUseSelectionCheckBox );
126 QList<int> dataTypes;
153 QList<int> dataTypes;
173 if ( settings.
value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
174 mCombo->setShowCrs(
true );
177 mCombo->setFilters( filters );
178 mCombo->setExcludedProviders( QStringList() << QStringLiteral(
"grass" ) );
182 mCombo->setAllowEmptyLayer(
true );
183 mCombo->setLayer(
nullptr );
187 if ( mUseSelectionCheckBox )
188 connect( mUseSelectionCheckBox, &QCheckBox::toggled,
this, [ = ]
190 if ( !mBlockChangedSignal )
196 setAcceptDrops(
true );
198 onLayerChanged( mCombo->currentLayer() );
201 QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() =
default;
203 void QgsProcessingMapLayerComboBox::setLayer(
QgsMapLayer *layer )
206 mCombo->setLayer( layer );
209 QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
211 return mCombo->currentLayer();
214 QString QgsProcessingMapLayerComboBox::currentText()
216 return mCombo->currentText();
219 void QgsProcessingMapLayerComboBox::setValue(
const QVariant &value,
QgsProcessingContext &context )
227 QVariant val = value;
229 bool selectedOnly =
false;
230 bool iterate =
false;
236 iterate = fromVar.
flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature;
238 mIsOverridingDefaultGeometryCheck = fromVar.
flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
244 mIsOverridingDefaultGeometryCheck =
false;
260 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
261 if ( !layer && val.type() == QVariant::String )
268 mBlockChangedSignal++;
271 found =
static_cast< bool >( currentLayer() );
272 bool changed = found && ( currentLayer() != prevLayer );
273 if ( found && mUseSelectionCheckBox )
275 const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
276 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
279 mUseSelectionCheckBox->setEnabled(
true );
280 mUseSelectionCheckBox->setChecked( selectedOnly );
284 mUseSelectionCheckBox->setChecked(
false );
285 mUseSelectionCheckBox->setEnabled(
false );
288 if ( mIterateButton )
290 mIterateButton->setChecked( iterate );
293 mBlockChangedSignal--;
300 const QString
string = val.toString();
301 if ( mIterateButton )
302 mIterateButton->setChecked( iterate );
304 if ( !
string.isEmpty() )
306 mBlockChangedSignal++;
307 if ( mCombo->findText(
string ) < 0 )
309 QStringList additional = mCombo->additionalItems();
310 additional.append(
string );
311 mCombo->setAdditionalItems( additional );
313 mCombo->setCurrentIndex( mCombo->findText(
string ) );
314 if ( mUseSelectionCheckBox )
316 mUseSelectionCheckBox->setChecked(
false );
317 mUseSelectionCheckBox->setEnabled(
false );
319 mBlockChangedSignal--;
320 if ( !mBlockChangedSignal )
325 mCombo->setLayer(
nullptr );
326 if ( mUseSelectionCheckBox )
328 mUseSelectionCheckBox->setChecked(
false );
329 mUseSelectionCheckBox->setEnabled(
false );
335 QVariant QgsProcessingMapLayerComboBox::value()
const
337 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
338 return mCombo->currentText();
340 const bool iterate = mIterateButton && mIterateButton->isChecked();
341 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
344 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
346 ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
347 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
354 if ( !mCombo->currentText().isEmpty() )
356 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
358 ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
359 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
362 return mCombo->currentText();
373 void QgsProcessingMapLayerComboBox::setEditable(
bool editable )
375 mCombo->setEditable( editable );
378 bool QgsProcessingMapLayerComboBox::isEditable()
const
380 return mCombo->isEditable();
383 QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData(
const QMimeData *data,
bool &incompatibleLayerSelected )
const
385 incompatibleLayerSelected =
false;
392 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
396 incompatibleLayerSelected =
true;
405 QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData(
const QMimeData *data )
const
412 && u.layerType == QLatin1String(
"vector" ) )
417 bool acceptable =
false;
448 && u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" ) )
451 && u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" ) )
461 if ( u.layerType == QLatin1String(
"vector" ) && u.providerKey == QLatin1String(
"ogr" ) )
487 else if ( u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" )
490 else if ( u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" )
495 if ( !uriList.isEmpty() )
499 QStringList rawPaths;
500 if ( data->hasUrls() )
502 const QList< QUrl > urls = data->urls();
503 rawPaths.reserve( urls.count() );
504 for (
const QUrl &url : urls )
506 const QString local = url.toLocalFile();
507 if ( !rawPaths.contains( local ) )
508 rawPaths.append( local );
511 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
512 rawPaths.append( data->text() );
514 for (
const QString &path : qgis::as_const( rawPaths ) )
516 QFileInfo file( path );
527 void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
529 if ( !( event->possibleActions() & Qt::CopyAction ) )
532 bool incompatibleLayerSelected =
false;
533 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
534 const QString uri = compatibleUriFromMimeData( event->mimeData() );
535 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
538 event->setDropAction( Qt::CopyAction );
541 mCombo->mHighlight =
true;
546 void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
548 QWidget::dragLeaveEvent( event );
553 mCombo->mHighlight =
false;
558 void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
560 if ( !( event->possibleActions() & Qt::CopyAction ) )
563 bool incompatibleLayerSelected =
false;
564 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
565 const QString uri = compatibleUriFromMimeData( event->mimeData() );
566 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
569 setFocus( Qt::MouseFocusReason );
570 event->setDropAction( Qt::CopyAction );
573 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
576 mCombo->mHighlight =
false;
580 void QgsProcessingMapLayerComboBox::onLayerChanged(
QgsMapLayer *layer )
584 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
586 if (
QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
590 if ( vl->selectedFeatureCount() == 0 )
591 mUseSelectionCheckBox->setChecked(
false );
592 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
598 if ( !mBlockChangedSignal )
604 if ( selected.isEmpty() )
605 mUseSelectionCheckBox->setChecked(
false );
606 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
609 void QgsProcessingMapLayerComboBox::showSourceOptions()
613 QgsProcessingFeatureSourceOptionsWidget *widget =
new QgsProcessingFeatureSourceOptionsWidget();
614 widget->setPanelTitle( tr(
"%1 Options" ).arg( mParameter->description() ) );
616 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
617 widget->setFeatureLimit( mFeatureLimit );
619 panel->openPanel( widget );
623 bool changed =
false;
624 changed = changed | ( widget->featureLimit() != mFeatureLimit );
625 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
626 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
628 mFeatureLimit = widget->featureLimit();
629 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
630 mGeometryCheck = widget->geometryCheckMethod();
638 void QgsProcessingMapLayerComboBox::selectFromFile()
641 const QString initialValue = currentText();
644 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( 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();
653 filter = generator->createFileFilter();
655 filter = QObject::tr(
"All files (*.*)" );
657 const QString filename = QFileDialog::getOpenFileName(
this, tr(
"Select File" ), path, filter );
658 if ( filename.isEmpty() )
661 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filename ).path() );
663 setValue( filename, context );
666 void QgsProcessingMapLayerComboBox::browseForLayer()
671 widget->
setPanelTitle( tr(
"Browse for \"%1\"" ).arg( mParameter->description() ) );
673 panel->openPanel( widget );
682 if ( widget->
uri().
uri.isEmpty() )
683 setValue( QVariant(), context );
685 setValue( widget->
uri().
uri, context );