-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
edb30a2
commit f70a031
Showing
9 changed files
with
722 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 ); | ||
|
||
}; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.