Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[diagram] Add expression for diagram attributes and size
  • Loading branch information
sbrunner authored and m-kuhn committed Jan 10, 2014
1 parent 443a416 commit a0911d6
Show file tree
Hide file tree
Showing 25 changed files with 610 additions and 116 deletions.
8 changes: 6 additions & 2 deletions python/core/diagram/qgsdiagram.sip
Expand Up @@ -6,12 +6,16 @@ class QgsDiagram
public:
virtual ~QgsDiagram();
/**Draws the diagram at the given position (in pixel coordinates)*/
virtual void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) /Deprecated/;
/**Draws the diagram at the given position (in pixel coordinates)*/
virtual void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual QString diagramName() const = 0;
/**Returns the size in map units the diagram will use to render.*/
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s ) = 0;
/**Returns the size in map units the diagram will use to render. Interpolate size*/
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) = 0;
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) /Deprecated/;
/**Returns the size in map units the diagram will use to render. Interpolate size*/
virtual QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is ) = 0;

protected:
/** Changes the pen width to match the current settings and rendering context
Expand Down
4 changes: 2 additions & 2 deletions python/core/diagram/qgshistogramdiagram.sip
Expand Up @@ -7,8 +7,8 @@ class QgsHistogramDiagram: QgsDiagram
QgsHistogramDiagram();
~QgsHistogramDiagram();

void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QString diagramName() const;
};
4 changes: 2 additions & 2 deletions python/core/diagram/qgspiediagram.sip
Expand Up @@ -7,8 +7,8 @@ class QgsPieDiagram: QgsDiagram
QgsPieDiagram();
~QgsPieDiagram();

void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QString diagramName() const;
};
4 changes: 2 additions & 2 deletions python/core/diagram/qgstextdiagram.sip
Expand Up @@ -20,9 +20,9 @@ class QgsTextDiagram: QgsDiagram

QgsTextDiagram();
~QgsTextDiagram();
void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c, const QgsDiagramSettings& s, const QgsDiagramInterpolationSettings& is );

QString diagramName() const;
};
24 changes: 12 additions & 12 deletions python/core/qgsdiagramrendererv2.sip
Expand Up @@ -69,7 +69,7 @@ class QgsDiagramSettings
QgsDiagramSettings();
QFont font;
QList< QColor > categoryColors;
QList< int > categoryIndices;
QList< QString > categoryAttributes;
QSizeF size; //size
SizeType sizeType; //mm or map units
QColor backgroundColor;
Expand Down Expand Up @@ -119,14 +119,14 @@ class QgsDiagramRendererV2
virtual ~QgsDiagramRendererV2();

/**Returns size of the diagram for feature f in map units. Returns an invalid QSizeF in case of error*/
virtual QSizeF sizeMapUnits( const QgsAttributes& attributes, const QgsRenderContext& c );
virtual QSizeF sizeMapUnits( const QgsFeature& feature, const QgsRenderContext& c );

virtual QString rendererName() const = 0;

/**Returns attribute indices needed for diagram rendering*/
virtual QList<int> diagramAttributes() const = 0;
virtual QList<QString> diagramAttributes() const = 0;

void renderDiagram( const QgsAttributes& att, QgsRenderContext& c, const QPointF& pos );
void renderDiagram( const QgsFeature& feature, QgsRenderContext& c, const QPointF& pos );

void setDiagram( QgsDiagram* d /Transfer/ );
const QgsDiagram* diagram() const;
Expand All @@ -144,10 +144,10 @@ class QgsDiagramRendererV2
* @param c render context
* @param s out: diagram settings for the feature
*/
virtual bool diagramSettings( const QgsAttributes& att, const QgsRenderContext& c, QgsDiagramSettings& s ) = 0;
virtual bool diagramSettings( const QgsFeature& feature, const QgsRenderContext& c, QgsDiagramSettings& s ) = 0;

/**Returns size of the diagram (in painter units) or an invalid size in case of error*/
virtual QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c ) = 0;
virtual QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c ) = 0;

/**Converts size from mm to map units*/
void convertSizeToMapUnits( QSizeF& size, const QgsRenderContext& context ) const;
Expand All @@ -173,7 +173,7 @@ class QgsSingleCategoryDiagramRenderer : QgsDiagramRendererV2

QString rendererName() const;

QList<int> diagramAttributes() const;
QList<QString> diagramAttributes() const;

void setDiagramSettings( const QgsDiagramSettings& s );

Expand All @@ -183,9 +183,9 @@ class QgsSingleCategoryDiagramRenderer : QgsDiagramRendererV2
void writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const;

protected:
bool diagramSettings( const QgsAttributes&, const QgsRenderContext& c, QgsDiagramSettings& s );
bool diagramSettings( const QgsFeature& feature, const QgsRenderContext& c, QgsDiagramSettings& s );

QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c );
};

class QgsLinearlyInterpolatedDiagramRenderer : QgsDiagramRendererV2
Expand All @@ -203,7 +203,7 @@ class QgsLinearlyInterpolatedDiagramRenderer : QgsDiagramRendererV2

void setDiagramSettings( const QgsDiagramSettings& s );

QList<int> diagramAttributes() const;
QList<QString> diagramAttributes() const;

QString rendererName() const;

Expand All @@ -226,7 +226,7 @@ class QgsLinearlyInterpolatedDiagramRenderer : QgsDiagramRendererV2
void writeXML( QDomElement& layerElem, QDomDocument& doc, const QgsVectorLayer* layer ) const;

protected:
bool diagramSettings( const QgsAttributes&, const QgsRenderContext& c, QgsDiagramSettings& s );
bool diagramSettings( const QgsFeature& feature, const QgsRenderContext& c, QgsDiagramSettings& s );

QSizeF diagramSize( const QgsAttributes& attributes, const QgsRenderContext& c );
QSizeF diagramSize( const QgsFeature& feature, const QgsRenderContext& c );
};
142 changes: 130 additions & 12 deletions src/app/qgsdiagramproperties.cpp
Expand Up @@ -20,13 +20,15 @@
#include "diagram/qgstextdiagram.h"

#include "qgisapp.h"
#include "qgsproject.h"
#include "qgsapplication.h"
#include "qgsdiagramproperties.h"
#include "qgsdiagramrendererv2.h"
#include "qgslabelengineconfigdialog.h"
#include "qgsmessagebar.h"
#include "qgsvectorlayerproperties.h"
#include "qgsvectordataprovider.h"
#include "qgsfeatureiterator.h"

#include <QColorDialog>
#include <QFontDialog>
Expand Down Expand Up @@ -127,8 +129,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer* layer, QWidget* pare
for ( int idx = 0; idx < layerFields.count(); ++idx )
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( mAttributesTreeWidget );
newItem->setText( 0, layerFields[idx].name() );
newItem->setData( 0, Qt::UserRole, idx );
QString name = QString( "\"%1\"" ).arg( layerFields[idx].name() );
newItem->setText( 0, name );
newItem->setData( 0, Qt::UserRole, name );
newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
if ( layerFields[idx].type() != QVariant::String )
{
Expand All @@ -138,6 +141,7 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer* layer, QWidget* pare
mDataDefinedXComboBox->addItem( layerFields[idx].name(), idx );
mDataDefinedYComboBox->addItem( layerFields[idx].name(), idx );
}
mAvailableAttributes = mSizeAttributeComboBox->count();

const QgsDiagramRendererV2* dr = layer->diagramRenderer();
if ( !dr ) //no diagram renderer yet, insert reasonable default
Expand Down Expand Up @@ -250,13 +254,13 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer* layer, QWidget* pare
}

QList< QColor > categoryColors = settingList.at( 0 ).categoryColors;
QList< int > categoryIndices = settingList.at( 0 ).categoryIndices;
QList< int >::const_iterator catIt = categoryIndices.constBegin();
QList< QString > categoryAttributes = settingList.at( 0 ).categoryAttributes;
QList< QString >::const_iterator catIt = categoryAttributes.constBegin();
QList< QColor >::const_iterator coIt = categoryColors.constBegin();
for ( ;catIt != categoryIndices.constEnd(); ++catIt, ++coIt )
for ( ; catIt != categoryAttributes.constEnd(); ++catIt, ++coIt )
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
newItem->setText( 0, layer->pendingFields()[*catIt].name() );
newItem->setText( 0, *catIt );
newItem->setData( 0, Qt::UserRole, *catIt );
newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
QColor col( *coIt );
Expand All @@ -273,7 +277,15 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer* layer, QWidget* pare
mDiagramSizeSpinBox->setEnabled( false );
mValueLineEdit->setText( QString::number( lidr->upperValue(), 'f' ) );
mSizeSpinBox->setValue(( lidr->upperSize().width() + lidr->upperSize().height() ) / 2 );
mSizeAttributeComboBox->setCurrentIndex( mSizeAttributeComboBox->findData( lidr->classificationAttribute() ) );
if ( lidr->classificationAttributeIsExpression() )
{
mSizeAttributeComboBox->addItem( lidr->classificationAttributeExpression() );
mSizeAttributeComboBox->setCurrentIndex( mSizeAttributeComboBox->count() - 1 );
}
else
{
mSizeAttributeComboBox->setCurrentIndex( mSizeAttributeComboBox->findData( lidr->classificationAttribute() ) );
}
}
}

Expand Down Expand Up @@ -307,6 +319,9 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer* layer, QWidget* pare

// Trigger a clicked event, so all the items get properly enabled and disabled
on_mDisplayDiagramsGroupBox_toggled( mDisplayDiagramsGroupBox->isChecked() );

connect( mSizeAttributeExpression, SIGNAL( clicked() ), this, SLOT( showSizeAttributeExpressionDialog() ) );
connect( mAddAttributeExpression, SIGNAL( clicked() ), this, SLOT( showAddAttributeExpressionDialog() ) );
}

void QgsDiagramProperties::on_mDiagramTypeComboBox_currentIndexChanged( int index )
Expand Down Expand Up @@ -433,7 +448,30 @@ void QgsDiagramProperties::on_mFindMaximumValueButton_clicked()
QgsVectorDataProvider* provider = mLayer->dataProvider();
if ( provider )
{
mValueLineEdit->setText( provider->maximumValue( mSizeAttributeComboBox->itemData( mSizeAttributeComboBox->currentIndex() ).toInt() ).toString() );
float maxValue = 0;
if ( mSizeAttributeComboBox->currentIndex() >= mAvailableAttributes )
{
QgsExpression exp( mSizeAttributeComboBox->currentText() );
exp.prepare( mLayer->pendingFields() );
if ( exp.hasEvalError() )
{
QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
}
else
{
QgsFeature feature;
QgsFeatureIterator features = mLayer->getFeatures();
while ( features.nextFeature( *&feature ) )
{
maxValue = qMax( maxValue, exp.evaluate( &feature ).toFloat() );
}
}
}
else
{
maxValue = provider->maximumValue( mSizeAttributeComboBox->itemData( mSizeAttributeComboBox->currentIndex() ).toInt() ).toFloat();
}
mValueLineEdit->setText( QString( "%1" ).arg( maxValue ) );
}
}
}
Expand Down Expand Up @@ -551,16 +589,16 @@ void QgsDiagramProperties::apply()
ds.transparency = mTransparencySlider->value();

QList<QColor> categoryColors;
QList<int> categoryAttributes;
QList<QString> categoryAttributes;
for ( int i = 0; i < mDiagramAttributesTreeWidget->topLevelItemCount(); ++i )
{
QColor color = mDiagramAttributesTreeWidget->topLevelItem( i )->background( 1 ).color();
color.setAlpha( 255 - ds.transparency );
categoryColors.append( color );
categoryAttributes.append( mDiagramAttributesTreeWidget->topLevelItem( i )->data( 0, Qt::UserRole ).toInt() );
categoryAttributes.append( mDiagramAttributesTreeWidget->topLevelItem( i )->data( 0, Qt::UserRole ).toString() );
}
ds.categoryColors = categoryColors;
ds.categoryIndices = categoryAttributes;
ds.categoryAttributes = categoryAttributes;
ds.size = QSizeF( mDiagramSizeSpinBox->value(), mDiagramSizeSpinBox->value() );
ds.sizeType = static_cast<QgsDiagramSettings::SizeType>( mDiagramUnitComboBox->itemData( mDiagramUnitComboBox->currentIndex() ).toInt() );
ds.labelPlacementMethod = static_cast<QgsDiagramSettings::LabelPlacementMethod>( mLabelPlacementComboBox->itemData( mLabelPlacementComboBox->currentIndex() ).toInt() );
Expand Down Expand Up @@ -611,7 +649,16 @@ void QgsDiagramProperties::apply()
dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
dr->setUpperValue( mValueLineEdit->text().toDouble() );
dr->setUpperSize( QSizeF( mSizeSpinBox->value(), mSizeSpinBox->value() ) );
dr->setClassificationAttribute( mSizeAttributeComboBox->itemData( mSizeAttributeComboBox->currentIndex() ).toInt() );
bool isExpression = mSizeAttributeComboBox->currentIndex() >= mAvailableAttributes;
dr->setClassificationAttributeIsExpression( isExpression );
if ( isExpression )
{
dr->setClassificationAttributeExpression( mSizeAttributeComboBox->currentText() );
}
else
{
dr->setClassificationAttribute( mSizeAttributeComboBox->itemData( mSizeAttributeComboBox->currentIndex() ).toInt() );
}
dr->setDiagram( diagram );
dr->setDiagramSettings( ds );
mLayer->setDiagramRenderer( dr );
Expand All @@ -638,3 +685,74 @@ void QgsDiagramProperties::apply()
mLayer->setDiagramLayerSettings( dls );
}
}

void QgsDiagramProperties::showSizeAttributeExpressionDialog()
{
QString current = mSizeAttributeComboBox->currentText();
if ( mSizeAttributeComboBox->currentIndex() < mAvailableAttributes )
{
current = QString( "\"%1\"" ).arg( current );
}
QgsExpressionBuilderDialog dlg( mLayer, current, this );

dlg.setWindowTitle( tr( "Expression based attribute" ) );

QgsDistanceArea myDa;
myDa.setSourceCrs( mLayer->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
dlg.setGeomCalculator( myDa );

if ( dlg.exec() == QDialog::Accepted )
{
QString expression = dlg.expressionText();
//Only add the expression if the user has entered some text.
if ( !expression.isEmpty() )
{
mSizeAttributeComboBox->addItem( expression );
mSizeAttributeComboBox->setCurrentIndex( mSizeAttributeComboBox->count() - 1 );
}
}
activateWindow(); // set focus back parent
}

void QgsDiagramProperties::showAddAttributeExpressionDialog()
{
QString expression;
QList<QTreeWidgetItem *> selections = mAttributesTreeWidget->selectedItems();
if ( !selections.empty() )
{
expression = selections[0]->text( 0 );
}
QgsExpressionBuilderDialog dlg( mLayer, expression, this );
dlg.setWindowTitle( tr( "Expression based attribute" ) );

QgsDistanceArea myDa;
myDa.setSourceCrs( mLayer->crs().srsid() );
myDa.setEllipsoidalMode( QgisApp::instance()->mapCanvas()->mapRenderer()->hasCrsTransformEnabled() );
myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) );
dlg.setGeomCalculator( myDa );

if ( dlg.exec() == QDialog::Accepted )
{
QString expression = dlg.expressionText();
//Only add the expression if the user has entered some text.
if ( !expression.isEmpty() )
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );

newItem->setText( 0, expression );
newItem->setData( 0, Qt::UserRole, expression );
newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );

//set initial color for diagram category
int red = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
int green = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
int blue = 1 + ( int )( 255.0 * rand() / ( RAND_MAX + 1.0 ) );
QColor randomColor( red, green, blue );
newItem->setBackground( 1, QBrush( randomColor ) );
mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
}
}
activateWindow(); // set focus back parent
}
3 changes: 3 additions & 0 deletions src/app/qgsdiagramproperties.h
Expand Up @@ -44,13 +44,16 @@ class APP_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr
void on_mDiagramFontButton_clicked();
void on_mDiagramAttributesTreeWidget_itemDoubleClicked( QTreeWidgetItem * item, int column );
void on_mEngineSettingsButton_clicked();
void showSizeAttributeExpressionDialog();
void showAddAttributeExpressionDialog();

protected:
QFont mDiagramFont;

QgsVectorLayer* mLayer;

private:
int mAvailableAttributes;
};

#endif // QGSDIAGRAMPROPERTIES_H

0 comments on commit a0911d6

Please sign in to comment.