mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-16 00:03:12 -04:00
291 lines
11 KiB
C++
291 lines
11 KiB
C++
/***************************************************************************
|
|
qgsprocessingmodelerparameterwidget.cpp
|
|
---------------------------------------
|
|
begin : August 2018
|
|
copyright : (C) 2018 by Nyall Dawson
|
|
email : nyall dot dawson at gmail dot com
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
|
|
#include "qgsprocessingmodelerparameterwidget.h"
|
|
#include "qgsprocessingparameters.h"
|
|
#include "qgsexpressionlineedit.h"
|
|
#include "qgsprocessingguiregistry.h"
|
|
#include "models/qgsprocessingmodelalgorithm.h"
|
|
#include "qgsgui.h"
|
|
#include <QHBoxLayout>
|
|
#include <QToolButton>
|
|
#include <QStackedWidget>
|
|
#include <QMenu>
|
|
#include <QLabel>
|
|
#include <QComboBox>
|
|
|
|
QgsProcessingModelerParameterWidget::QgsProcessingModelerParameterWidget( QgsProcessingModelAlgorithm *model,
|
|
const QString &childId,
|
|
const QgsProcessingParameterDefinition *parameter, const QgsProcessingContext &context,
|
|
QWidget *parent )
|
|
: QWidget( parent )
|
|
, mModel( model )
|
|
, mChildId( childId )
|
|
, mParameterDefinition( parameter )
|
|
, mContext( context )
|
|
{
|
|
setFocusPolicy( Qt::StrongFocus );
|
|
|
|
// icon size is a bit bigger than text, but minimum size of 24 so that we get pixel-aligned rendering on low-dpi screens
|
|
int iconSize = static_cast< int >( std::floor( std::max( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.1, 24.0 ) ) );
|
|
|
|
QHBoxLayout *hLayout = new QHBoxLayout();
|
|
|
|
mSourceButton = new QToolButton();
|
|
mSourceButton->setFocusPolicy( Qt::StrongFocus );
|
|
|
|
// button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins
|
|
mSourceButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) );
|
|
mSourceButton->setIconSize( QSize( iconSize, iconSize ) );
|
|
mSourceButton->setPopupMode( QToolButton::InstantPopup );
|
|
|
|
mSourceMenu = new QMenu( this );
|
|
connect( mSourceMenu, &QMenu::aboutToShow, this, &QgsProcessingModelerParameterWidget::sourceMenuAboutToShow );
|
|
connect( mSourceMenu, &QMenu::triggered, this, &QgsProcessingModelerParameterWidget::sourceMenuActionTriggered );
|
|
mSourceButton->setMenu( mSourceMenu );
|
|
|
|
hLayout->addWidget( mSourceButton );
|
|
|
|
mStackedWidget = new QStackedWidget();
|
|
|
|
mStaticWidgetWrapper.reset( QgsGui::processingGuiRegistry()->createParameterWidgetWrapper( mParameterDefinition, QgsProcessingGui::Modeler ) );
|
|
if ( mStaticWidgetWrapper )
|
|
{
|
|
QWidget *widget = mStaticWidgetWrapper->createWrappedWidget( context );
|
|
if ( widget )
|
|
{
|
|
mHasStaticWrapper = true;
|
|
mStackedWidget->addWidget( widget );
|
|
}
|
|
else
|
|
mStackedWidget->addWidget( new QWidget() );
|
|
}
|
|
else
|
|
{
|
|
mStackedWidget->addWidget( new QWidget() );
|
|
}
|
|
|
|
mExpressionWidget = new QgsExpressionLineEdit();
|
|
mStackedWidget->addWidget( mExpressionWidget );
|
|
|
|
mModelInputCombo = new QComboBox();
|
|
QHBoxLayout *hLayout2 = new QHBoxLayout();
|
|
hLayout2->setMargin( 0 );
|
|
hLayout2->setContentsMargins( 0, 0, 0, 0 );
|
|
hLayout2->addWidget( new QLabel( tr( "Using model input" ) ) );
|
|
hLayout2->addWidget( mModelInputCombo, 1 );
|
|
QWidget *hWidget2 = new QWidget();
|
|
hWidget2->setLayout( hLayout2 );
|
|
mStackedWidget->addWidget( hWidget2 );
|
|
|
|
mChildOutputCombo = new QComboBox();
|
|
QHBoxLayout *hLayout3 = new QHBoxLayout();
|
|
hLayout3->setMargin( 0 );
|
|
hLayout3->setContentsMargins( 0, 0, 0, 0 );
|
|
hLayout3->addWidget( new QLabel( tr( "Using algorithm output" ) ) );
|
|
hLayout3->addWidget( mChildOutputCombo, 1 );
|
|
QWidget *hWidget3 = new QWidget();
|
|
hWidget3->setLayout( hLayout3 );
|
|
mStackedWidget->addWidget( hWidget3 );
|
|
|
|
hLayout->setMargin( 0 );
|
|
hLayout->setContentsMargins( 0, 0, 0, 0 );
|
|
hLayout->addWidget( mStackedWidget, 1 );
|
|
|
|
setLayout( hLayout );
|
|
setSourceType( QgsProcessingModelChildParameterSource::StaticValue );
|
|
}
|
|
|
|
QgsProcessingModelerParameterWidget::~QgsProcessingModelerParameterWidget() = default;
|
|
|
|
const QgsProcessingParameterDefinition *QgsProcessingModelerParameterWidget::parameterDefinition() const
|
|
{
|
|
return mParameterDefinition;
|
|
}
|
|
|
|
QLabel *QgsProcessingModelerParameterWidget::createLabel()
|
|
{
|
|
if ( mStaticWidgetWrapper )
|
|
return mStaticWidgetWrapper->createWrappedLabel();
|
|
else
|
|
return nullptr;
|
|
}
|
|
|
|
void QgsProcessingModelerParameterWidget::setWidgetValue( const QgsProcessingModelChildParameterSource &value )
|
|
{
|
|
// we make a copy of all attributes and store locally, so that users can flick between
|
|
// sources without losing their current value
|
|
mStaticValue = value.staticValue();
|
|
mModelInputParameterName = value.parameterName();
|
|
mOutputChildId = value.outputChildId();
|
|
mOutputName = value.outputName();
|
|
mExpression = value.expression();
|
|
|
|
updateUi();
|
|
setSourceType( value.source() );
|
|
}
|
|
|
|
QgsProcessingModelChildParameterSource QgsProcessingModelerParameterWidget::value() const
|
|
{
|
|
switch ( mStackedWidget->currentIndex() )
|
|
{
|
|
case 0:
|
|
return QgsProcessingModelChildParameterSource::fromStaticValue( mStaticWidgetWrapper->parameterValue() );
|
|
|
|
case 1:
|
|
return QgsProcessingModelChildParameterSource::fromExpression( mExpressionWidget->expression() );
|
|
|
|
case 2:
|
|
return QgsProcessingModelChildParameterSource::fromModelParameter( mModelInputCombo->currentData().toString() );
|
|
|
|
case 3:
|
|
{
|
|
const QStringList parts = mChildOutputCombo->currentData().toStringList();
|
|
return QgsProcessingModelChildParameterSource::fromChildOutput( parts.value( 0, QString() ), parts.value( 1, QString() ) );
|
|
}
|
|
}
|
|
|
|
return QgsProcessingModelChildParameterSource();
|
|
}
|
|
|
|
void QgsProcessingModelerParameterWidget::sourceMenuAboutToShow()
|
|
{
|
|
mSourceMenu->clear();
|
|
|
|
if ( mHasStaticWrapper )
|
|
{
|
|
QAction *fixedValueAction = mSourceMenu->addAction( tr( "Value" ) );
|
|
fixedValueAction->setCheckable( mStackedWidget->currentIndex() == 0 );
|
|
fixedValueAction->setChecked( mStackedWidget->currentIndex() == 0 );
|
|
fixedValueAction->setData( QgsProcessingModelChildParameterSource::StaticValue );
|
|
}
|
|
|
|
QAction *calculatedValueAction = mSourceMenu->addAction( tr( "Pre-calculated Value" ) );
|
|
calculatedValueAction->setCheckable( mStackedWidget->currentIndex() == 1 );
|
|
calculatedValueAction->setChecked( mStackedWidget->currentIndex() == 1 );
|
|
calculatedValueAction->setData( QgsProcessingModelChildParameterSource::Expression );
|
|
|
|
QAction *inputValueAction = mSourceMenu->addAction( tr( "Model Input" ) );
|
|
inputValueAction->setCheckable( mStackedWidget->currentIndex() == 2 );
|
|
inputValueAction->setChecked( mStackedWidget->currentIndex() == 2 );
|
|
inputValueAction->setData( QgsProcessingModelChildParameterSource::ModelParameter );
|
|
|
|
QAction *childOutputValueAction = mSourceMenu->addAction( tr( "Algorithm Output" ) );
|
|
childOutputValueAction->setCheckable( mStackedWidget->currentIndex() == 3 );
|
|
childOutputValueAction->setChecked( mStackedWidget->currentIndex() == 3 );
|
|
childOutputValueAction->setData( QgsProcessingModelChildParameterSource::ChildOutput );
|
|
|
|
// TODO - expression text item?
|
|
}
|
|
|
|
void QgsProcessingModelerParameterWidget::sourceMenuActionTriggered( QAction *action )
|
|
{
|
|
QgsProcessingModelChildParameterSource::Source sourceType = static_cast< QgsProcessingModelChildParameterSource::Source >( action->data().toInt() );
|
|
setSourceType( sourceType );
|
|
}
|
|
|
|
void QgsProcessingModelerParameterWidget::setSourceType( QgsProcessingModelChildParameterSource::Source type )
|
|
{
|
|
switch ( type )
|
|
{
|
|
case QgsProcessingModelChildParameterSource::StaticValue:
|
|
mStackedWidget->setCurrentIndex( 0 );
|
|
mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconFieldInteger.svg" ) ) );
|
|
mSourceButton->setToolTip( tr( "Value" ) );
|
|
break;
|
|
|
|
case QgsProcessingModelChildParameterSource::Expression:
|
|
mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconExpression.svg" ) ) );
|
|
mStackedWidget->setCurrentIndex( 1 );
|
|
mSourceButton->setToolTip( tr( "Pre-calculated Value" ) );
|
|
break;
|
|
|
|
case QgsProcessingModelChildParameterSource::ModelParameter:
|
|
{
|
|
mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingModel.svg" ) ) );
|
|
mStackedWidget->setCurrentIndex( 2 );
|
|
mSourceButton->setToolTip( tr( "Model Input" ) );
|
|
break;
|
|
}
|
|
|
|
case QgsProcessingModelChildParameterSource::ChildOutput:
|
|
{
|
|
mSourceButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "processingAlgorithm.svg" ) ) );
|
|
mStackedWidget->setCurrentIndex( 3 );
|
|
mSourceButton->setToolTip( tr( "Algorithm Output" ) );
|
|
break;
|
|
}
|
|
|
|
case QgsProcessingModelChildParameterSource::ExpressionText:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void QgsProcessingModelerParameterWidget::updateUi()
|
|
{
|
|
mStaticWidgetWrapper->setParameterValue( mStaticValue, mContext );
|
|
|
|
mExpressionWidget->setExpression( mExpression );
|
|
|
|
int currentIndex = mModelInputCombo->findData( mModelInputParameterName );
|
|
if ( currentIndex == -1 && mModelInputCombo->count() > 0 )
|
|
currentIndex = 0;
|
|
mModelInputCombo->setCurrentIndex( currentIndex );
|
|
|
|
const QStringList parts = QStringList() << mOutputChildId << mOutputName;
|
|
currentIndex = mChildOutputCombo->findData( parts );
|
|
if ( currentIndex == -1 && mChildOutputCombo->count() > 0 )
|
|
currentIndex = 0;
|
|
mChildOutputCombo->setCurrentIndex( currentIndex );
|
|
}
|
|
|
|
void QgsProcessingModelerParameterWidget::populateSources( const QStringList &compatibleParameterTypes, const QStringList &compatibleOutputTypes, const QList<int> &compatibleDataTypes )
|
|
{
|
|
const QList< QgsProcessingModelChildParameterSource > sources = mModel->availableSourcesForChild( mChildId,
|
|
compatibleParameterTypes, compatibleOutputTypes, compatibleDataTypes );
|
|
|
|
for ( const QgsProcessingModelChildParameterSource &source : sources )
|
|
{
|
|
switch ( source.source() )
|
|
{
|
|
case QgsProcessingModelChildParameterSource::ModelParameter:
|
|
mModelInputCombo->addItem( mModel->parameterDefinition( source.parameterName() )->description(), source.parameterName() );
|
|
break;
|
|
|
|
case QgsProcessingModelChildParameterSource::ChildOutput:
|
|
{
|
|
const QgsProcessingModelChildAlgorithm &alg = mModel->childAlgorithm( source.outputChildId() );
|
|
if ( !alg.algorithm() )
|
|
continue;
|
|
const QString outputDescription = alg.algorithm()->outputDefinition( source.outputName() )->description();
|
|
const QString childDescription = alg.description();
|
|
|
|
mChildOutputCombo->addItem( tr( "“%1” from algorithm “%2”" ).arg( outputDescription, childDescription ), QStringList() << source.outputChildId() << source.outputName() );
|
|
break;
|
|
}
|
|
|
|
case QgsProcessingModelChildParameterSource::StaticValue:
|
|
case QgsProcessingModelChildParameterSource::Expression:
|
|
case QgsProcessingModelChildParameterSource::ExpressionText:
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|