Skip to content

Commit

Permalink
Add basic shell for widget
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Feb 14, 2017
1 parent edb30a2 commit f70a031
Show file tree
Hide file tree
Showing 9 changed files with 722 additions and 16 deletions.
1 change: 1 addition & 0 deletions python/gui/gui.sip
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
%Include qgsprevieweffect.sip
%Include qgsprojectionselectionwidget.sip
%Include qgsprojectionselector.sip
%Include qgspropertyassistantwidget.sip
%Include qgspropertyoverridebutton.sip
%Include qgsquerybuilder.sip
%Include qgsrasterformatsaveoptionswidget.sip
Expand Down
12 changes: 12 additions & 0 deletions python/gui/qgspropertyassistantwidget.sip
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class QgsPropertyAssistantWidget : public QgsPanelWidget
{
%TypeHeaderCode
#include <qgspropertyassistantwidget.h>
%End

public:

QgsPropertyAssistantWidget( QWidget* parent /TransferThis/ = nullptr );

};

2 changes: 2 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ SET(QGIS_GUI_SRCS
qgsprevieweffect.cpp
qgsprojectionselectionwidget.cpp
qgsprojectionselector.cpp
qgspropertyassistantwidget.cpp
qgspropertyoverridebutton.cpp
qgsquerybuilder.cpp
qgsrasterformatsaveoptionswidget.cpp
Expand Down Expand Up @@ -436,6 +437,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsprevieweffect.h
qgsprojectionselectionwidget.h
qgsprojectionselector.h
qgspropertyassistantwidget.h
qgspropertyoverridebutton.h
qgsquerybuilder.h
qgsrasterformatsaveoptionswidget.h
Expand Down
250 changes: 250 additions & 0 deletions src/gui/qgspropertyassistantwidget.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/***************************************************************************
qgspropertyassistantwidget.cpp
------------------------------
begin : February, 2017
copyright : (C) 2017 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 "qgspropertyassistantwidget.h"
#include "qgsproject.h"
#include "qgsmapsettings.h"
#include "qgsvectorlayer.h"

QgsPropertyAssistantWidget::QgsPropertyAssistantWidget( QWidget* parent ,
const QgsPropertyDefinition& definition, const QgsProperty& initialState,
const QgsVectorLayer* layer )
: QgsPanelWidget( parent )
, mDefinition( definition )
, mLayer( layer )
{
setupUi( this );

layout()->setContentsMargins( 0, 0, 0, 0 );
layout()->setMargin( 0 );

setPanelTitle( mDefinition.description() );

mLegendPreview->hide();

minValueSpinBox->setShowClearButton( false );
maxValueSpinBox->setShowClearButton( false );

// TODO expression widget shouldn't require a non-const layer
mExpressionWidget->setLayer( const_cast< QgsVectorLayer* >( mLayer ) );
mExpressionWidget->setFilters( QgsFieldProxyModel::Numeric );
mExpressionWidget->setField( initialState.propertyType() == QgsProperty::ExpressionBasedProperty ? initialState.expressionString() : initialState.field() );

if ( initialState.transformer() )
{
minValueSpinBox->setValue( initialState.transformer()->minValue() );
maxValueSpinBox->setValue( initialState.transformer()->maxValue() );
}

connect( computeValuesButton, &QPushButton::clicked, this, &QgsPropertyAssistantWidget::computeValuesFromLayer );

switch ( definition.standardTemplate() )
{
case QgsPropertyDefinition::Size:
{
mTransformerWidget = new QgsPropertySizeAssistantWidget( this, mDefinition, initialState );
}
default:
break;
}

if ( mTransformerWidget )
{
mOutputWidget->layout()->addWidget( mTransformerWidget );
connect( mTransformerWidget, &QgsPropertyAbstractTransformerWidget::widgetChanged, this, &QgsPropertyAssistantWidget::widgetChanged );
}

connect( minValueSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
connect( maxValueSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
connect( mExpressionWidget, static_cast < void ( QgsFieldExpressionWidget::* )( const QString& ) > ( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsPropertyAssistantWidget::widgetChanged );
}

void QgsPropertyAssistantWidget::registerExpressionContextGenerator( QgsExpressionContextGenerator* generator )
{
mExpressionContextGenerator = generator;
mExpressionWidget->registerExpressionContextGenerator( generator );
}

void QgsPropertyAssistantWidget::updateProperty( QgsProperty& property )
{
property.setActive( true );
if ( mExpressionWidget->isExpression() )
property.setExpressionString( mExpressionWidget->currentField() );
else
property.setField( mExpressionWidget->currentField() );

if ( mTransformerWidget )
property.setTransformer( mTransformerWidget->createTransformer( minValueSpinBox->value(), maxValueSpinBox->value() ) );
}

void QgsPropertyAssistantWidget::computeValuesFromLayer()
{
if ( !mLayer )
return;

double minValue = 0.0;
double maxValue = 0.0;

if ( mExpressionWidget->isExpression() )
{
if ( !computeValuesFromExpression( mExpressionWidget->currentField(), minValue, maxValue ) )
return;
}
else
{
if ( !computeValuesFromField( mExpressionWidget->currentField(), minValue, maxValue ) )
return;
}

whileBlocking( minValueSpinBox )->setValue( minValue );
whileBlocking( maxValueSpinBox )->setValue( maxValue );
emit widgetChanged();
}

bool QgsPropertyAssistantWidget::computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const
{
QgsExpression e( expression );

QgsExpressionContext context;
if ( mExpressionContextGenerator )
{
context = mExpressionContextGenerator->createExpressionContext();
}
else
{
context << QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope( QgsProject::instance() )
<< QgsExpressionContextUtils::layerScope( mLayer );
}

if ( !e.prepare( &context ) )
return false;

QSet<QString> referencedCols( e.referencedColumns() );

QgsFeatureIterator fit = mLayer->getFeatures(
QgsFeatureRequest().setFlags( e.needsGeometry()
? QgsFeatureRequest::NoFlags
: QgsFeatureRequest::NoGeometry )
.setSubsetOfAttributes( referencedCols, mLayer->fields() ) );

// create list of non-null attribute values
double min = DBL_MAX;
double max = -DBL_MAX;
QgsFeature f;
bool found = false;
while ( fit.nextFeature( f ) )
{
bool ok;
context.setFeature( f );
const double value = e.evaluate( &context ).toDouble( &ok );
if ( ok )
{
max = qMax( max, value );
min = qMin( min, value );
found = true;
}
}
if ( found )
{
minValue = min;
maxValue = max;
}
return found;
}

bool QgsPropertyAssistantWidget::computeValuesFromField( const QString& fieldName, double& minValue, double& maxValue ) const
{
int fieldIndex = mLayer->fields().lookupField( fieldName );
if ( fieldIndex < 0 )
{
return false;
}

bool ok = false;
double minDouble = mLayer->minimumValue( fieldIndex ).toDouble( &ok );
if ( !ok )
return false;

double maxDouble = mLayer->maximumValue( fieldIndex ).toDouble( &ok );
if ( !ok )
return false;

minValue = minDouble;
maxValue = maxDouble;
return true;
}


//
// QgsPropertySizeAssistantWidget
//

QgsPropertySizeAssistantWidget::QgsPropertySizeAssistantWidget( QWidget* parent, const QgsPropertyDefinition& definition, const QgsProperty& initialState )
: QgsPropertyAbstractTransformerWidget( parent, definition )
{
setupUi( this );

layout()->setContentsMargins( 0, 0, 0, 0 );
layout()->setMargin( 0 );

scaleMethodComboBox->addItem( tr( "Flannery" ), QgsSizeScaleTransformer::Flannery );
scaleMethodComboBox->addItem( tr( "Surface" ), QgsSizeScaleTransformer::Area );
scaleMethodComboBox->addItem( tr( "Radius" ), QgsSizeScaleTransformer::Linear );
scaleMethodComboBox->addItem( tr( "Exponential" ), QgsSizeScaleTransformer::Exponential );

minSizeSpinBox->setShowClearButton( false );
maxSizeSpinBox->setShowClearButton( false );
nullSizeSpinBox->setShowClearButton( false );

if ( const QgsSizeScaleTransformer* sizeTransform = dynamic_cast< const QgsSizeScaleTransformer* >( initialState.transformer() ) )
{
minSizeSpinBox->setValue( sizeTransform->minSize() );
maxSizeSpinBox->setValue( sizeTransform->maxSize() );
nullSizeSpinBox->setValue( sizeTransform->nullSize() );
exponentSpinBox->setValue( sizeTransform->exponent() );
scaleMethodComboBox->setCurrentIndex( scaleMethodComboBox->findData( sizeTransform->type() ) );
}

exponentSpinBox->setEnabled( scaleMethodComboBox->currentData().toInt() == QgsSizeScaleTransformer::Exponential );

connect( minSizeSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
connect( maxSizeSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
connect( nullSizeSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
connect( exponentSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
connect( scaleMethodComboBox, static_cast < void ( QComboBox::* )( int ) > ( &QComboBox::currentIndexChanged ), this, &QgsPropertySizeAssistantWidget::widgetChanged );
connect( scaleMethodComboBox, static_cast < void ( QComboBox::* )( int ) > ( &QComboBox::currentIndexChanged ), this,
[=]
{
exponentSpinBox->setEnabled( scaleMethodComboBox->currentData().toInt() == QgsSizeScaleTransformer::Exponential );
}
);
}

QgsPropertyTransformer* QgsPropertySizeAssistantWidget::createTransformer( double minValue, double maxValue ) const
{
QgsSizeScaleTransformer* transformer = new QgsSizeScaleTransformer(
static_cast< QgsSizeScaleTransformer::ScaleType >( scaleMethodComboBox->currentData().toInt() ),
minValue,
maxValue,
minSizeSpinBox->value(),
maxSizeSpinBox->value(),
nullSizeSpinBox->value(),
exponentSpinBox->value() );
return transformer;
}
104 changes: 104 additions & 0 deletions src/gui/qgspropertyassistantwidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/***************************************************************************
qgspropertyassistantwidget.h
----------------------------
begin : February, 2017
copyright : (C) 2017 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. *
* *
***************************************************************************/
#ifndef QGSPROPERTYASSISTANTWIDGET_H
#define QGSPROPERTYASSISTANTWIDGET_H

#include "qgspanelwidget.h"
#include "ui_qgspropertyassistantwidgetbase.h"
#include "ui_qgspropertysizeassistantwidget.h"
#include "qgsproperty.h"
#include "qgis_gui.h"

class QgsMapCanvas;

///@cond PRIVATE

class GUI_EXPORT QgsPropertyAbstractTransformerWidget : public QWidget
{
Q_OBJECT

public:

QgsPropertyAbstractTransformerWidget( QWidget* parent = nullptr, const QgsPropertyDefinition& definition = QgsPropertyDefinition() )
: QWidget( parent )
, mDefinition( definition )
{}

virtual QgsPropertyTransformer* createTransformer( double minValue, double maxValue ) const = 0;

signals:

void widgetChanged();

protected:

QgsPropertyDefinition mDefinition;

};

class GUI_EXPORT QgsPropertySizeAssistantWidget : public QgsPropertyAbstractTransformerWidget, private Ui::PropertySizeAssistant
{
Q_OBJECT

public:

QgsPropertySizeAssistantWidget( QWidget* parent = nullptr, const QgsPropertyDefinition& definition = QgsPropertyDefinition(), const QgsProperty& initialState = QgsProperty() );

virtual QgsPropertyTransformer* createTransformer( double minValue, double maxValue ) const override;


};

///@endcond PRIVATE

class GUI_EXPORT QgsPropertyAssistantWidget : public QgsPanelWidget, private Ui::PropertyAssistantBase
{
Q_OBJECT

public:

QgsPropertyAssistantWidget( QWidget* parent = nullptr, const QgsPropertyDefinition& definition = QgsPropertyDefinition(),
const QgsProperty& initialState = QgsProperty(),
const QgsVectorLayer* layer = nullptr );

/**
* Register an expression context generator class that will be used to retrieve
* an expression context for the button when required.
*/
void registerExpressionContextGenerator( QgsExpressionContextGenerator* generator );

void updateProperty( QgsProperty& property );


private slots:
void computeValuesFromLayer();

private:

QgsPropertyDefinition mDefinition;
const QgsVectorLayer* mLayer = nullptr;
QgsExpressionContextGenerator* mExpressionContextGenerator = nullptr;
QgsPropertyAbstractTransformerWidget* mTransformerWidget = nullptr;

bool computeValuesFromExpression( const QString& expression, double& minValue, double& maxValue ) const;
bool computeValuesFromField( const QString& fieldName, double& minValue, double& maxValue ) const;

};


#endif // QGSPROPERTYASSISTANTWIDGET_H
Loading

0 comments on commit f70a031

Please sign in to comment.