Skip to content

Commit

Permalink
Add widget wrapper for processing map theme parameter type
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 5, 2020
1 parent 54629b8 commit 35e7fc7
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/gui/processing/qgsprocessingguiregistry.cpp
Expand Up @@ -45,6 +45,7 @@ QgsProcessingGuiRegistry::QgsProcessingGuiRegistry()
addParameterWidgetFactory( new QgsProcessingColorWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingCoordinateOperationWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingFieldWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingMapThemeWidgetWrapper() );
}

QgsProcessingGuiRegistry::~QgsProcessingGuiRegistry()
Expand Down
110 changes: 110 additions & 0 deletions src/gui/processing/qgsprocessingwidgetwrapperimpl.cpp
Expand Up @@ -46,6 +46,7 @@
#include "qgscoordinateoperationwidget.h"
#include "qgsdatumtransformdialog.h"
#include "qgsfieldcombobox.h"
#include "qgsmapthemecollection.h"
#include <QToolButton>
#include <QLabel>
#include <QHBoxLayout>
Expand Down Expand Up @@ -3494,4 +3495,113 @@ QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingFieldWidgetWrapper::cr
return new QgsProcessingFieldWidgetWrapper( parameter, type );
}

//
// QgsProcessingMapThemeWidgetWrapper
//

QgsProcessingMapThemeWidgetWrapper::QgsProcessingMapThemeWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
: QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
{

}

QWidget *QgsProcessingMapThemeWidgetWrapper::createWidget()
{
const QgsProcessingParameterMapTheme *themeParam = dynamic_cast< const QgsProcessingParameterMapTheme *>( parameterDefinition() );

mComboBox = new QComboBox();

if ( themeParam->flags() & QgsProcessingParameterDefinition::FlagOptional )
mComboBox->addItem( tr( "[Not selected]" ), QVariant( -1 ) );

const QStringList mapThemes = widgetContext().project() ? widgetContext().project()->mapThemeCollection()->mapThemes() : QgsProject::instance()->mapThemeCollection()->mapThemes();
for ( const QString &theme : mapThemes )
{
mComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowAllLayers.svg" ) ), theme, theme );
}

switch ( type() )
{
case QgsProcessingGui::Standard:
case QgsProcessingGui::Batch:
break;

case QgsProcessingGui::Modeler:
mComboBox->setEditable( true );
break;
}

mComboBox->setToolTip( parameterDefinition()->toolTip() );
connect( mComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]( int )
{
emit widgetValueHasChanged( this );
} );

return mComboBox;
}

void QgsProcessingMapThemeWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
{
const QString v = QgsProcessingParameters::parameterAsString( parameterDefinition(), value, context );

if ( !value.isValid() )
mComboBox->setCurrentIndex( mComboBox->findData( QVariant( -1 ) ) );
else
{
if ( mComboBox->isEditable() && mComboBox->findData( v ) == -1 )
{
const QString prev = mComboBox->currentText();
mComboBox->setCurrentText( v );
if ( prev != v )
emit widgetValueHasChanged( this );
}
else
mComboBox->setCurrentIndex( mComboBox->findData( v ) );
}
}

QVariant QgsProcessingMapThemeWidgetWrapper::widgetValue() const
{
if ( mComboBox )
return mComboBox->currentData().toInt() == -1 ? QVariant() :
!mComboBox->currentData().isValid() && mComboBox->isEditable() ? mComboBox->currentText().isEmpty() ? QVariant() : QVariant( mComboBox->currentText() )
: mComboBox->currentData();
else
return QVariant();
}

QStringList QgsProcessingMapThemeWidgetWrapper::compatibleParameterTypes() const
{
return QStringList()
<< QgsProcessingParameterString::typeName()
<< QgsProcessingParameterExpression::typeName();
}

QStringList QgsProcessingMapThemeWidgetWrapper::compatibleOutputTypes() const
{
return QStringList()
<< QgsProcessingOutputString::typeName();
}

QList<int> QgsProcessingMapThemeWidgetWrapper::compatibleDataTypes() const
{
return QList< int >();
}

QString QgsProcessingMapThemeWidgetWrapper::modelerExpressionFormatString() const
{
return tr( "map theme as a string value (e.g. 'base maps')" );
}

QString QgsProcessingMapThemeWidgetWrapper::parameterType() const
{
return QgsProcessingParameterMapTheme::typeName();
}

QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingMapThemeWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
{
return new QgsProcessingMapThemeWidgetWrapper( parameter, type );
}


///@endcond PRIVATE
36 changes: 36 additions & 0 deletions src/gui/processing/qgsprocessingwidgetwrapperimpl.h
Expand Up @@ -1032,6 +1032,42 @@ class GUI_EXPORT QgsProcessingFieldWidgetWrapper : public QgsAbstractProcessingP
};



class GUI_EXPORT QgsProcessingMapThemeWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper, public QgsProcessingParameterWidgetFactoryInterface
{
Q_OBJECT

public:

QgsProcessingMapThemeWidgetWrapper( 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;

// 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;

QList< int > compatibleDataTypes() const override;
QString modelerExpressionFormatString() const override;

private:

QComboBox *mComboBox = nullptr;

friend class TestProcessingGui;
};

///@endcond PRIVATE

#endif // QGSPROCESSINGWIDGETWRAPPERIMPL_H
120 changes: 120 additions & 0 deletions tests/src/gui/testprocessinggui.cpp
Expand Up @@ -66,6 +66,7 @@
#include "qgscoordinateoperationwidget.h"
#include "qgsmessagebar.h"
#include "qgsfieldcombobox.h"
#include "qgsmapthemecollection.h"

class TestParamType : public QgsProcessingParameterDefinition
{
Expand Down Expand Up @@ -195,6 +196,7 @@ class TestProcessingGui : public QObject
void testCoordinateOperationWrapper();
void mapLayerComboBox();
void paramConfigWidget();
void testMapThemeWrapper();

private:

Expand Down Expand Up @@ -4254,6 +4256,124 @@ void TestProcessingGui::paramConfigWidget()
QVERIFY( def->flags() & QgsProcessingParameterDefinition::FlagAdvanced );
}

void TestProcessingGui::testMapThemeWrapper()
{
// add some themes to the project
QgsProject p;
p.mapThemeCollection()->insert( QStringLiteral( "aa" ), QgsMapThemeCollection::MapThemeRecord() );
p.mapThemeCollection()->insert( QStringLiteral( "bb" ), QgsMapThemeCollection::MapThemeRecord() );

QCOMPARE( p.mapThemeCollection()->mapThemes(), QStringList() << QStringLiteral( "aa" ) << QStringLiteral( "bb" ) );

auto testWrapper = [&p]( QgsProcessingGui::WidgetType type )
{
// non optional, no existing themes
QgsProcessingParameterMapTheme param( QStringLiteral( "theme" ), QStringLiteral( "theme" ), false );

QgsProcessingMapThemeWidgetWrapper wrapper( &param, type );

QgsProcessingContext context;
QWidget *w = wrapper.createWrappedWidget( context );

QSignalSpy spy( &wrapper, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
wrapper.setWidgetValue( QStringLiteral( "bb" ), context );

switch ( type )
{
case QgsProcessingGui::Standard:
case QgsProcessingGui::Batch:
// batch or standard mode, only valid themes can be set!
QCOMPARE( spy.count(), 0 );
QVERIFY( !wrapper.widgetValue().isValid() );
QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), -1 );
wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
QCOMPARE( spy.count(), 0 );
QVERIFY( !wrapper.widgetValue().isValid() );
QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentIndex(), -1 );
break;

case QgsProcessingGui::Modeler:
QCOMPARE( spy.count(), 1 );
QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "bb" ) );
QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
wrapper.setWidgetValue( QStringLiteral( "aa" ), context );
QCOMPARE( spy.count(), 2 );
QCOMPARE( wrapper.widgetValue().toString(), QStringLiteral( "aa" ) );
QCOMPARE( static_cast< QComboBox * >( wrapper.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
break;
}

delete w;

// with project
QgsProcessingParameterWidgetContext widgetContext;
widgetContext.setProject( &p );

QgsProcessingMapThemeWidgetWrapper wrapper2( &param, type );
wrapper2.setWidgetContext( widgetContext );
w = wrapper2.createWrappedWidget( context );

QSignalSpy spy2( &wrapper2, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
wrapper2.setWidgetValue( QStringLiteral( "bb" ), context );
QCOMPARE( spy2.count(), 1 );
QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "bb" ) );
QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
wrapper2.setWidgetValue( QStringLiteral( "aa" ), context );
QCOMPARE( spy2.count(), 2 );
QCOMPARE( wrapper2.widgetValue().toString(), QStringLiteral( "aa" ) );
QCOMPARE( static_cast< QComboBox * >( wrapper2.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );

// check signal
static_cast< QComboBox * >( wrapper2.wrappedWidget() )->setCurrentIndex( 2 );
QCOMPARE( spy2.count(), 3 );

delete w;

// optional
QgsProcessingParameterMapTheme param2( QStringLiteral( "theme" ), QStringLiteral( "theme" ), true );
QgsProcessingMapThemeWidgetWrapper wrapper3( &param2, type );
wrapper3.setWidgetContext( widgetContext );
w = wrapper3.createWrappedWidget( context );

QSignalSpy spy3( &wrapper3, &QgsProcessingEnumWidgetWrapper::widgetValueHasChanged );
wrapper3.setWidgetValue( QStringLiteral( "bb" ), context );
QCOMPARE( spy3.count(), 1 );
QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "bb" ) );
QCOMPARE( static_cast< QComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "bb" ) );
wrapper3.setWidgetValue( QStringLiteral( "aa" ), context );
QCOMPARE( spy3.count(), 2 );
QCOMPARE( wrapper3.widgetValue().toString(), QStringLiteral( "aa" ) );
QCOMPARE( static_cast< QComboBox * >( wrapper3.wrappedWidget() )->currentText(), QStringLiteral( "aa" ) );
wrapper3.setWidgetValue( QVariant(), context );
QCOMPARE( spy3.count(), 3 );
QVERIFY( !wrapper3.widgetValue().isValid() );
delete w;


QLabel *l = wrapper.createWrappedLabel();
if ( wrapper.type() != QgsProcessingGui::Batch )
{
QVERIFY( l );
QCOMPARE( l->text(), QStringLiteral( "theme" ) );
QCOMPARE( l->toolTip(), param.toolTip() );
delete l;
}
else
{
QVERIFY( !l );
}
};

// standard wrapper
testWrapper( QgsProcessingGui::Standard );

// batch wrapper
testWrapper( QgsProcessingGui::Batch );

// modeler wrapper
testWrapper( QgsProcessingGui::Modeler );
}

void TestProcessingGui::cleanupTempDir()
{
QDir tmpDir = QDir( mTempDir );
Expand Down

0 comments on commit 35e7fc7

Please sign in to comment.