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->setContentsMargins( 0, 0, 0, 0 );
46 layout->setSpacing( 6 );
49 layout->addWidget( mCombo );
50 layout->setAlignment( mCombo, Qt::AlignTop );
55 mIterateButton =
new QToolButton();
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 );
62 mIterateButton->setFixedSize( 2 *
static_cast< int >( 1.25 *
iconSize / 2.0 ), 2 *
static_cast< int >(
iconSize * 1.1 / 2.0 ) );
65 layout->addWidget( mIterateButton );
66 layout->setAlignment( mIterateButton, Qt::AlignTop );
71 mSettingsButton =
new QToolButton();
73 mSettingsButton->setToolTip( tr(
"Advanced options" ) );
76 mSettingsButton->setFixedSize( 2 *
static_cast< int >( 1.25 *
iconSize / 2.0 ), 2 *
static_cast< int >(
iconSize * 1.1 / 2.0 ) );
78 mSettingsButton->setAutoRaise(
true );
80 connect( mSettingsButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::showSourceOptions );
81 layout->addWidget( mSettingsButton );
82 layout->setAlignment( mSettingsButton, Qt::AlignTop );
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 );
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 );
104 connect( mSelectButton, &QToolButton::clicked,
this, &QgsProcessingMapLayerComboBox::selectFromFile );
107 QVBoxLayout *vl =
new QVBoxLayout();
108 vl->setContentsMargins( 0, 0, 0, 0 );
110 vl->addLayout( layout );
112 QgsMapLayerProxyModel::Filters filters = QgsMapLayerProxyModel::Filters();
116 mUseSelectionCheckBox =
new QCheckBox( tr(
"Selected features only" ) );
117 mUseSelectionCheckBox->setChecked(
false );
118 mUseSelectionCheckBox->setEnabled(
false );
119 vl->addWidget( mUseSelectionCheckBox );
124 QList<int> dataTypes;
151 QList<int> dataTypes;
171 if ( settings.
value( QStringLiteral(
"Processing/Configuration/SHOW_CRS_DEF" ), true ).toBool() )
172 mCombo->setShowCrs(
true );
175 mCombo->setFilters( filters );
176 mCombo->setExcludedProviders( QStringList() << QStringLiteral(
"grass" ) );
180 mCombo->setAllowEmptyLayer(
true );
181 mCombo->setLayer(
nullptr );
185 if ( mUseSelectionCheckBox )
186 connect( mUseSelectionCheckBox, &QCheckBox::toggled,
this, [ = ]
188 if ( !mBlockChangedSignal )
194 setAcceptDrops(
true );
196 onLayerChanged( mCombo->currentLayer() );
199 QgsProcessingMapLayerComboBox::~QgsProcessingMapLayerComboBox() =
default;
201 void QgsProcessingMapLayerComboBox::setLayer(
QgsMapLayer *layer )
204 mCombo->setLayer( layer );
207 QgsMapLayer *QgsProcessingMapLayerComboBox::currentLayer()
209 return mCombo->currentLayer();
212 QString QgsProcessingMapLayerComboBox::currentText()
214 return mCombo->currentText();
217 void QgsProcessingMapLayerComboBox::setValue(
const QVariant &value,
QgsProcessingContext &context )
225 QVariant val = value;
227 bool selectedOnly =
false;
228 bool iterate =
false;
234 iterate = fromVar.
flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature;
236 mIsOverridingDefaultGeometryCheck = fromVar.
flags & QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck;
242 mIsOverridingDefaultGeometryCheck =
false;
258 QgsMapLayer *layer = qobject_cast< QgsMapLayer * >( val.value< QObject * >() );
259 if ( !layer && val.type() == QVariant::String )
266 mBlockChangedSignal++;
269 found =
static_cast< bool >( currentLayer() );
270 bool changed = found && ( currentLayer() != prevLayer );
271 if ( found && mUseSelectionCheckBox )
273 const bool hasSelection = qobject_cast< QgsVectorLayer * >( layer ) && qobject_cast< QgsVectorLayer * >( layer )->selectedFeatureCount() > 0;
274 changed = changed | ( ( hasSelection && selectedOnly ) != mUseSelectionCheckBox->isChecked() );
277 mUseSelectionCheckBox->setEnabled(
true );
278 mUseSelectionCheckBox->setChecked( selectedOnly );
282 mUseSelectionCheckBox->setChecked(
false );
283 mUseSelectionCheckBox->setEnabled(
false );
286 if ( mIterateButton )
288 mIterateButton->setChecked( iterate );
291 mBlockChangedSignal--;
298 const QString
string = val.toString();
299 if ( mIterateButton )
300 mIterateButton->setChecked( iterate );
302 if ( !
string.isEmpty() )
304 mBlockChangedSignal++;
305 if ( mCombo->findText(
string ) < 0 )
307 QStringList additional = mCombo->additionalItems();
308 additional.append(
string );
309 mCombo->setAdditionalItems( additional );
311 mCombo->setCurrentIndex( mCombo->findText(
string ) );
312 if ( mUseSelectionCheckBox )
314 mUseSelectionCheckBox->setChecked(
false );
315 mUseSelectionCheckBox->setEnabled(
false );
317 mBlockChangedSignal--;
318 if ( !mBlockChangedSignal )
323 mCombo->setLayer(
nullptr );
324 if ( mUseSelectionCheckBox )
326 mUseSelectionCheckBox->setChecked(
false );
327 mUseSelectionCheckBox->setEnabled(
false );
333 QVariant QgsProcessingMapLayerComboBox::value()
const
335 if ( isEditable() && mCombo->currentText() != mCombo->itemText( mCombo->currentIndex() ) )
336 return mCombo->currentText();
338 const bool iterate = mIterateButton && mIterateButton->isChecked();
339 const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked();
342 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
344 ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
345 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
352 if ( !mCombo->currentText().isEmpty() )
354 if ( selectedOnly || iterate || mFeatureLimit != -1 || mIsOverridingDefaultGeometryCheck )
356 ( iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() )
357 | ( mIsOverridingDefaultGeometryCheck ? QgsProcessingFeatureSourceDefinition::Flag::FlagOverrideDefaultGeometryCheck : QgsProcessingFeatureSourceDefinition::Flags() ),
360 return mCombo->currentText();
371 void QgsProcessingMapLayerComboBox::setEditable(
bool editable )
373 mCombo->setEditable( editable );
376 bool QgsProcessingMapLayerComboBox::isEditable()
const
378 return mCombo->isEditable();
381 QgsMapLayer *QgsProcessingMapLayerComboBox::compatibleMapLayerFromMimeData(
const QMimeData *data,
bool &incompatibleLayerSelected )
const
383 incompatibleLayerSelected =
false;
390 if ( mCombo->mProxyModel->acceptsLayer( layer ) )
394 incompatibleLayerSelected =
true;
403 QString QgsProcessingMapLayerComboBox::compatibleUriFromMimeData(
const QMimeData *data )
const
410 && u.layerType == QLatin1String(
"vector" ) )
415 bool acceptable =
false;
446 && u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" ) )
449 && u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" ) )
459 if ( u.layerType == QLatin1String(
"vector" ) && u.providerKey == QLatin1String(
"ogr" ) )
485 else if ( u.layerType == QLatin1String(
"raster" ) && u.providerKey == QLatin1String(
"gdal" )
488 else if ( u.layerType == QLatin1String(
"mesh" ) && u.providerKey == QLatin1String(
"mdal" )
493 if ( !uriList.isEmpty() )
497 QStringList rawPaths;
498 if ( data->hasUrls() )
500 const QList< QUrl > urls = data->urls();
501 rawPaths.reserve( urls.count() );
502 for (
const QUrl &url : urls )
504 const QString local = url.toLocalFile();
505 if ( !rawPaths.contains( local ) )
506 rawPaths.append( local );
509 if ( !data->text().isEmpty() && !rawPaths.contains( data->text() ) )
510 rawPaths.append( data->text() );
512 for (
const QString &path : qgis::as_const( rawPaths ) )
514 QFileInfo file( path );
525 void QgsProcessingMapLayerComboBox::dragEnterEvent( QDragEnterEvent *event )
527 if ( !( event->possibleActions() & Qt::CopyAction ) )
530 bool incompatibleLayerSelected =
false;
531 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
532 const QString uri = compatibleUriFromMimeData( event->mimeData() );
533 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
536 event->setDropAction( Qt::CopyAction );
539 mCombo->mHighlight =
true;
544 void QgsProcessingMapLayerComboBox::dragLeaveEvent( QDragLeaveEvent *event )
546 QWidget::dragLeaveEvent( event );
551 mCombo->mHighlight =
false;
556 void QgsProcessingMapLayerComboBox::dropEvent( QDropEvent *event )
558 if ( !( event->possibleActions() & Qt::CopyAction ) )
561 bool incompatibleLayerSelected =
false;
562 QgsMapLayer *layer = compatibleMapLayerFromMimeData( event->mimeData(), incompatibleLayerSelected );
563 const QString uri = compatibleUriFromMimeData( event->mimeData() );
564 if ( layer || ( !incompatibleLayerSelected && !uri.isEmpty() ) )
567 setFocus( Qt::MouseFocusReason );
568 event->setDropAction( Qt::CopyAction );
571 setValue( layer ? QVariant::fromValue( layer ) : QVariant::fromValue( uri ), context );
574 mCombo->mHighlight =
false;
578 void QgsProcessingMapLayerComboBox::onLayerChanged(
QgsMapLayer *layer )
582 if (
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
584 if (
QgsVectorLayer *prevLayer = qobject_cast< QgsVectorLayer * >( mPrevLayer ) )
588 if ( vl->selectedFeatureCount() == 0 )
589 mUseSelectionCheckBox->setChecked(
false );
590 mUseSelectionCheckBox->setEnabled( vl->selectedFeatureCount() > 0 );
596 if ( !mBlockChangedSignal )
602 if ( selected.isEmpty() )
603 mUseSelectionCheckBox->setChecked(
false );
604 mUseSelectionCheckBox->setEnabled( !selected.isEmpty() );
607 void QgsProcessingMapLayerComboBox::showSourceOptions()
611 QgsProcessingFeatureSourceOptionsWidget *widget =
new QgsProcessingFeatureSourceOptionsWidget();
612 widget->setPanelTitle( tr(
"%1 Options" ).arg( mParameter->description() ) );
614 widget->setGeometryCheckMethod( mIsOverridingDefaultGeometryCheck, mGeometryCheck );
615 widget->setFeatureLimit( mFeatureLimit );
617 panel->openPanel( widget );
621 bool changed =
false;
622 changed = changed | ( widget->featureLimit() != mFeatureLimit );
623 changed = changed | ( widget->isOverridingInvalidGeometryCheck() != mIsOverridingDefaultGeometryCheck );
624 changed = changed | ( widget->geometryCheckMethod() != mGeometryCheck );
626 mFeatureLimit = widget->featureLimit();
627 mIsOverridingDefaultGeometryCheck = widget->isOverridingInvalidGeometryCheck();
628 mGeometryCheck = widget->geometryCheckMethod();
636 void QgsProcessingMapLayerComboBox::selectFromFile()
639 const QString initialValue = currentText();
642 if ( QFileInfo( initialValue ).isDir() && QFileInfo::exists( 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();
651 filter = generator->createFileFilter();
653 filter = QObject::tr(
"All files (*.*)" );
655 const QString filename = QFileDialog::getOpenFileName(
this, tr(
"Select File" ), path, filter );
656 if ( filename.isEmpty() )
659 settings.
setValue( QStringLiteral(
"/Processing/LastInputPath" ), QFileInfo( filename ).path() );
661 setValue( filename, context );
664 void QgsProcessingMapLayerComboBox::browseForLayer()
669 widget->
setPanelTitle( tr(
"Browse for \"%1\"" ).arg( mParameter->description() ) );
671 panel->openPanel( widget );
680 if ( widget->
uri().
uri.isEmpty() )
681 setValue( QVariant(), context );
683 setValue( widget->
uri().
uri, context );