Add geometry processing parameter

This commit is contained in:
David Marteau 2020-09-07 21:21:50 +02:00 committed by Nyall Dawson
parent cd04374d51
commit 4eb931e890
13 changed files with 638 additions and 0 deletions

View File

@ -235,6 +235,8 @@ their acceptable ranges, defaults, etc.
sipType = sipType_QgsProcessingParameterExtent;
else if ( sipCpp->type() == QgsProcessingParameterPoint::typeName() )
sipType = sipType_QgsProcessingParameterPoint;
else if ( sipCpp->type() == QgsProcessingParameterGeometry::typeName() )
sipType = sipType_QgsProcessingParameterGeometry;
else if ( sipCpp->type() == QgsProcessingParameterFile::typeName() )
sipType = sipType_QgsProcessingParameterFile;
else if ( sipCpp->type() == QgsProcessingParameterMatrix::typeName() )
@ -1170,6 +1172,20 @@ Returns the coordinate reference system associated with an point parameter value
.. seealso:: :py:func:`parameterAsPoint`
.. versionadded:: 3.8
%End
static QgsGeometry parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
%Docstring
Evaluates the parameter with matching ``definition`` to a geometry.
.. versionadded:: 3.16
%End
static QgsGeometry parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context );
%Docstring
Evaluates the parameter with matching ``definition`` and ``value`` to a geometry.
.. versionadded:: 3.16
%End
static QString parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
@ -1527,6 +1543,43 @@ Creates a new parameter using the definition from a script code.
};
class QgsProcessingParameterGeometry : QgsProcessingParameterDefinition
{
%Docstring
A geometry parameter for processing algorithms.
.. versionadded:: 3.16
%End
%TypeHeaderCode
#include "qgsprocessingparameters.h"
%End
public:
QgsProcessingParameterGeometry( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), bool optional = false );
%Docstring
Constructor for QgsProcessingParameterGeometry.
%End
static QString typeName();
%Docstring
Returns the type name for the parameter class.
%End
virtual QgsProcessingParameterDefinition *clone() const /Factory/;
virtual QString type() const;
virtual bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = 0 ) const;
virtual QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const;
static QgsProcessingParameterGeometry *fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) /Factory/;
%Docstring
Creates a new parameter using the definition from a script code.
%End
};
class QgsProcessingParameterFile : QgsProcessingParameterDefinition
{
%Docstring

View File

@ -42,6 +42,7 @@ from qgis.core import (QgsRasterLayer,
QgsProcessingParameterCrs,
QgsProcessingParameterRange,
QgsProcessingParameterPoint,
QgsProcessingParameterGeometry,
QgsProcessingParameterEnum,
QgsProcessingParameterExtent,
QgsProcessingParameterExpression,
@ -74,6 +75,7 @@ PARAMETER_TABLE_FIELD = 'field'
PARAMETER_EXTENT = 'extent'
PARAMETER_FILE = 'file'
PARAMETER_POINT = 'point'
PARAMETER_GEOMETRY = 'geometry'
PARAMETER_CRS = 'crs'
PARAMETER_MULTIPLE = 'multilayer'
PARAMETER_BAND = 'band'
@ -129,6 +131,9 @@ def getParameterFromString(s, context=''):
elif clazz == QgsProcessingParameterPoint:
if len(params) > 3:
params[3] = True if params[3].lower() == 'true' else False
elif clazz == QgsProcessingParameterGeometry:
if len(params) > 3:
params[3] = True if params[3].lower() == 'true' else False
elif clazz == QgsProcessingParameterCrs:
if len(params) > 3:
params[3] = True if params[3].lower() == 'true' else False

View File

@ -50,6 +50,7 @@ from qgis.core import (QgsProcessingParameterDefinition,
QgsProcessingParameterMatrix,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterPoint,
QgsProcessingParameterGeometry,
QgsProcessingParameterRange,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterVectorLayer,
@ -326,6 +327,7 @@ class ProcessingAlgFactory():
FIELD = "FIELD",
MATRIX = "MATRIX",
POINT = "POINT",
GEOMETRY = "GEOMETRY",
RANGE = "RANGE",
AUTH_CFG = "AUTH_CFG"
SCALE = "SCALE"
@ -462,6 +464,7 @@ class ProcessingAlgFactory():
alg.MATRIX: QgsProcessingParameterMatrix
alg.MULTILAYER: QgsProcessingParameterMultipleLayers
alg.POINT: QgsProcessingParameterPoint
alg.GEOMETRY: QgsProcessingParameterGeometry
alg.RANGE: QgsProcessingParameterRange
alg.VECTOR_LAYER: QgsProcessingParameterVectorLayer
alg.AUTH_CFG: QgsProcessingParameterAuthConfig
@ -519,6 +522,7 @@ input_type_mapping = {
ProcessingAlgFactory.MATRIX: QgsProcessingParameterMatrix,
ProcessingAlgFactory.MULTILAYER: QgsProcessingParameterMultipleLayers,
ProcessingAlgFactory.POINT: QgsProcessingParameterPoint,
ProcessingAlgFactory.GEOMETRY: QgsProcessingParameterGeometry,
ProcessingAlgFactory.RANGE: QgsProcessingParameterRange,
ProcessingAlgFactory.VECTOR_LAYER: QgsProcessingParameterVectorLayer,
ProcessingAlgFactory.AUTH_CFG: QgsProcessingParameterAuthConfig,

View File

@ -851,6 +851,7 @@ QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> QgsProcessingMode
<< QgsProcessingParameterCrs::typeName()
<< QgsProcessingParameterRange::typeName()
<< QgsProcessingParameterPoint::typeName()
<< QgsProcessingParameterGeometry::typeName()
<< QgsProcessingParameterFile::typeName()
<< QgsProcessingParameterFolderDestination::typeName()
<< QgsProcessingParameterBand::typeName()

View File

@ -1417,6 +1417,34 @@ QgsCoordinateReferenceSystem QgsProcessingParameters::parameterAsPointCrs( const
return QgsCoordinateReferenceSystem();
}
QgsGeometry QgsProcessingParameters::parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
{
if ( !definition )
return QgsGeometry();
return parameterAsGeometry( definition, parameters.value( definition->name() ), context );
}
QgsGeometry QgsProcessingParameters::parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context )
{
if ( !definition )
return QgsGeometry();
QVariant val = value;
if ( val.canConvert< QgsGeometry >() )
{
return val.value<QgsGeometry>();
}
QString valueAsString = parameterAsString( definition, value, context );
if ( !valueAsString.isEmpty() )
{
return QgsGeometry::fromWkt( valueAsString );
}
return QgsGeometry();
}
QString QgsProcessingParameters::parameterAsFile( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context )
{
if ( !definition )
@ -2002,6 +2030,8 @@ QgsProcessingParameterDefinition *QgsProcessingParameters::parameterFromScriptCo
return QgsProcessingParameterExtent::fromScriptCode( name, description, isOptional, definition );
else if ( type == QStringLiteral( "point" ) )
return QgsProcessingParameterPoint::fromScriptCode( name, description, isOptional, definition );
else if ( type == QStringLiteral( "geometry" ) )
return QgsProcessingParameterGeometry::fromScriptCode( name, description, isOptional, definition );
else if ( type == QStringLiteral( "file" ) )
return QgsProcessingParameterFile::fromScriptCode( name, description, isOptional, definition, QgsProcessingParameterFile::File );
else if ( type == QStringLiteral( "folder" ) )
@ -2770,6 +2800,78 @@ QgsProcessingParameterPoint *QgsProcessingParameterPoint::fromScriptCode( const
return new QgsProcessingParameterPoint( name, description, definition, isOptional );
}
QgsProcessingParameterGeometry::QgsProcessingParameterGeometry( const QString &name, const QString &description,
const QVariant &defaultValue, bool optional )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
{
}
QgsProcessingParameterDefinition *QgsProcessingParameterGeometry::clone() const
{
return new QgsProcessingParameterGeometry( *this );
}
bool QgsProcessingParameterGeometry::checkValueIsAcceptable( const QVariant &input, QgsProcessingContext * ) const
{
if ( !input.isValid() )
return mFlags & FlagOptional;
if ( input.canConvert<QgsProperty>() )
{
return true;
}
if ( input.canConvert< QgsGeometry >() )
{
return true;
}
if ( input.type() == QVariant::String )
{
if ( input.toString().isEmpty() )
return mFlags & FlagOptional;
}
QgsGeometry g = QgsGeometry::fromWkt( input.toString() );
if ( ! g.isNull() )
{
return true;
}
else
{
QgsMessageLog::logMessage( QObject::tr( "Error creating geometry: \"%1\"" ).arg( g.lastError() ), QObject::tr( "Processing" ) );
return false;
}
}
QString QgsProcessingParameterGeometry::valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const
{
if ( !value.isValid() )
return QStringLiteral( "None" );
if ( value.canConvert<QgsProperty>() )
return QStringLiteral( "QgsProperty.fromExpression('%1')" ).arg( value.value< QgsProperty >().asExpression() );
if ( value.canConvert< QgsGeometry >() )
{
const QgsGeometry g = value.value<QgsGeometry>();
if ( !g.isNull() )
{
const QString wkt = g.asWkt();
return QStringLiteral( "QgsGeometry.fromWkt('%1')" ).arg( wkt );
}
}
return QgsProcessingParameterDefinition::valueAsPythonString( value, context );
}
QgsProcessingParameterGeometry *QgsProcessingParameterGeometry::fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition )
{
return new QgsProcessingParameterGeometry( name, description, definition, isOptional );
}
QgsProcessingParameterFile::QgsProcessingParameterFile( const QString &name, const QString &description, Behavior behavior, const QString &extension, const QVariant &defaultValue, bool optional, const QString &fileFilter )
: QgsProcessingParameterDefinition( name, description, defaultValue, optional )
, mBehavior( behavior )

View File

@ -342,6 +342,8 @@ class CORE_EXPORT QgsProcessingParameterDefinition
sipType = sipType_QgsProcessingParameterExtent;
else if ( sipCpp->type() == QgsProcessingParameterPoint::typeName() )
sipType = sipType_QgsProcessingParameterPoint;
else if ( sipCpp->type() == QgsProcessingParameterGeometry::typeName() )
sipType = sipType_QgsProcessingParameterGeometry;
else if ( sipCpp->type() == QgsProcessingParameterFile::typeName() )
sipType = sipType_QgsProcessingParameterFile;
else if ( sipCpp->type() == QgsProcessingParameterMatrix::typeName() )
@ -1247,6 +1249,20 @@ class CORE_EXPORT QgsProcessingParameters
*/
static QgsCoordinateReferenceSystem parameterAsPointCrs( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context );
/**
* Evaluates the parameter with matching \a definition to a geometry.
*
* \since QGIS 3.16
*/
static QgsGeometry parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariantMap &parameters, QgsProcessingContext &context );
/**
* Evaluates the parameter with matching \a definition and \a value to a geometry.
*
* \since QGIS 3.16
*/
static QgsGeometry parameterAsGeometry( const QgsProcessingParameterDefinition *definition, const QVariant &value, QgsProcessingContext &context );
/**
* Evaluates the parameter with matching \a definition to a file/folder name.
*/
@ -1568,6 +1584,37 @@ class CORE_EXPORT QgsProcessingParameterPoint : public QgsProcessingParameterDef
};
/**
* \class QgsProcessingParameterGeometry
* \ingroup core
* A geometry parameter for processing algorithms.
* \since QGIS 3.16
*/
class CORE_EXPORT QgsProcessingParameterGeometry : public QgsProcessingParameterDefinition
{
public:
/**
* Constructor for QgsProcessingParameterGeometry.
*/
QgsProcessingParameterGeometry( const QString &name, const QString &description = QString(), const QVariant &defaultValue = QVariant(), bool optional = false );
/**
* Returns the type name for the parameter class.
*/
static QString typeName() { return QStringLiteral( "geometry" ); }
QgsProcessingParameterDefinition *clone() const override SIP_FACTORY;
QString type() const override { return typeName(); }
bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override;
QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override;
/**
* Creates a new parameter using the definition from a script code.
*/
static QgsProcessingParameterGeometry *fromScriptCode( const QString &name, const QString &description, bool isOptional, const QString &definition ) SIP_FACTORY;
};
/**
* \class QgsProcessingParameterFile
* \ingroup core

View File

@ -518,6 +518,58 @@ class CORE_EXPORT QgsProcessingParameterTypePoint : public QgsProcessingParamete
}
};
/**
* A geometry parameter for processing algorithms.
*
* \ingroup core
* \note No Python bindings available. Get your copy from QgsApplication.processingRegistry().parameterType('geometry')
* \since QGIS 3.16
*/
class CORE_EXPORT QgsProcessingParameterTypeGeometry : public QgsProcessingParameterType
{
QgsProcessingParameterDefinition *create( const QString &name ) const override SIP_FACTORY
{
return new QgsProcessingParameterGeometry( name );
}
QString description() const override
{
return QCoreApplication::translate( "Processing", "A geometry parameter." );
}
QString name() const override
{
return QCoreApplication::translate( "Processing", "Geometry" );
}
QString id() const override
{
return QStringLiteral( "geometry" );
}
QString pythonImportString() const override
{
return QStringLiteral( "from qgis.core import QgsProcessingParameterGeometry" );
}
QString className() const override
{
return QStringLiteral( "QgsProcessingParameterGeometry" );
}
QStringList acceptedPythonTypes() const override
{
return QStringList() << QObject::tr( "str: as Well-Known Text string (WKT)" )
<< QStringLiteral( "QgsGeometry" )
<< QStringLiteral( "QgsProperty" );
}
QStringList acceptedStringValues() const override
{
return QStringList() << QObject::tr( "Well-Known Text string (WKT)" );
}
};
/**
* An enum based parameter for processing algorithms, allowing for selection from predefined values.
*

View File

@ -35,6 +35,7 @@ QgsProcessingRegistry::QgsProcessingRegistry( QObject *parent SIP_TRANSFERTHIS )
addParameterType( new QgsProcessingParameterTypeCrs() );
addParameterType( new QgsProcessingParameterTypeRange() );
addParameterType( new QgsProcessingParameterTypePoint() );
addParameterType( new QgsProcessingParameterTypeGeometry() );
addParameterType( new QgsProcessingParameterTypeEnum() );
addParameterType( new QgsProcessingParameterTypeExtent() );
addParameterType( new QgsProcessingParameterTypeMatrix() );

View File

@ -47,6 +47,7 @@ QgsProcessingGuiRegistry::QgsProcessingGuiRegistry()
addParameterWidgetFactory( new QgsProcessingLayoutWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingLayoutItemWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingPointWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingGeometryWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingColorWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingCoordinateOperationWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingFieldWidgetWrapper() );

View File

@ -3161,6 +3161,117 @@ QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingPointWidgetWrapper:
}
//
// QgsProcessingGeometryWidgetWrapper
//
QgsProcessingGeometryParameterDefinitionWidget::QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm, QWidget *parent )
: QgsProcessingAbstractParameterDefinitionWidget( context, widgetContext, definition, algorithm, parent )
{
QVBoxLayout *vlayout = new QVBoxLayout();
vlayout->setMargin( 0 );
vlayout->setContentsMargins( 0, 0, 0, 0 );
vlayout->addWidget( new QLabel( tr( "Default value" ) ) );
mDefaultLineEdit = new QLineEdit();
mDefaultLineEdit->setToolTip( tr( "Geometry as WKT" ) );
mDefaultLineEdit->setPlaceholderText( tr( "Geometry as WKT" ) );
if ( const QgsProcessingParameterGeometry *geometryParam = dynamic_cast<const QgsProcessingParameterGeometry *>( definition ) )
{
QgsGeometry g = QgsProcessingParameters::parameterAsGeometry( geometryParam, geometryParam->defaultValue(), context );
if ( !g.isNull() )
mDefaultLineEdit->setText( g.asWkt() );
}
vlayout->addWidget( mDefaultLineEdit );
setLayout( vlayout );
}
QgsProcessingParameterDefinition *QgsProcessingGeometryParameterDefinitionWidget::createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const
{
auto param = qgis::make_unique< QgsProcessingParameterGeometry >( name, description, mDefaultLineEdit->text() );
param->setFlags( flags );
return param.release();
}
QgsProcessingGeometryWidgetWrapper::QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
: QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
{
}
QWidget *QgsProcessingGeometryWidgetWrapper::createWidget()
{
switch ( type() )
{
case QgsProcessingGui::Standard:
case QgsProcessingGui::Modeler:
case QgsProcessingGui::Batch:
{
mLineEdit = new QLineEdit();
mLineEdit->setToolTip( parameterDefinition()->toolTip() );
connect( mLineEdit, &QLineEdit::textChanged, this, [ = ]
{
emit widgetValueHasChanged( this );
} );
return mLineEdit;
}
}
return nullptr;
}
void QgsProcessingGeometryWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
{
if ( mLineEdit )
{
QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );
mLineEdit->setText( v );
}
}
QVariant QgsProcessingGeometryWidgetWrapper::widgetValue() const
{
if ( mLineEdit )
return mLineEdit->text().isEmpty() ? QVariant() : mLineEdit->text();
else
return QVariant();
}
QStringList QgsProcessingGeometryWidgetWrapper::compatibleParameterTypes() const
{
return QStringList()
<< QgsProcessingParameterGeometry::typeName()
<< QgsProcessingParameterString::typeName();
}
QStringList QgsProcessingGeometryWidgetWrapper::compatibleOutputTypes() const
{
return QStringList()
<< QgsProcessingOutputString::typeName();
}
QString QgsProcessingGeometryWidgetWrapper::modelerExpressionFormatString() const
{
return tr( "string in the Well-Known-Text format or a geometry value" );
}
QString QgsProcessingGeometryWidgetWrapper::parameterType() const
{
return QgsProcessingParameterGeometry::typeName();
}
QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingGeometryWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
{
return new QgsProcessingGeometryWidgetWrapper( parameter, type );
}
QgsProcessingAbstractParameterDefinitionWidget *QgsProcessingGeometryWidgetWrapper::createParameterDefinitionWidget( QgsProcessingContext &context, const QgsProcessingParameterWidgetContext &widgetContext, const QgsProcessingParameterDefinition *definition, const QgsProcessingAlgorithm *algorithm )
{
return new QgsProcessingGeometryParameterDefinitionWidget( context, widgetContext, definition, algorithm );
}
//
// QgsProcessingColorWidgetWrapper

View File

@ -1022,8 +1022,59 @@ class GUI_EXPORT QgsProcessingPointWidgetWrapper : public QgsAbstractProcessingP
friend class TestProcessingGui;
};
class GUI_EXPORT QgsProcessingGeometryParameterDefinitionWidget : public QgsProcessingAbstractParameterDefinitionWidget
{
Q_OBJECT
public:
QgsProcessingGeometryParameterDefinitionWidget( QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr, QWidget *parent SIP_TRANSFERTHIS = nullptr );
QgsProcessingParameterDefinition *createParameter( const QString &name, const QString &description, QgsProcessingParameterDefinition::Flags flags ) const override;
private:
QLineEdit *mDefaultLineEdit = nullptr;
};
class GUI_EXPORT QgsProcessingGeometryWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper, public QgsProcessingParameterWidgetFactoryInterface
{
Q_OBJECT
public:
QgsProcessingGeometryWidgetWrapper( const QgsProcessingParameterDefinition *parameter = nullptr,
QgsProcessingGui::WidgetType type = QgsProcessingGui::Standard, QWidget *parent = nullptr );
// QgsProcessingParameterWidgetFactoryInterface
QString parameterType() const override;
QgsAbstractProcessingParameterWidgetWrapper *createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type ) override;
QgsProcessingAbstractParameterDefinitionWidget *createParameterDefinitionWidget(
QgsProcessingContext &context,
const QgsProcessingParameterWidgetContext &widgetContext,
const QgsProcessingParameterDefinition *definition = nullptr,
const QgsProcessingAlgorithm *algorithm = nullptr ) override;
// QgsProcessingParameterWidgetWrapper interface
QWidget *createWidget() override SIP_FACTORY;
protected:
void setWidgetValue( const QVariant &value, QgsProcessingContext &context ) override;
QVariant widgetValue() const override;
QStringList compatibleParameterTypes() const override;
QStringList compatibleOutputTypes() const override;
QString modelerExpressionFormatString() const override;
private:
QLineEdit *mLineEdit = nullptr;
friend class TestProcessingGui;
};
class GUI_EXPORT QgsProcessingExtentParameterDefinitionWidget : public QgsProcessingAbstractParameterDefinitionWidget
{

View File

@ -568,6 +568,7 @@ class TestQgsProcessing: public QObject
void parameterMapLayer();
void parameterExtent();
void parameterPoint();
void parameterGeometry();
void parameterFile();
void parameterMatrix();
void parameterLayerList();
@ -3379,6 +3380,87 @@ void TestQgsProcessing::parameterPoint()
QCOMPARE( fromCode->defaultValue(), def->defaultValue() );
}
void TestQgsProcessing::parameterGeometry()
{
QgsProcessingContext context;
// not optional!
std::unique_ptr< QgsProcessingParameterGeometry > def( new QgsProcessingParameterGeometry( "non_optional", QString(), QString( "Point(1 2)" ), false ) );
QVERIFY( !def->checkValueIsAcceptable( false ) );
QVERIFY( !def->checkValueIsAcceptable( true ) );
QVERIFY( !def->checkValueIsAcceptable( 5 ) );
QVERIFY( !def->checkValueIsAcceptable( "Nonsense string" ) );
QVERIFY( !def->checkValueIsAcceptable( "" ) );
QVERIFY( !def->checkValueIsAcceptable( QVariant() ) );
QVERIFY( !def->checkValueIsAcceptable( QString( "LineString(10 10, 20 a)" ) ) );
QVERIFY( def->checkValueIsAcceptable( QString( "LineString(10 10, 20 20)" ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromPointXY( QgsPointXY( 1, 2 ) ) ) );
QVERIFY( def->checkValueIsAcceptable( QgsGeometry::fromWkt( QStringLiteral( "LineString(10 10, 20 20)" ) ) ) );
// string representing a geometry
QVariantMap params;
params.insert( "non_optional", QString( "LineString(10 10, 20 20)" ) );
QVERIFY( def->checkValueIsAcceptable( "LineString(10 10, 20 20)" ) );
QgsGeometry geometry = QgsProcessingParameters::parameterAsGeometry( def.get(), params, context );
QCOMPARE( geometry.asWkt(), QStringLiteral( "LineString (10 10, 20 20)" ) );
// nonsense string
params.insert( "non_optional", QString( "i'm not a geometry, and nothing you can do will make me one" ) );
geometry = QgsProcessingParameters::parameterAsGeometry( def.get(), params, context );
QVERIFY( geometry.isNull() );
QCOMPARE( def->valueAsPythonString( QVariant(), context ), QStringLiteral( "None" ) );
QCOMPARE( def->valueAsPythonString( "LineString( 10 10, 20 20)", context ), QStringLiteral( "'LineString( 10 10, 20 20)'" ) );
QCOMPARE( def->valueAsPythonString( QgsGeometry::fromWkt( QStringLiteral( "LineString( 10 10, 20 20)" ) ), context ), QStringLiteral( "QgsGeometry.fromWkt('LineString (10 10, 20 20)')" ) );
QString pythonCode = def->asPythonString();
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterGeometry('non_optional', '', defaultValue='Point(1 2)')" ) );
QString code = def->asScriptCode();
QCOMPARE( code, QStringLiteral( "##non_optional=geometry Point(1 2)" ) );
std::unique_ptr< QgsProcessingParameterGeometry > fromCode( dynamic_cast< QgsProcessingParameterGeometry * >( QgsProcessingParameters::parameterFromScriptCode( code ) ) );
QVERIFY( fromCode.get() );
QCOMPARE( fromCode->name(), def->name() );
QCOMPARE( fromCode->description(), QStringLiteral( "non optional" ) );
QCOMPARE( fromCode->flags(), def->flags() );
QCOMPARE( fromCode->defaultValue(), def->defaultValue() );
QVariantMap map = def->toVariantMap();
QgsProcessingParameterGeometry fromMap( "x" );
QVERIFY( fromMap.fromVariantMap( map ) );
QCOMPARE( fromMap.name(), def->name() );
QCOMPARE( fromMap.description(), def->description() );
QCOMPARE( fromMap.flags(), def->flags() );
QCOMPARE( fromMap.defaultValue(), def->defaultValue() );
def.reset( dynamic_cast< QgsProcessingParameterGeometry *>( QgsProcessingParameters::parameterFromVariantMap( map ) ) );
QVERIFY( dynamic_cast< QgsProcessingParameterGeometry *>( def.get() ) );
// optional
def.reset( new QgsProcessingParameterGeometry( "optional", QString(), QString( "Point(-1 3)" ), true ) );
QVERIFY( def->checkValueIsAcceptable( "LineString(10 10, 20 20)" ) );
QVERIFY( !def->checkValueIsAcceptable( "Point(-1 a)" ) );
QVERIFY( def->checkValueIsAcceptable( "" ) );
QVERIFY( def->checkValueIsAcceptable( QVariant() ) );
params.insert( "optional", QVariant() );
geometry = QgsProcessingParameters::parameterAsGeometry( def.get(), params, context );
QCOMPARE( geometry.asWkt(), QStringLiteral( "Point (-1 3)" ) );
pythonCode = def->asPythonString();
QCOMPARE( pythonCode, QStringLiteral( "QgsProcessingParameterGeometry('optional', '', optional=True, defaultValue='Point(-1 3)')" ) );
code = def->asScriptCode();
QCOMPARE( code, QStringLiteral( "##optional=optional geometry Point(-1 3)" ) );
fromCode.reset( dynamic_cast< QgsProcessingParameterGeometry * >( QgsProcessingParameters::parameterFromScriptCode( code ) ) );
QVERIFY( fromCode.get() );
QCOMPARE( fromCode->name(), def->name() );
QCOMPARE( fromCode->description(), QStringLiteral( "optional" ) );
QCOMPARE( fromCode->flags(), def->flags() );
QCOMPARE( fromCode->defaultValue(), def->defaultValue() );
}
void TestQgsProcessing::parameterFile()
{
QgsProcessingContext context;

View File

@ -219,6 +219,7 @@ class TestProcessingGui : public QObject
void testLayoutItemWrapper();
void testPointPanel();
void testPointWrapper();
void testGeometryWrapper();
void testExtentWrapper();
void testColorWrapper();
void testCoordinateOperationWrapper();
@ -4510,6 +4511,7 @@ void TestProcessingGui::testPointPanel()
panel.reset();
}
void TestProcessingGui::testPointWrapper()
{
auto testWrapper = []( QgsProcessingGui::WidgetType type )
@ -4688,6 +4690,132 @@ void TestProcessingGui::testPointWrapper()
}
void TestProcessingGui::testGeometryWrapper()
{
auto testWrapper = []( QgsProcessingGui::WidgetType type )
{
// non optional
QgsProcessingParameterGeometry param( QStringLiteral( "geometry" ), QStringLiteral( "geometry" ), false );
QgsProcessingGeometryWidgetWrapper wrapper( &param, type );
QgsProcessingContext context;
QWidget *w = wrapper.createWrappedWidget( context );
QSignalSpy spy( &wrapper, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
wrapper.setWidgetValue( QStringLiteral( "POINT (1 2)" ), context );
QCOMPARE( spy.count(), 1 );
QCOMPARE( wrapper.widgetValue().toString().toLower(), QStringLiteral( "point (1 2)" ) );
QCOMPARE( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text().toLower(), QStringLiteral( "point (1 2)" ).toLower() );
wrapper.setWidgetValue( QString(), context );
QCOMPARE( spy.count(), 2 );
QVERIFY( wrapper.widgetValue().toString().isEmpty() );
QVERIFY( static_cast< QLineEdit * >( wrapper.wrappedWidget() )->text().isEmpty() );
QLabel *l = wrapper.createWrappedLabel();
if ( wrapper.type() != QgsProcessingGui::Batch )
{
QVERIFY( l );
QCOMPARE( l->text(), QStringLiteral( "geometry" ) );
QCOMPARE( l->toolTip(), param.toolTip() );
delete l;
}
else
{
QVERIFY( !l );
}
// check signal
static_cast< QLineEdit * >( wrapper.wrappedWidget() )->setText( QStringLiteral( "b" ) );
QCOMPARE( spy.count(), 3 );
static_cast< QLineEdit * >( wrapper.wrappedWidget() )->clear();
QCOMPARE( spy.count(), 4 );
delete w;
// optional
QgsProcessingParameterGeometry param2( QStringLiteral( "geometry" ), QStringLiteral( "geometry" ), QVariant(), true );
QgsProcessingGeometryWidgetWrapper wrapper2( &param2, type );
w = wrapper2.createWrappedWidget( context );
QSignalSpy spy2( &wrapper2, &QgsProcessingLayoutItemWidgetWrapper::widgetValueHasChanged );
wrapper2.setWidgetValue( "POINT (1 2)", context );
QCOMPARE( spy2.count(), 1 );
QCOMPARE( wrapper2.widgetValue().toString().toLower(), QStringLiteral( "point (1 2)" ) );
QCOMPARE( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().toLower(), QStringLiteral( "point (1 2)" ) );
wrapper2.setWidgetValue( QVariant(), context );
QCOMPARE( spy2.count(), 2 );
QVERIFY( !wrapper2.widgetValue().isValid() );
QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
wrapper2.setWidgetValue( "POINT (1 3)", context );
QCOMPARE( spy2.count(), 3 );
wrapper2.setWidgetValue( "", context );
QCOMPARE( spy2.count(), 4 );
QVERIFY( !wrapper2.widgetValue().isValid() );
QVERIFY( static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->text().isEmpty() );
// check signals
wrapper2.setWidgetValue( "1,3", context );
QCOMPARE( spy2.count(), 5 );
static_cast< QLineEdit * >( wrapper2.wrappedWidget() )->clear();
QCOMPARE( spy2.count(), 6 );
delete w;
};
// standard wrapper
testWrapper( QgsProcessingGui::Standard );
// batch wrapper
testWrapper( QgsProcessingGui::Batch );
// modeler wrapper
testWrapper( QgsProcessingGui::Modeler );
// config widget
QgsProcessingContext context;
QgsProcessingParameterWidgetContext widgetContext;
std::unique_ptr< QgsProcessingParameterDefinitionWidget > widget = qgis::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "geometry" ), context, widgetContext );
std::unique_ptr< QgsProcessingParameterDefinition > def( widget->createParameter( QStringLiteral( "param_name" ) ) );
QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) ); // should default to mandatory
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
// using a parameter definition as initial values
QgsProcessingParameterGeometry geometryParam( QStringLiteral( "n" ), QStringLiteral( "test desc" ), QStringLiteral( "POINT (1 2)" ) );
widget = qgis::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "geometry" ), context, widgetContext, &geometryParam );
def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagOptional ) );
QVERIFY( !( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced ) );
QCOMPARE( static_cast< QgsProcessingParameterGeometry * >( def.get() )->defaultValue().toString().toLower(), QStringLiteral( "point (1 2)" ) );
geometryParam.setFlags( QgsProcessingParameterDefinition::FlagAdvanced | QgsProcessingParameterDefinition::FlagOptional );
geometryParam.setDefaultValue( QStringLiteral( "POINT (4 7)" ) );
widget = qgis::make_unique< QgsProcessingParameterDefinitionWidget >( QStringLiteral( "geometry" ), context, widgetContext, &geometryParam );
def.reset( widget->createParameter( QStringLiteral( "param_name" ) ) );
QCOMPARE( def->name(), QStringLiteral( "param_name" ) );
QCOMPARE( def->description(), QStringLiteral( "test desc" ) );
QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagOptional );
QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
QCOMPARE( static_cast< QgsProcessingParameterGeometry * >( def.get() )->defaultValue().toString().toLower(), QStringLiteral( "point (4 7)" ) );
}
void TestProcessingGui::testExtentWrapper()
{
auto testWrapper = []( QgsProcessingGui::WidgetType type )