[FEATURE] Add diagram system that uses the same pal instance as labeling-ng

git-svn-id: http://svn.osgeo.org/qgis/trunk@15503 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
mhugent 2011-03-15 16:43:23 +00:00
parent 393e206e2d
commit c3ac6df9ee
35 changed files with 2371 additions and 77 deletions

View File

@ -0,0 +1,160 @@
struct QgsDiagramLayerSettings
{
%TypeHeaderCode
#include <qgsdiagramrendererv2.h>
%End
//avoid inclusion of QgsPalLabeling
enum Placement
{
AroundPoint, // Point / Polygon
OverPoint, // Point / Polygon
Line, // Line / Polygon
Curved, // Line
Horizontal, // Polygon
Free // Polygon
};
enum LinePlacementFlags
{
OnLine = 1,
AboveLine = 2,
BelowLine = 4,
MapOrientation = 8
};
QgsDiagramLayerSettings();
//pal placement properties
Placement placement;
LinePlacementFlags placementFlags;
int priority; // 0 = low, 10 = high
bool obstacle; // whether it's an obstacle
double dist; // distance from the feature (in mm)
QgsDiagramRendererV2* renderer;
int xPosColumn; //attribute index for x coordinate (or -1 if position not data defined)
int yPosColumn;//attribute index for y coordinate (or -1 if position not data defined)
void readXML( const QDomElement& elem );
void writeXML( QDomElement& layerElem, QDomDocument& doc ) const;
};
//diagram settings for rendering
struct QgsDiagramSettings
{
%TypeHeaderCode
#include <qgsdiagramrendererv2.h>
%End
enum SizeType
{
MM,
MapUnits
};
QgsDiagramSettings();
QFont font;
QList< QColor > categoryColors;
QList< int > categoryIndices;
QSizeF size; //size
SizeType sizeType; //mm or map units
QColor backgroundColor;
QColor penColor;
double penWidth;
//scale range (-1 if no lower / upper bound )
double minScaleDenominator;
double maxScaleDenominator;
void readXML( const QDomElement& elem );
void writeXML( QDomElement& rendererElem, QDomDocument& doc ) const;
};
/**Returns diagram settings for a feature*/
class QgsDiagramRendererV2
{
%TypeHeaderCode
#include <qgsdiagramrendererv2.h>
%End
public:
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 QgsAttributeMap& attributes, const QgsRenderContext& c );
virtual QString rendererName() const = 0;
/**Returns attribute indices needed for diagram rendering*/
virtual QList<int> diagramAttributes() const = 0;
void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QPointF& pos );
void setDiagram( QgsDiagram* d );
const QgsDiagram* diagram() const;
/**Returns list with all diagram settings in the renderer*/
virtual QList<QgsDiagramSettings> diagramSettings() const = 0;
virtual void readXML( const QDomElement& elem ) = 0;
virtual void writeXML( QDomElement& layerElem, QDomDocument& doc ) const = 0;
};
/**Renders the diagrams for all features with the same settings*/
class QgsSingleCategoryDiagramRenderer: QgsDiagramRendererV2
{
%TypeHeaderCode
#include <qgsdiagramrendererv2.h>
%End
public:
QgsSingleCategoryDiagramRenderer();
~QgsSingleCategoryDiagramRenderer();
QString rendererName() const;
QList<int> diagramAttributes() const;
void setDiagramSettings( const QgsDiagramSettings& s );
QList<QgsDiagramSettings> diagramSettings() const;
void readXML( const QDomElement& elem );
void writeXML( QDomElement& layerElem, QDomDocument& doc ) const;
};
class QgsLinearlyInterpolatedDiagramRenderer: QgsDiagramRendererV2
{
%TypeHeaderCode
#include <qgsdiagramrendererv2.h>
%End
public:
QgsLinearlyInterpolatedDiagramRenderer();
~QgsLinearlyInterpolatedDiagramRenderer();
/**Returns list with all diagram settings in the renderer*/
QList<QgsDiagramSettings> diagramSettings() const;
void setDiagramSettings( const QgsDiagramSettings& s );
QList<int> diagramAttributes() const;
QString rendererName() const;
void setLowerValue( double val );
double lowerValue() const;
void setUpperValue( double val );
double upperValue() const;
void setLowerSize( QSizeF s );
QSizeF lowerSize() const;
void setUpperSize( QSizeF s );
QSizeF upperSize() const;
int classificationAttribute() const;
void setClassificationAttribute( int index );
void readXML( const QDomElement& elem );
void writeXML( QDomElement& layerElem, QDomDocument& doc ) const;
};

View File

@ -17,6 +17,7 @@
#include "qgsinterpolator.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsgeometry.h"
QgsInterpolator::QgsInterpolator( const QList<LayerData>& layerData ): mDataIsCached( false ), mLayerData( layerData )

View File

@ -5663,14 +5663,17 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer )
for ( QMap<QString, QgsMapLayer*>::iterator it = layers.begin(); it != layers.end(); it++ )
{
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( it.value() );
if ( !vlayer || !vlayer->isEditable() || vlayer->customProperty( "labeling" ).toString() != QString( "pal" ) )
if ( !vlayer || !vlayer->isEditable() ||
( !vlayer->diagramRenderer() && vlayer->customProperty( "labeling" ).toString() != QString( "pal" ) ) )
continue;
int colX, colY, colAng;
enableMove =
enableMove ||
( qobject_cast<QgsMapToolMoveLabel*>( mMapTools.mMoveLabel ) &&
qobject_cast<QgsMapToolMoveLabel*>( mMapTools.mMoveLabel )->layerIsMoveable( vlayer, colX, colY ) );
( qobject_cast<QgsMapToolMoveLabel*>( mMapTools.mMoveLabel )->labelMoveable( vlayer, colX, colY )
|| qobject_cast<QgsMapToolMoveLabel*>( mMapTools.mMoveLabel )->diagramMoveable( vlayer, colX, colY ) )
);
enableRotate =
enableRotate ||

View File

@ -18,6 +18,7 @@
#include "qgslabelpropertydialog.h"
#include "qgsmaplayerregistry.h"
#include "qgsmaprenderer.h"
#include "qgsvectorlayer.h"
#include <QColorDialog>
#include <QFontDialog>

View File

@ -280,6 +280,14 @@ bool QgsMapToolLabel::rotationPoint( QgsPoint& pos )
pos = mCurrentLabelPos.cornerPoints.at( 0 );
}
//alignment always center/center and rotation 0 for diagrams
if ( mCurrentLabelPos.isDiagram )
{
pos.setX( pos.x() + mCurrentLabelPos.labelRect.width() / 2.0 );
pos.setY( pos.y() + mCurrentLabelPos.labelRect.height() / 2.0 );
return true;
}
//adapt pos depending on data defined alignment
QString haliString, valiString;
currentAlignment( haliString, valiString );
@ -356,7 +364,14 @@ bool QgsMapToolLabel::dataDefinedPosition( QgsVectorLayer* vlayer, int featureId
return false;
}
if ( !layerIsMoveable( vlayer, xCol, yCol ) )
if ( mCurrentLabelPos.isDiagram )
{
if ( !diagramMoveable( vlayer, xCol, yCol ) )
{
return false;
}
}
else if ( !labelMoveable( vlayer, xCol, yCol ) )
{
return false;
}
@ -374,7 +389,23 @@ bool QgsMapToolLabel::dataDefinedPosition( QgsVectorLayer* vlayer, int featureId
return true;
}
bool QgsMapToolLabel::layerIsMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const
bool QgsMapToolLabel:: diagramMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const
{
const QgsVectorLayer* vlayer = dynamic_cast<const QgsVectorLayer*>( ml );
if ( vlayer && vlayer->diagramRenderer() )
{
QgsDiagramLayerSettings dls = vlayer->diagramLayerSettings();
if ( dls.xPosColumn >= 0 && dls.yPosColumn >= 0 )
{
xCol = dls.xPosColumn;
yCol = dls.yPosColumn;
return true;
}
}
return false;
}
bool QgsMapToolLabel::labelMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const
{
const QgsVectorLayer* vlayer = dynamic_cast<const QgsVectorLayer*>( ml );
if ( !vlayer || !vlayer->isEditable() )

View File

@ -31,11 +31,16 @@ class QgsMapToolLabel: public QgsMapTool
QgsMapToolLabel( QgsMapCanvas* canvas );
~QgsMapToolLabel();
/**Returns true if layer move can be applied to a layer
/**Returns true if label move can be applied to a layer
@param xCol out: index of the attribute for data defined x coordinate
@param yCol out: index of the attribute for data defined y coordinate
@return true if labels of layer can be moved*/
bool layerIsMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const;
bool labelMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const;
/**Returns true if diagram move can be applied to a layer
@param xCol out: index of the attribute for data defined x coordinate
@param yCol out: index of the attribute for data defined y coordinate
@return true if labels of layer can be moved*/
bool diagramMoveable( const QgsMapLayer* ml, int& xCol, int& yCol ) const;
protected:
QgsRubberBand* mLabelRubberBand;

View File

@ -40,13 +40,13 @@ void QgsMapToolMoveLabel::canvasPressEvent( QMouseEvent * e )
}
QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID );
if ( !layer )
if ( !layer || !layer->isEditable() )
{
return;
}
int xCol, yCol;
if ( layerIsMoveable( layer, xCol, yCol ) )
if ( labelMoveable( layer, xCol, yCol ) || diagramMoveable( layer, xCol, yCol ) )
{
mStartPointMapCoords = toMapCoordinates( e->pos() );
mClickOffsetX = mStartPointMapCoords.x() - mCurrentLabelPos.labelRect.xMinimum();

View File

@ -28,6 +28,8 @@
#include "qgscontexthelp.h"
#include "qgscontinuouscolordialog.h"
#include "qgscoordinatetransform.h"
#include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsfieldcalculator.h"
#include "qgsgraduatedsymboldialog.h"
#include "qgslabeldialog.h"
@ -53,10 +55,12 @@
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QFontDialog>
#include <QSettings>
#include <QComboBox>
#include <QCheckBox>
#include <QHeaderView>
#include <QColorDialog>
#include "qgsrendererv2propertiesdialog.h"
#include "qgsstylev2.h"
@ -142,6 +146,8 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
addJoinToTreeWidget( joins[i] );
}
initDiagramTab();
//for each overlay plugin create a new tab
int position;
QList<QgsVectorOverlayPlugin*> overlayPluginList = overlayPlugins();
@ -678,6 +684,92 @@ void QgsVectorLayerProperties::apply()
}
//apply diagram settings
if ( !mDisplayDiagramsCheckBox->isChecked() )
{
layer->setDiagramRenderer( 0 );
}
else
{
QgsDiagram* diagram = 0;
if ( mDiagramTypeComboBox->currentText() == tr( "Text diagram" ) )
{
diagram = new QgsTextDiagram();
}
else if ( mDiagramTypeComboBox->currentText() == tr( "Pie chart" ) )
{
diagram = new QgsPieDiagram();
}
QgsDiagramSettings ds;
ds.font = mDiagramFont;
QList<QColor> categoryColors;
QList<int> categoryAttributes;
for ( int i = 0; i < mDiagramAttributesTreeWidget->topLevelItemCount(); ++i )
{
categoryColors.append( mDiagramAttributesTreeWidget->topLevelItem( i )->background( 1 ).color() );
categoryAttributes.append( mDiagramAttributesTreeWidget->topLevelItem( i )->data( 0, Qt::UserRole ).toInt() );
}
ds.categoryColors = categoryColors;
ds.categoryIndices = categoryAttributes;
ds.size = QSizeF( mDiagramSizeSpinBox->value(), mDiagramSizeSpinBox->value() );
if ( mDiagramUnitComboBox->currentText() == tr( "Map units" ) )
{
ds.sizeType = QgsDiagramSettings::MapUnits;
}
else
{
ds.sizeType = QgsDiagramSettings::MM;
}
ds.backgroundColor = mBackgroundColorButton->color();
ds.penColor = mDiagramPenColorButton->color();
ds.penWidth = mPenWidthSpinBox->value();
if ( mScaleDependentDiagramVisibilityCheckBox->isChecked() )
{
ds.minScaleDenominator = mMinimumDiagramScaleLineEdit->text().toDouble();
ds.maxScaleDenominator = mMaximumDiagramScaleLineEdit->text().toDouble();
}
else
{
ds.minScaleDenominator = -1;
ds.maxScaleDenominator = -1;
}
QgsDiagramRendererV2* r = 0;
if ( mFixedSizeCheckBox->isChecked() )
{
QgsSingleCategoryDiagramRenderer* dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( diagram );
dr->setDiagramSettings( ds );
layer->setDiagramRenderer( dr );
}
else
{
QgsLinearlyInterpolatedDiagramRenderer* dr = new QgsLinearlyInterpolatedDiagramRenderer();
dr->setLowerValue( 0.0 );
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() );
dr->setDiagram( diagram );
dr->setDiagramSettings( ds );
layer->setDiagramRenderer( dr );
}
QgsDiagramLayerSettings dls;
dls.dist = mDiagramDistanceSpinBox->value();
dls.priority = mPrioritySlider->value();
dls.xPosColumn = mDataDefinedXComboBox->itemData( mDataDefinedXComboBox->currentIndex() ).toInt();
dls.yPosColumn = mDataDefinedYComboBox->itemData( mDataDefinedYComboBox->currentIndex() ).toInt();
dls.placement = ( QgsDiagramLayerSettings::Placement )mPlacementComboBox->itemData( mPlacementComboBox->currentIndex() ).toInt();
if ( mLineOptionsComboBox->isEnabled() )
{
dls.placementFlags = ( QgsDiagramLayerSettings::LinePlacementFlags )mLineOptionsComboBox->itemData( mLineOptionsComboBox->currentIndex() ).toInt();
}
layer->setDiagramLayerSettings( dls );
}
//apply overlay dialogs
for ( QList<QgsApplyDialog*>::iterator it = mOverlayDialogs.begin(); it != mOverlayDialogs.end(); ++it )
{
@ -1243,6 +1335,18 @@ void QgsVectorLayerProperties::on_mButtonRemoveJoin_clicked()
mJoinTreeWidget->takeTopLevelItem( mJoinTreeWidget->indexOfTopLevelItem( currentJoinItem ) );
}
void QgsVectorLayerProperties::handleDiagramItemDoubleClick( QTreeWidgetItem * item, int column )
{
if ( column == 1 ) //change color
{
QColor newColor = QColorDialog::getColor();
if ( newColor.isValid() )
{
item->setBackground( 1, QBrush( newColor ) );
}
}
}
void QgsVectorLayerProperties::useNewSymbology()
{
int res = QMessageBox::question( this, tr( "Symbology" ),
@ -1338,3 +1442,271 @@ void QgsVectorLayerProperties::enableLabelOptions( bool theFlag )
{
labelOptionsFrame->setEnabled( theFlag );
}
void QgsVectorLayerProperties::on_mAddCategoryPushButton_clicked()
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
newItem->setText( 0, mDiagramAttributesComboBox->currentText() );
newItem->setData( 0, Qt::UserRole, mDiagramAttributesComboBox->itemData( mDiagramAttributesComboBox->currentIndex() ) );
//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 );
}
void QgsVectorLayerProperties::on_mRemoveCategoryPushButton_clicked()
{
QTreeWidgetItem* currentItem = mDiagramAttributesTreeWidget->currentItem();
if ( currentItem )
{
delete currentItem;
}
}
void QgsVectorLayerProperties::on_mDiagramFontButton_clicked()
{
bool ok;
mDiagramFont = QFontDialog::getFont( &ok, mDiagramFont );
}
void QgsVectorLayerProperties::on_mFixedSizeCheckBox_stateChanged( int state )
{
mDiagramSizeSpinBox->setEnabled( state == Qt::Checked );
//enable / disable all widget in the scaling layout
mLinearlyScalingLabel->setEnabled( state != Qt::Checked );
QWidget* currentWidget = 0;
for ( int i = 0; i < mLinearlyScalingLayout->count(); ++i )
{
currentWidget = mLinearlyScalingLayout->itemAt( i )->widget();
if ( currentWidget )
{
currentWidget->setEnabled( state != Qt::Checked );
}
}
}
void QgsVectorLayerProperties::on_mScaleDependentDiagramVisibilityCheckBox_stateChanged( int state )
{
mMinimumDiagramScaleLabel->setEnabled( state == Qt::Checked );
mMinimumDiagramScaleLineEdit->setEnabled( state == Qt::Checked );
mMaximumDiagramScaleLabel->setEnabled( state == Qt::Checked );
mMaximumDiagramScaleLineEdit->setEnabled( state == Qt::Checked );
}
void QgsVectorLayerProperties::on_mFindMaximumValueButton_clicked()
{
//get maximum value from provider (ignoring not-commited edits)
if ( layer )
{
QgsVectorDataProvider* provider = layer->dataProvider();
if ( provider )
{
mValueLineEdit->setText( provider->maximumValue( mSizeAttributeComboBox->itemData( mSizeAttributeComboBox->currentIndex() ).toInt() ).toString() );
}
}
}
void QgsVectorLayerProperties::on_mBackgroundColorButton_clicked()
{
QColor newColor = QColorDialog::getColor( mBackgroundColorButton->color(), 0, tr( "Background color" ), QColorDialog::ShowAlphaChannel );
if ( newColor.isValid() )
{
mBackgroundColorButton->setColor( newColor );
}
}
void QgsVectorLayerProperties::on_mDiagramPenColorButton_clicked()
{
QColor newColor = QColorDialog::getColor( mDiagramPenColorButton->color(), 0, tr( "Pen color" ), QColorDialog::ShowAlphaChannel );
if ( newColor.isValid() )
{
mDiagramPenColorButton->setColor( newColor );
}
}
void QgsVectorLayerProperties::initDiagramTab()
{
if ( !layer )
{
mDiagramPage->setEnabled( false );
}
mValueLineEdit->setValidator( new QDoubleValidator( mValueLineEdit ) );
mMinimumDiagramScaleLineEdit->setValidator( new QDoubleValidator( mMinimumDiagramScaleLineEdit ) );
mMaximumDiagramScaleLineEdit->setValidator( new QDoubleValidator( mMaximumDiagramScaleLineEdit ) );
mDiagramUnitComboBox->insertItem( 0, tr( "MM" ) );
mDiagramUnitComboBox->insertItem( 1, tr( "Map units" ) );
QGis::GeometryType layerType = layer->geometryType();
if ( layerType == QGis::UnknownGeometry || layerType == QGis::NoGeometry )
{
mDiagramPage->setEnabled( false );
}
//insert placement options
if ( layerType == QGis::Point || layerType == QGis::Polygon )
{
mPlacementComboBox->addItem( tr( "AroundPoint" ), 0 );
mPlacementComboBox->addItem( tr( "OverPoint" ), 1 );
}
if ( layerType == QGis::Line || layerType == QGis::Polygon )
{
mPlacementComboBox->addItem( tr( "Line" ), 2 );
mPlacementComboBox->addItem( tr( "Horizontal" ), 3 );
}
if ( layerType == QGis::Polygon )
{
mPlacementComboBox->addItem( tr( "Free" ), 4 );
}
if ( layerType == QGis::Line )
{
mLineOptionsComboBox->addItem( tr( "On line" ), 1 );
mLineOptionsComboBox->addItem( tr( "Above line" ), 2 );
mLineOptionsComboBox->addItem( tr( "Below Line" ), 4 );
mLineOptionsComboBox->addItem( tr( "Map orientation" ), 8 );
}
else
{
mLineOptionsComboBox->setEnabled( false );
}
mDiagramTypeComboBox->addItem( tr( "Pie chart" ) );
mDiagramTypeComboBox->addItem( tr( "Text diagram" ) );
//insert all attributes into the combo boxes
const QgsFieldMap& layerFields = layer->pendingFields();
QgsFieldMap::const_iterator fieldIt = layerFields.constBegin();
for ( ; fieldIt != layerFields.constEnd(); ++fieldIt )
{
mDiagramAttributesComboBox->addItem( fieldIt.value().name(), fieldIt.key() );
if ( fieldIt.value().type() != QVariant::String )
{
mSizeAttributeComboBox->addItem( fieldIt.value().name(), fieldIt.key() );
}
}
mDataDefinedXComboBox->addItem( tr( "None" ), -1 );
for ( fieldIt = layerFields.constBegin(); fieldIt != layerFields.constEnd(); ++fieldIt )
{
mDataDefinedXComboBox->addItem( fieldIt.value().name(), fieldIt.key() );
}
mDataDefinedYComboBox->addItem( tr( "None" ), -1 );
for ( fieldIt = layerFields.constBegin(); fieldIt != layerFields.constEnd(); ++fieldIt )
{
mDataDefinedYComboBox->addItem( fieldIt.value().name(), fieldIt.key() );
}
const QgsDiagramRendererV2* dr = layer->diagramRenderer();
if ( !dr ) //no diagram renderer yet, insert reasonable default
{
mDisplayDiagramsCheckBox->setChecked( false );
mFixedSizeCheckBox->setChecked( true );
mDiagramUnitComboBox->setCurrentIndex( mDiagramUnitComboBox->findText( tr( "MM" ) ) );
mDiagramSizeSpinBox->setValue( 30 );
mScaleDependentDiagramVisibilityCheckBox->setChecked( false );
switch ( layerType )
{
case QGis::Point:
mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( 0 ) );
break;
case QGis::Line:
mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( 3 ) );
mLineOptionsComboBox->setCurrentIndex( mLineOptionsComboBox->findData( 2 ) );
break;
case QGis::Polygon:
mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( 0 ) );
break;
}
mBackgroundColorButton->setColor( QColor( 255, 255, 255, 255 ) );
}
else
{
mDisplayDiagramsCheckBox->setChecked( true );
//single category renderer or interpolated one?
mFixedSizeCheckBox->setChecked( dr->rendererName() == "SingleCategory" );
//assume single category or linearly interpolated diagram renderer for now
QList<QgsDiagramSettings> settingList = dr->diagramSettings();
if ( settingList.size() > 0 )
{
mDiagramFont = settingList.at( 0 ).font;
QSizeF size = settingList.at( 0 ).size;
mBackgroundColorButton->setColor( settingList.at( 0 ).backgroundColor );
mDiagramPenColorButton->setColor( settingList.at( 0 ).penColor );
mPenWidthSpinBox->setValue( settingList.at( 0 ).penWidth );
mDiagramSizeSpinBox->setValue(( size.width() + size.height() ) / 2.0 );
mMinimumDiagramScaleLineEdit->setText( QString::number( settingList.at( 0 ).minScaleDenominator ) );
mMaximumDiagramScaleLineEdit->setText( QString::number( settingList.at( 0 ).maxScaleDenominator ) );
mScaleDependentDiagramVisibilityCheckBox->setChecked( settingList.at( 0 ).minScaleDenominator != -1 &&
settingList.at( 0 ).maxScaleDenominator != -1 );
if ( settingList.at( 0 ).sizeType == QgsDiagramSettings::MM )
{
mDiagramUnitComboBox->setCurrentIndex( 0 );
}
else
{
mDiagramUnitComboBox->setCurrentIndex( 1 );
}
QList< QColor > categoryColors = settingList.at( 0 ).categoryColors;
QList< int > categoryIndices = settingList.at( 0 ).categoryIndices;
QList< int >::const_iterator catIt = categoryIndices.constBegin();
QList< QColor >::const_iterator coIt = categoryColors.constBegin();
for ( ;catIt != categoryIndices.constEnd(); ++catIt, ++coIt )
{
QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
newItem->setText( 0, layer->pendingFields()[*catIt].name() );
newItem->setData( 0, Qt::UserRole, *catIt );
newItem->setBackground( 1, QBrush( *coIt ) );
}
}
if ( dr->rendererName() == "LinearlyInterpolated" )
{
const QgsLinearlyInterpolatedDiagramRenderer* lidr = dynamic_cast<const QgsLinearlyInterpolatedDiagramRenderer*>( dr );
if ( lidr )
{
mDiagramSizeSpinBox->setEnabled( false );
mValueLineEdit->setText( QString::number( lidr->upperValue() ) );
mSizeSpinBox->setValue(( lidr->upperSize().width() + lidr->upperSize().height() ) / 2 );
mSizeAttributeComboBox->setCurrentIndex( mSizeAttributeComboBox->findData( lidr->classificationAttribute() ) );
}
}
QgsDiagramLayerSettings dls = layer->diagramLayerSettings();
mDiagramDistanceSpinBox->setValue( dls.dist );
mPrioritySlider->setValue( dls.priority );
mDataDefinedXComboBox->setCurrentIndex( mDataDefinedXComboBox->findData( dls.xPosColumn ) );
mDataDefinedYComboBox->setCurrentIndex( mDataDefinedYComboBox->findData( dls.yPosColumn ) );
mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( dls.placement ) );
mLineOptionsComboBox->setCurrentIndex( mLineOptionsComboBox->findData( dls.placementFlags ) );
if ( dr->diagram() )
{
QString diagramName = dr->diagram()->diagramName();
if ( diagramName == "Text" )
{
mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findText( tr( "Text diagram" ) ) );
}
else if ( diagramName == "Pie" )
{
mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findText( tr( "Pie chart" ) ) );
}
}
}
QObject::connect( mDiagramAttributesTreeWidget, SIGNAL( itemDoubleClicked( QTreeWidgetItem*, int ) ), this, SLOT( handleDiagramItemDoubleClick( QTreeWidgetItem*, int ) ) );
}

View File

@ -106,6 +106,14 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
void on_pbnSelectEditForm_clicked();
void on_tabWidget_currentChanged( int idx );
void on_buttonBox_helpRequested() { QgsContextHelp::run( metaObject()->className() ); }
void on_mAddCategoryPushButton_clicked();
void on_mRemoveCategoryPushButton_clicked();
void on_mDiagramFontButton_clicked();
void on_mFixedSizeCheckBox_stateChanged( int state );
void on_mScaleDependentDiagramVisibilityCheckBox_stateChanged( int state );
void on_mFindMaximumValueButton_clicked();
void on_mBackgroundColorButton_clicked();
void on_mDiagramPenColorButton_clicked();
void enableLabelOptions( bool theFlag );
void addAttribute();
@ -120,6 +128,9 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
void on_mButtonAddJoin_clicked();
void on_mButtonRemoveJoin_clicked();
/**Set color for diagram category*/
void handleDiagramItemDoubleClick( QTreeWidgetItem * item, int column );
signals:
/** emitted when changes to layer were saved to update legend */
@ -164,10 +175,14 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
QMap<int, QgsVectorLayer::RangeData> mRanges;
QMap<int, QPair<QString, QString> > mCheckedStates;
QFont mDiagramFont;
void updateButtons();
void loadRows();
void setRow( int row, int idx, const QgsField &field );
void initDiagramTab();
/**Requests all overlay plugis from the plugin registry. Useful for inserting their dialogs as new tabs*/
QList<QgsVectorOverlayPlugin*> overlayPlugins() const;

View File

@ -46,6 +46,8 @@ SET(QGIS_CORE_SRCS
qgscontexthelp.cpp
qgscoordinatetransform.cpp
qgsdatasourceuri.cpp
qgsdiagram.cpp
qgsdiagramrendererv2.cpp
qgsdistancearea.cpp
qgsfeature.cpp
qgsfield.cpp

283
src/core/qgsdiagram.cpp Normal file
View File

@ -0,0 +1,283 @@
#include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgsrendercontext.h"
#include <QPainter>
void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
{
if ( s.sizeType == QgsDiagramSettings::MM )
{
pen.setWidthF( s.penWidth * c.scaleFactor() );
}
else
{
pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
}
}
QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
{
if ( s.sizeType == QgsDiagramSettings::MM )
{
return QSizeF( s.size.width() * c.scaleFactor(), s.size.height() * c.scaleFactor() );
}
else
{
return QSizeF( s.size.width() / c.mapToPixel().mapUnitsPerPixel(), s.size.height() / c.mapToPixel().mapUnitsPerPixel() );
}
}
QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c )
{
QFont f = s.font;
if ( s.sizeType == QgsDiagramSettings::MM )
{
f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
}
else
{
f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
}
return f;
}
QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
{
mPen.setWidthF( 2.0 );
mPen.setColor( QColor( 0, 0, 0 ) );
mPen.setCapStyle( Qt::FlatCap );
mBrush.setStyle( Qt::SolidPattern );
}
QgsTextDiagram::~QgsTextDiagram()
{
}
void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
{
return;
}
double scaleDenominator = c.rendererScale();
if (( s.minScaleDenominator != -1 && scaleDenominator < s.minScaleDenominator )
|| ( s.maxScaleDenominator != -1 && scaleDenominator > s.maxScaleDenominator ) )
{
return;
}
//convert from mm / map units to painter units
QSizeF spu = sizePainterUnits( s.size, s, c );
double w = spu.width();
double h = spu.height();
double baseX = position.x();
double baseY = position.y() - h;
QList<QPointF> textPositions; //midpoints for text placement
int nCategories = s.categoryIndices.size();
for ( int i = 0; i < nCategories; ++i )
{
if ( mOrientation == Horizontal )
{
textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0 , baseY + h / 2.0 ) );
}
else //vertical
{
textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) );
}
}
mPen.setColor( s.penColor );
setPenWidth( mPen, s, c );
p->setPen( mPen );
mBrush.setColor( s.backgroundColor );
p->setBrush( mBrush );
//draw shapes and separator lines first
if ( mShape == Circle )
{
p->drawEllipse( baseX, baseY, w, h );
//draw separator lines
QList<QPointF> intersect; //intersections between shape and separation lines
QPointF center( baseX + w / 2.0, baseY + h / 2.0 );
double r1 = w / 2.0; double r2 = h / 2.0;
for ( int i = 1; i < nCategories; ++i )
{
if ( mOrientation == Horizontal )
{
lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect );
}
else //vertical
{
lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect );
}
if ( intersect.size() > 1 )
{
p->drawLine( intersect.at( 0 ), intersect.at( 1 ) );
}
}
}
else if ( mShape == Rectangle )
{
p->drawRect( QRectF( baseX, baseY, w, h ) );
for ( int i = 1; i < nCategories; ++i )
{
if ( mOrientation == Horizontal )
{
p->drawLine( QPointF( baseX + w / nCategories * i , baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) );
}
else
{
p->drawLine( QPointF( baseX, baseY + h / nCategories * i ) , QPointF( baseX + w, baseY + h / nCategories * i ) );
}
}
}
else //triangle
{
QPolygonF triangle;
triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY );
p->drawPolygon( triangle );
QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h );
QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY );
QPointF intersectionPoint1, intersectionPoint2;
for ( int i = 1; i < nCategories; ++i )
{
if ( mOrientation == Horizontal )
{
QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY );
if ( baseX + w / nCategories * i < baseX + w / 2.0 )
{
verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
}
else
{
verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 );
}
p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 );
}
else //vertical
{
QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i );
horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 );
p->drawLine( intersectionPoint1, intersectionPoint2 );
}
}
}
//draw text
QFont sFont = scaledFont( s, c );
QFontMetricsF fontMetrics( sFont );
p->setFont( sFont );
for ( int i = 0; i < textPositions.size(); ++i )
{
QString val = att[ s.categoryIndices.at( i )].toString();
//find out dimensions
double textHeight = fontMetrics.height();
double textWidth = fontMetrics.width( val );
mPen.setColor( s.categoryColors.at( i ) );
p->setPen( mPen );
QPointF position = textPositions.at( i );
p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + textHeight / 2.0 ), val );
}
}
void QgsTextDiagram::lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const
{
result.clear();
double rrx = r1 * r1;
double rry = r2 * r2;
double x21 = lineEnd.x() - lineStart.x();
double y21 = lineEnd.y() - lineStart.y();
double x10 = lineStart.x() - ellipseMid.x();
double y10 = lineStart.y() - ellipseMid.y();
double a = x21 * x21 / rrx + y21 * y21 / rry;
double b = x21 * x10 / rrx + y21 * y10 / rry;
double c = x10 * x10 / rrx + y10 * y10 / rry;
double d = b * b - a * ( c - 1 );
if ( d > 0 )
{
double e = sqrt( d );
double u1 = ( -b - e ) / a;
double u2 = ( -b + e ) / a;
//work with a tolerance of 0.00001 because of limited numerical precision
if ( -0.00001 <= u1 && u1 < 1.00001 )
{
result.push_back( QPointF( lineStart.x() + x21 * u1, lineStart.y() + y21 * u1 ) );
}
if ( -0.00001 <= u2 && u2 <= 1.00001 )
{
result.push_back( QPointF( lineStart.x() + x21 * u2, lineStart.y() + y21 * u2 ) );
}
}
}
QgsPieDiagram::QgsPieDiagram()
{
mCategoryBrush.setStyle( Qt::SolidPattern );
mPen.setStyle( Qt::SolidLine );
}
QgsPieDiagram::~QgsPieDiagram()
{
}
void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
{
QPainter* p = c.painter();
if ( !p )
{
return;
}
//get sum of values
QList<double> values;
double currentVal = 0;
double valSum = 0;
QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
{
currentVal = att[*catIt].toDouble();
values.push_back( currentVal );
valSum += currentVal;
}
//draw the slices
double totalAngle = 0;
double currentAngle;
//convert from mm / map units to painter units
QSizeF spu = sizePainterUnits( s.size, s, c );
double w = spu.width();
double h = spu.height();
double baseX = position.x();
double baseY = position.y() - h;
mPen.setColor( s.penColor );
setPenWidth( mPen, s, c );
p->setPen( mPen );
QList<double>::const_iterator valIt = values.constBegin();
QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
{
currentAngle = *valIt / valSum * 360 * 16;
mCategoryBrush.setColor( *colIt );
p->setBrush( mCategoryBrush );
p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
totalAngle += currentAngle;
}
}

74
src/core/qgsdiagram.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef QGSDIAGRAM_H
#define QGSDIAGRAM_H
#include "qgsfeature.h"
#include <QPen>
class QPainter;
class QPointF;
struct QgsDiagramSettings;
class QgsRenderContext;
/**Base class for all diagram types*/
class QgsDiagram
{
public:
/**Draws the diagram at the given position (in pixel coordinates)*/
virtual void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position ) = 0;
virtual QString diagramName() const = 0;
protected:
void setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c );
QSizeF sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c );
QFont scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c );
};
class QgsTextDiagram: public QgsDiagram
{
public:
enum Shape
{
Circle = 0,
Rectangle,
Triangle
};
enum Orientation
{
Horizontal = 0,
Vertical
};
QgsTextDiagram();
~QgsTextDiagram();
void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QString diagramName() const { return "Text"; }
private:
Orientation mOrientation;
Shape mShape;
QBrush mBrush; //transparent brush
QPen mPen;
/**Calculates intersection points between a line and an ellipse
@return intersection points*/
void lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const;
};
class QgsPieDiagram: public QgsDiagram
{
public:
QgsPieDiagram();
~QgsPieDiagram();
void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position );
QString diagramName() const { return "Pie"; }
private:
QBrush mCategoryBrush;
QPen mPen;
};
#endif // QGSDIAGRAM_H

View File

@ -0,0 +1,342 @@
#include "qgsdiagramrendererv2.h"
#include "qgsdiagram.h"
#include "qgsrendercontext.h"
#include <QDomElement>
#include <QPainter>
void QgsDiagramLayerSettings::readXML( const QDomElement& elem )
{
placement = ( Placement )elem.attribute( "placement" ).toInt();
placementFlags = ( LinePlacementFlags )elem.attribute( "linePlacementFlags" ).toInt();
priority = elem.attribute( "priority" ).toInt();
obstacle = elem.attribute( "obstacle" ).toInt();
dist = elem.attribute( "dist" ).toDouble();
xPosColumn = elem.attribute( "xPosColumn" ).toInt();
yPosColumn = elem.attribute( "yPosColumn" ).toInt();
}
void QgsDiagramLayerSettings::writeXML( QDomElement& layerElem, QDomDocument& doc ) const
{
QDomElement diagramLayerElem = doc.createElement( "DiagramLayerSettings" );
diagramLayerElem.setAttribute( "placement", placement );
diagramLayerElem.setAttribute( "linePlacementFlags", placementFlags );
diagramLayerElem.setAttribute( "priority", priority );
diagramLayerElem.setAttribute( "obstacle", obstacle );
diagramLayerElem.setAttribute( "dist", dist );
diagramLayerElem.setAttribute( "xPosColumn", xPosColumn );
diagramLayerElem.setAttribute( "yPosColumn", yPosColumn );
layerElem.appendChild( diagramLayerElem );
}
void QgsDiagramSettings::readXML( const QDomElement& elem )
{
font.fromString( elem.attribute( "font" ) );
backgroundColor.setNamedColor( elem.attribute( "backgroundColor" ) );
backgroundColor.setAlpha( elem.attribute( "backgroundAlpha" ).toInt() );
size.setWidth( elem.attribute( "width" ).toDouble() );
size.setHeight( elem.attribute( "height" ).toDouble() );
penColor.setNamedColor( elem.attribute( "penColor" ) );
penWidth = elem.attribute( "penWidth" ).toDouble();
minScaleDenominator = elem.attribute( "minScaleDenominator", "-1" ).toDouble();
maxScaleDenominator = elem.attribute( "maxScaleDenominator", "-1" ).toDouble();
//mm vs map units
if ( elem.attribute( "sizeType" ) == "MM" )
{
sizeType = MM;
}
else
{
sizeType = MapUnits;
}
//colors
categoryColors.clear();
QStringList colorList = elem.attribute( "colors" ).split( "/" );
QStringList::const_iterator colorIt = colorList.constBegin();
for ( ; colorIt != colorList.constEnd(); ++colorIt )
{
categoryColors.append( QColor( *colorIt ) );
}
//attribute indices
categoryIndices.clear();
QStringList catList = elem.attribute( "categories" ).split( "/" );
QStringList::const_iterator catIt = catList.constBegin();
for ( ; catIt != catList.constEnd(); ++catIt )
{
categoryIndices.append( catIt->toInt() );
}
}
void QgsDiagramSettings::writeXML( QDomElement& rendererElem, QDomDocument& doc ) const
{
QDomElement categoryElem = doc.createElement( "DiagramCategory" );
categoryElem.setAttribute( "font", font.toString() );
categoryElem.setAttribute( "backgroundColor", backgroundColor.name() );
categoryElem.setAttribute( "backgroundAlpha", backgroundColor.alpha() );
categoryElem.setAttribute( "width", size.width() );
categoryElem.setAttribute( "height", size.height() );
categoryElem.setAttribute( "penColor", penColor.name() );
categoryElem.setAttribute( "penWidth", penWidth );
categoryElem.setAttribute( "minScaleDenominator", minScaleDenominator );
categoryElem.setAttribute( "maxScaleDenominator", maxScaleDenominator );
if ( sizeType == MM )
{
categoryElem.setAttribute( "sizeType", "MM" );
}
else
{
categoryElem.setAttribute( "sizeType", "MapUnits" );
}
QString colors;
for ( int i = 0; i < categoryColors.size(); ++i )
{
if ( i > 0 )
{
colors.append( "/" );
}
colors.append( categoryColors.at( i ).name() );
}
categoryElem.setAttribute( "colors", colors );
QString categories;
for ( int i = 0; i < categoryIndices.size(); ++i )
{
if ( i > 0 )
{
categories.append( "/" );
}
categories.append( QString::number( categoryIndices.at( i ) ) );
}
categoryElem.setAttribute( "categories", categories );
rendererElem.appendChild( categoryElem );
}
QgsDiagramRendererV2::QgsDiagramRendererV2(): mDiagram( 0 )
{
}
QgsDiagramRendererV2::~QgsDiagramRendererV2()
{
delete mDiagram;
}
void QgsDiagramRendererV2::setDiagram( QgsDiagram* d )
{
delete mDiagram;
mDiagram = d;
}
void QgsDiagramRendererV2::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QPointF& pos )
{
if ( !mDiagram )
{
return;
}
QgsDiagramSettings s;
if ( !diagramSettings( att, c, s ) )
{
return;
}
mDiagram->renderDiagram( att, c, s, pos );
}
QSizeF QgsDiagramRendererV2::sizeMapUnits( const QgsAttributeMap& attributes, const QgsRenderContext& c )
{
QgsDiagramSettings s;
if ( !diagramSettings( attributes, c, s ) )
{
return QSizeF();
}
QSizeF size = diagramSize( attributes, c );
if ( s.sizeType == QgsDiagramSettings::MM )
{
convertSizeToMapUnits( size, c );
}
return size;
}
void QgsDiagramRendererV2::convertSizeToMapUnits( QSizeF& size, const QgsRenderContext& context ) const
{
if ( !size.isValid() )
{
return;
}
int dpi = dpiPaintDevice( context.constPainter() );
if ( dpi < 0 )
{
return;
}
double pixelToMap = dpi / 25.4 * context.mapToPixel().mapUnitsPerPixel();
size.rwidth() *= pixelToMap;
size.rheight() *= pixelToMap;
}
int QgsDiagramRendererV2::dpiPaintDevice( const QPainter* painter )
{
if ( painter )
{
QPaintDevice* device = painter->device();
if ( device )
{
return device->logicalDpiX();
}
}
return -1;
}
void QgsDiagramRendererV2::_readXML( const QDomElement& elem )
{
delete mDiagram;
QString diagramType = elem.attribute( "diagramType" );
if ( diagramType == "Pie" )
{
mDiagram = new QgsPieDiagram();
}
else if ( diagramType == "Text" )
{
mDiagram = new QgsTextDiagram();
}
else
{
mDiagram = 0;
}
}
void QgsDiagramRendererV2::_writeXML( QDomElement& rendererElem, QDomDocument& doc ) const
{
if ( mDiagram )
{
rendererElem.setAttribute( "diagramType", mDiagram->diagramName() );
}
}
QgsSingleCategoryDiagramRenderer::QgsSingleCategoryDiagramRenderer(): QgsDiagramRendererV2()
{
}
QgsSingleCategoryDiagramRenderer::~QgsSingleCategoryDiagramRenderer()
{
}
bool QgsSingleCategoryDiagramRenderer::diagramSettings( const QgsAttributeMap&, const QgsRenderContext& c, QgsDiagramSettings& s )
{
s = mSettings;
return true;
}
QList<QgsDiagramSettings> QgsSingleCategoryDiagramRenderer::diagramSettings() const
{
QList<QgsDiagramSettings> settingsList;
settingsList.push_back( mSettings );
return settingsList;
}
void QgsSingleCategoryDiagramRenderer::readXML( const QDomElement& elem )
{
QDomElement categoryElem = elem.firstChildElement( "DiagramCategory" );
if ( categoryElem.isNull() )
{
return;
}
mSettings.readXML( categoryElem );
_readXML( elem );
}
void QgsSingleCategoryDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc ) const
{
QDomElement rendererElem = doc.createElement( "SingleCategoryDiagramRenderer" );
mSettings.writeXML( rendererElem, doc );
_writeXML( rendererElem, doc );
layerElem.appendChild( rendererElem );
}
QgsLinearlyInterpolatedDiagramRenderer::QgsLinearlyInterpolatedDiagramRenderer(): QgsDiagramRendererV2()
{
}
QgsLinearlyInterpolatedDiagramRenderer::~QgsLinearlyInterpolatedDiagramRenderer()
{
}
QList<QgsDiagramSettings> QgsLinearlyInterpolatedDiagramRenderer::diagramSettings() const
{
QList<QgsDiagramSettings> settingsList;
settingsList.push_back( mSettings );
return settingsList;
}
bool QgsLinearlyInterpolatedDiagramRenderer::diagramSettings( const QgsAttributeMap& attributes, const QgsRenderContext& c, QgsDiagramSettings& s )
{
s = mSettings;
s.size = diagramSize( attributes, c );
return true;
}
QList<int> QgsLinearlyInterpolatedDiagramRenderer::diagramAttributes() const
{
QList<int> attributes = mSettings.categoryIndices;
if ( !attributes.contains( mClassificationAttribute ) )
{
attributes.push_back( mClassificationAttribute );
}
return attributes;
}
QSizeF QgsLinearlyInterpolatedDiagramRenderer::diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c )
{
QgsAttributeMap::const_iterator attIt = attributes.find( mClassificationAttribute );
if ( attIt == attributes.constEnd() )
{
return QSizeF(); //zero size if attribute is missing
}
double value = attIt.value().toDouble();
//interpolate size
double ratio = ( value - mLowerValue ) / ( mUpperValue - mLowerValue );
return QSizeF( mUpperSize.width() * ratio + mLowerSize.width() * ( 1 - ratio ),
mUpperSize.height() * ratio + mLowerSize.height() * ( 1 - ratio ) );
}
void QgsLinearlyInterpolatedDiagramRenderer::readXML( const QDomElement& elem )
{
mLowerValue = elem.attribute( "lowerValue" ).toDouble();
mUpperValue = elem.attribute( "upperValue" ).toDouble();
mLowerSize.setWidth( elem.attribute( "lowerWidth" ).toDouble() );
mLowerSize.setHeight( elem.attribute( "lowerHeight" ).toDouble() );
mUpperSize.setWidth( elem.attribute( "upperWidth" ).toDouble() );
mUpperSize.setHeight( elem.attribute( "upperHeight" ).toDouble() );
mClassificationAttribute = elem.attribute( "classificationAttribute" ).toInt();
QDomElement settingsElem = elem.firstChildElement( "DiagramCategory" );
if ( !settingsElem.isNull() )
{
mSettings.readXML( settingsElem );
}
_readXML( elem );
}
void QgsLinearlyInterpolatedDiagramRenderer::writeXML( QDomElement& layerElem, QDomDocument& doc ) const
{
QDomElement rendererElem = doc.createElement( "LinearlyInterpolatedDiagramRenderer" );
rendererElem.setAttribute( "lowerValue", mLowerValue );
rendererElem.setAttribute( "upperValue", mUpperValue );
rendererElem.setAttribute( "lowerWidth", mLowerSize.width() );
rendererElem.setAttribute( "lowerHeight", mLowerSize.height() );
rendererElem.setAttribute( "upperWidth", mUpperSize.width() );
rendererElem.setAttribute( "upperHeight", mUpperSize.height() );
rendererElem.setAttribute( "classificationAttribute", mClassificationAttribute );
mSettings.writeXML( rendererElem, doc );
_writeXML( rendererElem, doc );
layerElem.appendChild( rendererElem );
}

View File

@ -0,0 +1,219 @@
#ifndef QGSDIAGRAMRENDERERV2_H
#define QGSDIAGRAMRENDERERV2_H
#include <QColor>
#include <QFont>
#include <QList>
#include <QPointF>
#include <QSizeF>
#include "pal/layer.h" //pal::Layer
#include "qgsfeature.h"
#include "qgspallabeling.h"
class QgsDiagram;
class QgsDiagramRendererV2;
class QgsFeature;
class QgsRenderContext;
class QDomElement;
struct QgsDiagramLayerSettings
{
//avoid inclusion of QgsPalLabeling
enum Placement
{
AroundPoint, // Point / Polygon
OverPoint, // Point / Polygon
Line, // Line / Polygon
Curved, // Line
Horizontal, // Polygon
Free // Polygon
};
enum LinePlacementFlags
{
OnLine = 1,
AboveLine = 2,
BelowLine = 4,
MapOrientation = 8
};
QgsDiagramLayerSettings(): placement( AroundPoint ), placementFlags( OnLine ), priority( 5 ), obstacle( false ), dist( 0.0 ), renderer( 0 ),
palLayer( 0 ), ct( 0 ), xform( 0 ), xPosColumn( -1 ), yPosColumn( -1 )
{
}
//pal placement properties
Placement placement;
LinePlacementFlags placementFlags;
int priority; // 0 = low, 10 = high
bool obstacle; // whether it's an obstacle
double dist; // distance from the feature (in mm)
QgsDiagramRendererV2* renderer;
//assigned when layer gets prepared
pal::Layer* palLayer;
const QgsCoordinateTransform* ct;
const QgsMapToPixel* xform;
QList<QgsPalGeometry*> geometries;
int xPosColumn; //attribute index for x coordinate (or -1 if position not data defined)
int yPosColumn;//attribute index for y coordinate (or -1 if position not data defined)
void readXML( const QDomElement& elem );
void writeXML( QDomElement& layerElem, QDomDocument& doc ) const;
};
//diagram settings for rendering
struct QgsDiagramSettings
{
enum SizeType
{
MM,
MapUnits
};
QgsDiagramSettings(): minScaleDenominator( -1 ), maxScaleDenominator( -1 ), sizeType( MM )
{}
QFont font;
QList< QColor > categoryColors;
QList< int > categoryIndices;
QSizeF size; //size
SizeType sizeType; //mm or map units
QColor backgroundColor;
QColor penColor;
double penWidth;
//scale range (-1 if no lower / upper bound )
double minScaleDenominator;
double maxScaleDenominator;
void readXML( const QDomElement& elem );
void writeXML( QDomElement& rendererElem, QDomDocument& doc ) const;
};
/**Returns diagram settings for a feature*/
class QgsDiagramRendererV2
{
public:
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 QgsAttributeMap& attributes, const QgsRenderContext& c );
virtual QString rendererName() const = 0;
/**Returns attribute indices needed for diagram rendering*/
virtual QList<int> diagramAttributes() const = 0;
void renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QPointF& pos );
void setDiagram( QgsDiagram* d );
const QgsDiagram* diagram() const { return mDiagram; }
/**Returns list with all diagram settings in the renderer*/
virtual QList<QgsDiagramSettings> diagramSettings() const = 0;
virtual void readXML( const QDomElement& elem ) = 0;
virtual void writeXML( QDomElement& layerElem, QDomDocument& doc ) const = 0;
protected:
/**Returns diagram settings for a feature (or false if the diagram for the feature is not to be rendered). Used internally within renderDiagram()
@param s out: diagram settings for the feature*/
virtual bool diagramSettings( const QgsAttributeMap& att, 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 QgsAttributeMap& attributes, const QgsRenderContext& c ) = 0;
/**Converts size from mm to map units*/
void convertSizeToMapUnits( QSizeF& size, const QgsRenderContext& context ) const;
/**Returns the paint device dpi (or -1 in case of error*/
static int dpiPaintDevice( const QPainter* );
//read / write diagram
void _readXML( const QDomElement& elem );
void _writeXML( QDomElement& rendererElem, QDomDocument& doc ) const;
/**Reference to the object that does the real diagram rendering*/
QgsDiagram* mDiagram;
};
/**Renders the diagrams for all features with the same settings*/
class QgsSingleCategoryDiagramRenderer: public QgsDiagramRendererV2
{
public:
QgsSingleCategoryDiagramRenderer();
~QgsSingleCategoryDiagramRenderer();
QString rendererName() const { return "SingleCategory"; }
QList<int> diagramAttributes() const { return mSettings.categoryIndices; }
void setDiagramSettings( const QgsDiagramSettings& s ) { mSettings = s; }
QList<QgsDiagramSettings> diagramSettings() const;
void readXML( const QDomElement& elem );
void writeXML( QDomElement& layerElem, QDomDocument& doc ) const;
protected:
bool diagramSettings( const QgsAttributeMap&, const QgsRenderContext& c, QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c ) { return mSettings.size; }
private:
QgsDiagramSettings mSettings;
};
class QgsLinearlyInterpolatedDiagramRenderer: public QgsDiagramRendererV2
{
public:
QgsLinearlyInterpolatedDiagramRenderer();
~QgsLinearlyInterpolatedDiagramRenderer();
/**Returns list with all diagram settings in the renderer*/
QList<QgsDiagramSettings> diagramSettings() const;
void setDiagramSettings( const QgsDiagramSettings& s ) { mSettings = s; }
QList<int> diagramAttributes() const;
QString rendererName() const { return "LinearlyInterpolated"; }
void setLowerValue( double val ) { mLowerValue = val; }
double lowerValue() const { return mLowerValue; }
void setUpperValue( double val ) { mUpperValue = val; }
double upperValue() const { return mUpperValue; }
void setLowerSize( QSizeF s ) { mLowerSize = s; }
QSizeF lowerSize() const { return mLowerSize; }
void setUpperSize( QSizeF s ) { mUpperSize = s; }
QSizeF upperSize() const { return mUpperSize; }
int classificationAttribute() const { return mClassificationAttribute; }
void setClassificationAttribute( int index ) { mClassificationAttribute = index; }
void readXML( const QDomElement& elem );
void writeXML( QDomElement& layerElem, QDomDocument& doc ) const;
protected:
bool diagramSettings( const QgsAttributeMap&, const QgsRenderContext& c, QgsDiagramSettings& s );
QSizeF diagramSize( const QgsAttributeMap& attributes, const QgsRenderContext& c );
private:
QgsDiagramSettings mSettings;
QSizeF mLowerSize;
QSizeF mUpperSize;
double mLowerValue;
double mUpperValue;
/**Index of the classification attribute*/
int mClassificationAttribute;
};
#endif // QGSDIAGRAMRENDERERV2_H

View File

@ -27,7 +27,7 @@ void QgsLabelSearchTree::label( const QgsPoint& p, QList<QgsLabelPosition*>& pos
posList = mSearchResults;
}
bool QgsLabelSearchTree::insertLabel( LabelPosition* labelPos, int featureId, const QString& layerName )
bool QgsLabelSearchTree::insertLabel( LabelPosition* labelPos, int featureId, const QString& layerName, bool diagram )
{
if ( !labelPos )
{
@ -44,7 +44,7 @@ bool QgsLabelSearchTree::insertLabel( LabelPosition* labelPos, int featureId, co
cornerPoints.push_back( QgsPoint( labelPos->getX( i ), labelPos->getY( i ) ) );
}
QgsLabelPosition* newEntry = new QgsLabelPosition( featureId, labelPos->getAlpha(), cornerPoints, QgsRectangle( c_min[0], c_min[1], c_max[0], c_max[1] ),
labelPos->getWidth(), labelPos->getHeight(), layerName, labelPos->getUpsideDown() );
labelPos->getWidth(), labelPos->getHeight(), layerName, labelPos->getUpsideDown(), diagram );
mSpatialIndex.Insert( c_min, c_max, newEntry );
return true;
}

View File

@ -44,7 +44,7 @@ class CORE_EXPORT QgsLabelSearchTree
/**Inserts label position. Does not take ownership of labelPos
@return true in case of success*/
bool insertLabel( LabelPosition* labelPos, int featureId, const QString& layerName );
bool insertLabel( LabelPosition* labelPos, int featureId, const QString& layerName, bool diagram = false );
private:
RTree<QgsLabelPosition*, double, 2, double> mSpatialIndex;

View File

@ -39,11 +39,13 @@ class QgsOverlayObjectPositionManager;
class QgsVectorLayer;
class QgsFeature;
struct QgsDiagramLayerSettings;
struct CORE_EXPORT QgsLabelPosition
{
QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, bool upside_down ):
featureId( id ), rotation( r ), cornerPoints( corners ), labelRect( rect ), width( w ), height( h ), layerID( layer ), upsideDown( upside_down ) {}
QgsLabelPosition(): featureId( -1 ), rotation( 0 ), labelRect( QgsRectangle() ), width( 0 ), height( 0 ), layerID( "" ), upsideDown( false ) {}
QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, bool upside_down, bool diagram = false ):
featureId( id ), rotation( r ), cornerPoints( corners ), labelRect( rect ), width( w ), height( h ), layerID( layer ), upsideDown( upside_down ), isDiagram( diagram ) {}
QgsLabelPosition(): featureId( -1 ), rotation( 0 ), labelRect( QgsRectangle() ), width( 0 ), height( 0 ), layerID( "" ), upsideDown( false ), isDiagram( false ) {}
int featureId;
double rotation;
QVector< QgsPoint > cornerPoints;
@ -52,6 +54,7 @@ struct CORE_EXPORT QgsLabelPosition
double height;
QString layerID;
bool upsideDown;
bool isDiagram;
};
/** Labeling engine interface.
@ -70,8 +73,12 @@ class QgsLabelingEngineInterface
//! called when starting rendering of a layer
//! @note: this method was added in version 1.6
virtual int prepareLayer( QgsVectorLayer* layer, QSet<int>& attrIndices, QgsRenderContext& ctx ) = 0;
//! adds a diagram layer to the labeling engine
virtual int addDiagramLayer( QgsVectorLayer* layer, QgsDiagramLayerSettings& s ) {};
//! called for every feature
virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() ) = 0;
//! called for every diagram feature
virtual void registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() ) {};
//! called when the map is drawn and labels should be placed
virtual void drawLabeling( QgsRenderContext& context ) = 0;
//! called when we're done with rendering

View File

@ -38,6 +38,8 @@
#include <QTime>
#include <QPainter>
#include "qgsdiagram.h"
#include "qgsdiagramrendererv2.h"
#include "qgslabelsearchtree.h"
#include <qgslogger.h>
#include <qgsvectorlayer.h>
@ -53,7 +55,7 @@ using namespace pal;
class QgsPalGeometry : public PalGeometry
{
public:
QgsPalGeometry( int id, QString text, GEOSGeometry* g ): mG( g ), mText( text ), mId( id ), mInfo( NULL )
QgsPalGeometry( int id, QString text, GEOSGeometry* g ): mG( g ), mText( text ), mId( id ), mInfo( NULL ), mIsDiagram( false )
{
mStrId = QByteArray::number( id );
}
@ -99,14 +101,24 @@ class QgsPalGeometry : public PalGeometry
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& dataDefinedValues() const { return mDataDefinedValues; }
void addDataDefinedValue( QgsPalLayerSettings::DataDefinedProperties p, QVariant v ) { mDataDefinedValues.insert( p, v ); }
void setIsDiagram( bool d ) { mIsDiagram = d; }
bool isDiagram() const { return mIsDiagram; }
void addDiagramAttribute( int index, QVariant value ) { mDiagramAttributes.insert( index, value ); }
const QgsAttributeMap& diagramAttributes() { return mDiagramAttributes; }
protected:
GEOSGeometry* mG;
QString mText;
QByteArray mStrId;
int mId;
LabelInfo* mInfo;
bool mIsDiagram;
/**Stores attribute values for data defined properties*/
QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > mDataDefinedValues;
/**Stores attribute values for diagram rendering*/
QgsAttributeMap mDiagramAttributes;
};
// -------------
@ -413,7 +425,6 @@ void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString t
labelY = qAbs( ptSize.y() - ptZero.y() );
}
void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext& context )
{
QString labelText = f.attributeMap()[fieldIndex].toString();
@ -742,6 +753,20 @@ int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QSet<int>& attrIndices,
return 1; // init successful
}
int QgsPalLabeling::addDiagramLayer( QgsVectorLayer* layer, QgsDiagramLayerSettings& s )
{
Layer* l = mPal->addLayer( layer->id().append( "d" ).toLocal8Bit().data(), -1, -1, pal::Arrangement( s.placement ), METER, s.priority, s.obstacle, true, true );
l->setArrangementFlags( s.placementFlags );
s.palLayer = l;
if ( mMapRenderer->hasCrsTransformEnabled() )
s.ct = new QgsCoordinateTransform( layer->srs(), mMapRenderer->destinationSrs() );
else
s.ct = NULL;
s.xform = mMapRenderer->coordinateTransform();
mActiveDiagramLayers.insert( layer, s );
return 1;
}
void QgsPalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context )
{
@ -749,6 +774,94 @@ void QgsPalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f, cons
lyr.registerFeature( f, context );
}
void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context )
{
//get diagram layer settings, diagram renderer
QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator layerIt = mActiveDiagramLayers.find( layer );
if ( layerIt == mActiveDiagramLayers.constEnd() )
{
return;
}
//convert geom to geos
QgsGeometry* geom = feat.geometry();
if ( layerIt.value().ct ) // reproject the geometry if necessary
{
geom->transform( *( layerIt.value().ct ) );
}
GEOSGeometry* geos_geom = geom->asGeos();
if ( geos_geom == 0 )
{
return; // invalid geometry
}
//create PALGeometry with diagram = true
QgsPalGeometry* lbl = new QgsPalGeometry( feat.id(), "", GEOSGeom_clone( geos_geom ) );
lbl->setIsDiagram( true );
// record the created geometry - it will be deleted at the end.
layerIt.value().geometries.append( lbl );
double diagramWidth = 0;
double diagramHeight = 0;
QgsDiagramRendererV2* dr = layerIt.value().renderer;
if ( dr )
{
QSizeF diagSize = dr->sizeMapUnits( feat.attributeMap(), context );
if ( diagSize.isValid() )
{
diagramWidth = diagSize.width();
diagramHeight = diagSize.height();
}
//append the diagram attributes to lbl
QList<int> diagramAttrib = dr->diagramAttributes();
QList<int>::const_iterator diagAttIt = diagramAttrib.constBegin();
for ( ; diagAttIt != diagramAttrib.constEnd(); ++diagAttIt )
{
lbl->addDiagramAttribute( *diagAttIt, feat.attributeMap()[*diagAttIt] );
}
}
// register feature to the layer
int ddColX = layerIt.value().xPosColumn;
int ddColY = layerIt.value().yPosColumn;
double ddPosX = 0.0;
double ddPosY = 0.0;
bool ddPos = ( ddColX >= 0 && ddColY >= 0 );
if ( ddPos )
{
bool posXOk, posYOk;
//data defined diagram position is always centered
ddPosX = feat.attributeMap()[ddColX].toDouble( &posXOk ) - diagramWidth / 2.0;
ddPosY = feat.attributeMap()[ddColY].toDouble( &posYOk ) - diagramHeight / 2.0;
if ( !posXOk || !posYOk )
{
ddPos = false;
}
}
try
{
if ( !layerIt.value().palLayer->registerFeature( lbl->strId(), lbl, diagramWidth, diagramHeight, "", ddPosX, ddPosY, ddPos ) )
{
return;
}
}
catch ( std::exception* e )
{
QgsDebugMsg( QString( "Ignoring feature %1 due PAL exception: " ).arg( feat.id() ) + QString::fromLatin1( e->what() ) );
return;
}
pal::Feature* palFeat = layerIt.value().palLayer->getFeature( lbl->strId() );
QgsPoint ptZero = layerIt.value().xform->toMapCoordinates( 0, 0 );
QgsPoint ptOne = layerIt.value().xform->toMapCoordinates( 1, 0 );
palFeat->setDistLabel( qAbs( ptOne.x() - ptZero.x() ) * layerIt.value().dist );
}
void QgsPalLabeling::init( QgsMapRenderer* mr )
{
@ -778,6 +891,7 @@ void QgsPalLabeling::init( QgsMapRenderer* mr )
mPal->setPolyP( mCandPolygon );
mActiveLayers.clear();
mActiveDiagramLayers.clear();
}
void QgsPalLabeling::exit()
@ -866,18 +980,42 @@ void QgsPalLabeling::drawLabeling( QgsRenderContext& context )
std::list<LabelPosition*>::iterator it = labels->begin();
for ( ; it != labels->end(); ++it )
{
const QgsPalLayerSettings& lyr = layer(( *it )->getLayerName() );
QFont fontForLabel = lyr.textFont;
QColor fontColor = lyr.textColor;
double bufferSize = lyr.bufferSize;
QColor bufferColor = lyr.bufferColor;
QgsPalGeometry* palGeometry = dynamic_cast< QgsPalGeometry* >(( *it )->getFeaturePart()->getUserGeometry() );
if ( !palGeometry )
{
continue;
}
if ( palGeometry->isDiagram() )
{
//render diagram
QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator dit = mActiveDiagramLayers.begin();
for ( dit = mActiveDiagramLayers.begin(); dit != mActiveDiagramLayers.end(); ++dit )
{
if ( dit.key() && dit.key()->id().append( "d" ) == ( *it )->getLayerName() )
{
QgsPoint outPt = xform->transform(( *it )->getX(), ( *it )->getY() );
dit.value().renderer->renderDiagram( palGeometry->diagramAttributes(), context, QPointF( outPt.x(), outPt.y() ) );
}
}
//insert into label search tree to manipulate position interactively
if ( mLabelSearchTree )
{
//for diagrams, remove the additional 'd' at the end of the layer id
QString layerId = ( *it )->getLayerName();
layerId.chop( 1 );
mLabelSearchTree->insertLabel( *it, QString( palGeometry->strId() ).toInt(), layerId, true );
}
continue;
}
const QgsPalLayerSettings& lyr = layer(( *it )->getLayerName() );
QFont fontForLabel = lyr.textFont;
QColor fontColor = lyr.textColor;
double bufferSize = lyr.bufferSize;
QColor bufferColor = lyr.bufferColor;
//apply data defined settings for the label
//font size
QVariant dataDefinedSize = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Size );
@ -968,9 +1106,18 @@ void QgsPalLabeling::drawLabeling( QgsRenderContext& context )
delete *git;
lyr.geometries.clear();
}
// labeling is done: clear the active layers hashtable
// mActiveLayers.clear();
//delete all allocated geometries for diagrams
QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator dIt = mActiveDiagramLayers.begin();
for ( ; dIt != mActiveDiagramLayers.end(); ++dIt )
{
QgsDiagramLayerSettings& dls = dIt.value();
for ( QList<QgsPalGeometry*>::iterator git = dls.geometries.begin(); git != dls.geometries.end(); ++git )
{
delete *git;
}
dls.geometries.clear();
}
}
QList<QgsLabelPosition> QgsPalLabeling::labelsAtPosition( const QgsPoint& p )

View File

@ -23,14 +23,17 @@
class QFontMetricsF;
class QPainter;
class QgsGeometry;
class QgsMapRenderer;
class QgsRectangle;
class QgsCoordinateTransform;
class QgsLabelSearchTree;
struct QgsDiagramLayerSettings;
#include <QString>
#include <QFont>
#include <QColor>
#include <QHash>
#include <QList>
#include <QRectF>
@ -45,9 +48,10 @@ class QgsMapToPixel;
class QgsFeature;
#include "qgspoint.h"
#include "qgsvectorlayer.h" // definition of QgsLabelingEngineInterface
#include "qgsmaprenderer.h" // definition of QgsLabelingEngineInterface
class QgsPalGeometry;
class QgsVectorLayer;
class CORE_EXPORT QgsPalLayerSettings
{
@ -195,8 +199,11 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
virtual bool willUseLayer( QgsVectorLayer* layer );
//! hook called when drawing layer before issuing select()
virtual int prepareLayer( QgsVectorLayer* layer, QSet<int>& attrIndices, QgsRenderContext& ctx );
//! adds a diagram layer to the labeling engine
virtual int addDiagramLayer( QgsVectorLayer* layer, QgsDiagramLayerSettings& s );
//! hook called when drawing for every feature in a layer
virtual void registerFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() );
virtual void registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context = QgsRenderContext() );
//! called when the map is drawn and labels should be placed
virtual void drawLabeling( QgsRenderContext& context );
//! called when we're done with rendering
@ -220,6 +227,8 @@ class CORE_EXPORT QgsPalLabeling : public QgsLabelingEngineInterface
protected:
// hashtable of layer settings, being filled during labeling
QHash<QgsVectorLayer*, QgsPalLayerSettings> mActiveLayers;
// hashtable of active diagram layers
QHash<QgsVectorLayer*, QgsDiagramLayerSettings> mActiveDiagramLayers;
QgsPalLayerSettings mInvalidLayerSettings;
QgsMapRenderer* mMapRenderer;

View File

@ -41,6 +41,7 @@ class CORE_EXPORT QgsRenderContext
//getters
QPainter* painter() {return mPainter;}
const QPainter* constPainter() const { return mPainter; }
const QgsCoordinateTransform* coordinateTransform() const {return mCoordTransform;}

View File

@ -25,8 +25,13 @@ class QTextCodec;
//QGIS Includes
#include "qgis.h"
#include "qgsdataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgsrectangle.h"
typedef QList<int> QgsAttributeList;
typedef QSet<int> QgsFeatureIds;
typedef QSet<int> QgsAttributeIds;
/** \ingroup core
* This is the base class for vector data providers.

View File

@ -111,7 +111,8 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
mLabelOn( false ),
mVertexMarkerOnlyForSelection( false ),
mFetching( false ),
mJoinBuffer( 0 )
mJoinBuffer( 0 ),
mDiagramRenderer( 0 )
{
mActions = new QgsAttributeAction( this );
@ -754,8 +755,17 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab
mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker );
// labeling - register feature
if ( labeling && mRendererV2->symbolForFeature( fet ) != NULL )
rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
if ( mRendererV2->symbolForFeature( fet ) != NULL )
{
if ( labeling )
{
rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
}
if ( mDiagramRenderer )
{
rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
}
}
if ( mEditable )
{
@ -821,8 +831,17 @@ void QgsVectorLayer::drawRendererV2Levels( QgsRenderContext& rendererContext, bo
}
features[sym].append( fet );
if ( labeling && mRendererV2->symbolForFeature( fet ) != NULL )
rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
if ( mRendererV2->symbolForFeature( fet ) != NULL )
{
if ( labeling )
{
rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
}
if ( mDiagramRenderer )
{
rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
}
}
if ( mEditable )
{
@ -949,22 +968,8 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
}
bool labeling = false;
if ( rendererContext.labelingEngine() )
{
QSet<int> attrIndex;
if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) )
{
QSet<int>::const_iterator attIt = attrIndex.constBegin();
for ( ; attIt != attrIndex.constEnd(); ++attIt )
{
if ( !attributes.contains( *attIt ) )
{
attributes << *attIt;
}
}
labeling = true;
}
}
//register label and diagram layer to the labeling engine
prepareLabelingAndDiagrams( rendererContext, attributes, labeling );
select( attributes, rendererContext.extent() );
@ -1011,22 +1016,7 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
QgsAttributeList attributes = mRenderer->classificationAttributes();
bool labeling = false;
if ( rendererContext.labelingEngine() )
{
QSet<int> attrIndex;
if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) )
{
QSet<int>::const_iterator attIt = attrIndex.constBegin();
for ( ; attIt != attrIndex.constEnd(); ++attIt )
{
if ( !attributes.contains( *attIt ) )
{
attributes << *attIt;
}
}
labeling = true;
}
}
prepareLabelingAndDiagrams( rendererContext, attributes, labeling );
select( attributes, rendererContext.extent() );
@ -1092,11 +1082,17 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )
//double scale = rendererContext.scaleFactor() / markerScaleFactor;
drawFeature( rendererContext, fet, &marker );
if ( labeling && mRenderer->willRenderFeature( &fet ) )
if ( mRenderer->willRenderFeature( &fet ) )
{
rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
if ( labeling )
{
rendererContext.labelingEngine()->registerFeature( this, fet, rendererContext );
}
if ( mDiagramRenderer )
{
rendererContext.labelingEngine()->registerDiagramFeature( this, fet, rendererContext );
}
}
++featureCount;
}
}
@ -1303,6 +1299,12 @@ void QgsVectorLayer::setRenderer( QgsRenderer * r )
}
}
void QgsVectorLayer::setDiagramRenderer( QgsDiagramRendererV2* r )
{
delete mDiagramRenderer;
mDiagramRenderer = r;
}
QGis::GeometryType QgsVectorLayer::geometryType() const
{
if ( mDataProvider )
@ -2937,6 +2939,30 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
QgsDebugMsg( "calling readXML" );
mLabel->readXML( labelattributesnode );
}
//diagram renderer and diagram layer settings
delete mDiagramRenderer; mDiagramRenderer = 0;
QDomElement singleCatDiagramElem = node.firstChildElement( "SingleCategoryDiagramRenderer" );
if ( !singleCatDiagramElem.isNull() )
{
mDiagramRenderer = new QgsSingleCategoryDiagramRenderer();
mDiagramRenderer->readXML( singleCatDiagramElem );
}
QDomElement linearDiagramElem = node.firstChildElement( "LinearlyInterpolatedDiagramRenderer" );
if ( !linearDiagramElem.isNull() )
{
mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer();
mDiagramRenderer->readXML( linearDiagramElem );
}
if ( mDiagramRenderer )
{
QDomElement diagramSettingsElem = node.firstChildElement( "DiagramLayerSettings" );
if ( !diagramSettingsElem.isNull() )
{
mDiagramLayerSettings.readXML( diagramSettingsElem );
}
}
}
// process the attribute actions
@ -3109,6 +3135,12 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
}
mLabel->writeXML( node, doc );
if ( mDiagramRenderer )
{
mDiagramRenderer->writeXML( mapLayerNode, doc );
mDiagramLayerSettings.writeXML( mapLayerNode, doc );
}
}
//edit types
@ -5131,3 +5163,49 @@ void QgsVectorLayer::updateAttributeMapIndex( QgsAttributeMap& map, int oldIndex
map.insert( newIndex, it.value() );
map.remove( oldIndex );
}
void QgsVectorLayer::prepareLabelingAndDiagrams( QgsRenderContext& rendererContext, QgsAttributeList& attributes, bool& labeling )
{
if ( rendererContext.labelingEngine() )
{
QSet<int> attrIndex;
if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) )
{
QSet<int>::const_iterator attIt = attrIndex.constBegin();
for ( ; attIt != attrIndex.constEnd(); ++attIt )
{
if ( !attributes.contains( *attIt ) )
{
attributes << *attIt;
}
}
labeling = true;
}
//register diagram layers
if ( mDiagramRenderer )
{
mDiagramLayerSettings.renderer = mDiagramRenderer;
rendererContext.labelingEngine()->addDiagramLayer( this, mDiagramLayerSettings );
//add attributes needed by the diagram renderer
QList<int> att = mDiagramRenderer->diagramAttributes();
QList<int>::const_iterator attIt = att.constBegin();
for ( ; attIt != att.constEnd(); ++attIt )
{
if ( !attributes.contains( *attIt ) )
{
attributes << *attIt;
}
}
//and the ones needed for data defined diagram positions
if ( mDiagramLayerSettings.xPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings.xPosColumn ) )
{
attributes << mDiagramLayerSettings.xPosColumn;
}
if ( mDiagramLayerSettings.yPosColumn >= 0 && !attributes.contains( mDiagramLayerSettings.yPosColumn ) )
{
attributes << mDiagramLayerSettings.yPosColumn;
}
}
}
}

View File

@ -24,7 +24,10 @@
#include <QList>
#include <QStringList>
#include "qgis.h"
#include "qgsdiagramrendererv2.h"
#include "qgsmaplayer.h"
#include "qgsfeature.h"
#include "qgssnapper.h"
@ -48,7 +51,6 @@ class QgsVectorOverlay;
class QgsSingleSymbolRendererV2;
class QgsRectangle;
class QgsVectorLayerJoinBuffer;
class QgsFeatureRendererV2;
typedef QList<int> QgsAttributeList;
@ -208,6 +210,13 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/** Sets the renderer. If a renderer is already present, it is deleted */
void setRenderer( QgsRenderer * r );
/** Sets diagram rendering object (takes ownership) */
void setDiagramRenderer( QgsDiagramRendererV2* r );
const QgsDiagramRendererV2* diagramRenderer() const { return mDiagramRenderer; }
void setDiagramLayerSettings( const QgsDiagramLayerSettings& s ) { mDiagramLayerSettings = s; }
QgsDiagramLayerSettings diagramLayerSettings() const { return mDiagramLayerSettings; }
/** Return renderer V2.
* @note added in 1.4 */
QgsFeatureRendererV2* rendererV2();
@ -804,6 +813,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/**Updates an index in an attribute map to a new value (usually necessary because of a join operation)*/
void updateAttributeMapIndex( QgsAttributeMap& map, int oldIndex, int newIndex ) const;
/**Registers label and diagram layer
@param attList attributes needed for labeling and diagrams will be added to the list
@param labeling out: true if there will be labeling (ng) for this layer*/
void prepareLabelingAndDiagrams( QgsRenderContext& rendererContext, QgsAttributeList& attributes, bool& labeling );
private: // Private attributes
/** Update threshold for drawing features as they are read. A value of zero indicates
@ -931,6 +945,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
//stores information about joined layers
QgsVectorLayerJoinBuffer* mJoinBuffer;
//diagram rendering object. 0 if diagram drawing is disabled
QgsDiagramRendererV2* mDiagramRenderer;
//stores infos about diagram placement (placement type, priority, position distance)
QgsDiagramLayerSettings mDiagramLayerSettings;
};
#endif

View File

@ -16,6 +16,7 @@
#include <qgsmapcanvas.h>
#include <qgsmaplayer.h>
#include <qgsvectordataprovider.h>
#include <qgsvectorlayer.h>
#include <qgsfield.h>
// Qt includes

View File

@ -1,5 +1,6 @@
SUBDIRS (copyright_label
delimited_text
delimited_text
diagram_overlay
interpolation
north_arrow
scale_bar
@ -7,7 +8,6 @@ SUBDIRS (copyright_label
raster_terrain_analysis
coordinate_capture
dxf2shp_converter
diagram_overlay
evis
point_displacement_renderer
spatialquery

View File

@ -22,6 +22,7 @@
#include "qgisinterface.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsvectorlayer.h"
#include "qgsvertexmarker.h"
#include <QMouseEvent>

View File

@ -37,7 +37,6 @@
#include "qgslogger.h"
#include "qgsmessageoutput.h"
#include "qgsrectangle.h"
#include "qgscoordinatereferencesystem.h"
#include "qgis.h"
static const QString TEXT_PROVIDER_KEY = "delimitedtext";

View File

@ -18,6 +18,7 @@
/* $Id$ */
#include "qgsvectordataprovider.h"
#include "qgscoordinatereferencesystem.h"
#include <QStringList>

View File

@ -21,6 +21,7 @@ class QgsField;
#include <QDateTime>
#include "qgsvectordataprovider.h"
#include <vector>
/* Update.
* Vectors are updated (reloaded) if:

View File

@ -14,6 +14,7 @@
***************************************************************************/
#include "qgsvectordataprovider.h"
#include "qgscoordinatereferencesystem.h"
typedef QMap<int, QgsFeature> QgsFeatureMap;

View File

@ -21,6 +21,7 @@
#include "qgsgeometry.h"
#include "qgslogger.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsapplication.h"
#include <QFileInfo>

View File

@ -17,6 +17,7 @@
#include <sqlite3.h>
#include <QFile>
class QgsVectorLayer;
/**
* Quantum GIS provider for OpenStreetMap data.

View File

@ -41,6 +41,7 @@
#include "qgslogger.h"
#include "qgscredentials.h"
#include <cassert>
const QString POSTGRES_KEY = "postgres";
const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";

View File

@ -19,6 +19,7 @@
#ifndef QGSSQLANYWHEREPROVIDER_H
#define QGSSQLANYWHEREPROVIDER_H
#include "qgscoordinatereferencesystem.h"
#include "qgsdatasourceuri.h"
#include "qgsvectordataprovider.h"
#include "qgsrectangle.h"

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>591</width>
<height>426</height>
<width>670</width>
<height>625</height>
</rect>
</property>
<property name="windowTitle">
@ -21,7 +21,7 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0" colspan="2">
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pbnLoadDefaultStyle">
@ -53,7 +53,7 @@
</item>
</layout>
</item>
<item row="2" column="0" colspan="2">
<item row="2" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -63,7 +63,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
@ -372,8 +372,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>432</width>
<height>419</height>
<width>648</width>
<height>501</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_3">
@ -679,11 +679,522 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="mDiagramPage">
<attribute name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/propertyicons/diagram.png</normaloff>:/images/themes/default/propertyicons/diagram.png</iconset>
</attribute>
<attribute name="title">
<string>Diagrams</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_14">
<item row="0" column="0" colspan="2">
<widget class="QCheckBox" name="mDisplayDiagramsCheckBox">
<property name="text">
<string>Display diagrams</string>
</property>
</widget>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="_2">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="mTypeLabel">
<property name="text">
<string>Diagram type</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mDiagramTypeComboBox"/>
</item>
</layout>
</item>
<item row="0" column="3" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="mPriorityLabel">
<property name="text">
<string>Priority:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mPriorityLowLabel">
<property name="text">
<string>Low</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="mPrioritySlider">
<property name="maximum">
<number>10</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="invertedControls">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mPriorityHighLabel">
<property name="text">
<string>High</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="6">
<widget class="QGroupBox" name="mAppearanceGroupBox">
<property name="title">
<string>Appearance</string>
</property>
<layout class="QGridLayout" name="gridLayout_13">
<item row="0" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QCheckBox" name="mScaleDependentDiagramVisibilityCheckBox">
<property name="text">
<string>Scale dependent visibility</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mMinimumDiagramScaleLabel">
<property name="text">
<string>Minimum</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mMinimumDiagramScaleLineEdit"/>
</item>
<item>
<widget class="QLabel" name="mMaximumDiagramScaleLabel">
<property name="text">
<string>Maximum</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mMaximumDiagramScaleLineEdit"/>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QLabel" name="mBackgroundColorLabel">
<property name="text">
<string>Background color</string>
</property>
</widget>
</item>
<item>
<widget class="QgsColorButton" name="mBackgroundColorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>25</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QLabel" name="mPenColorLabel">
<property name="text">
<string>Pen color</string>
</property>
</widget>
</item>
<item>
<widget class="QgsColorButton" name="mDiagramPenColorButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>25</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_16">
<item>
<widget class="QLabel" name="mPenWidthLabel">
<property name="text">
<string>Pen width</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mPenWidthSpinBox">
<property name="maximum">
<double>99999.990000000005239</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="mDiagramFontButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Font...</string>
</property>
</widget>
</item>
</layout>
<zorder></zorder>
<zorder></zorder>
<zorder>mDiagramFontButton</zorder>
<zorder></zorder>
<zorder>mPenWidthSpinBox</zorder>
<zorder>mPenWidthLabel</zorder>
<zorder>mPenWidthLabel</zorder>
</widget>
</item>
<item row="2" column="0" colspan="6">
<widget class="QGroupBox" name="mSizeGroupBox">
<property name="title">
<string>Size</string>
</property>
<layout class="QGridLayout" name="gridLayout_12">
<item row="0" column="0">
<widget class="QCheckBox" name="mFixedSizeCheckBox">
<property name="text">
<string>Fixed size</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="mDiagramSizeSpinBox">
<property name="maximum">
<double>9999999.990000000223517</double>
</property>
</widget>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>335</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0" colspan="4">
<widget class="QLabel" name="mLinearlyScalingLabel">
<property name="text">
<string>Scale linearly between 0 and the following attribute value / diagram size:</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<layout class="QHBoxLayout" name="mLinearlyScalingLayout">
<item>
<widget class="QLabel" name="mSizeAttributeLabel">
<property name="text">
<string>Attribute</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mSizeAttributeComboBox"/>
</item>
<item>
<widget class="QPushButton" name="mFindMaximumValueButton">
<property name="text">
<string>Find maximum value</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mValueLineEdit"/>
</item>
<item>
<widget class="QLabel" name="mSizeLabel">
<property name="text">
<string>Size</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="mSizeSpinBox">
<property name="maximum">
<number>10000000</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLabel" name="mDiagramUnitsLabel">
<property name="text">
<string>Size units</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mDiagramUnitComboBox"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="3" column="0" colspan="6">
<widget class="QGroupBox" name="mPlacementGroupBox">
<property name="title">
<string>Position</string>
</property>
<layout class="QGridLayout" name="gridLayout_11">
<item row="0" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="mPlacementLabel">
<property name="text">
<string>Placement</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mPlacementComboBox"/>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="mLineOptionsLabel">
<property name="text">
<string>Line Options</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mLineOptionsComboBox"/>
</item>
</layout>
</item>
<item row="0" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="mDiagramDistanceLabel">
<property name="text">
<string>Distance</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="mDiagramDistanceSpinBox"/>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mDataDefinedPositionLabel">
<property name="text">
<string>Date defined position</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="mXPosColLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mDataDefinedXComboBox"/>
</item>
</layout>
</item>
<item row="1" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="mYPosColLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>y</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="mDataDefinedYComboBox"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="mAttributesLabel">
<property name="text">
<string>Attributes</string>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QComboBox" name="mDiagramAttributesComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="4" column="3">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>241</width>
<height>23</height>
</size>
</property>
</spacer>
</item>
<item row="4" column="4">
<widget class="QPushButton" name="mRemoveCategoryPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/symbologyRemove.png</normaloff>:/images/themes/default/symbologyRemove.png</iconset>
</property>
</widget>
</item>
<item row="4" column="5">
<widget class="QPushButton" name="mAddCategoryPushButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/default/symbologyAdd.png</normaloff>:/images/themes/default/symbologyAdd.png</iconset>
</property>
</widget>
</item>
<item row="5" column="0" colspan="6">
<widget class="QTreeWidget" name="mDiagramAttributesTreeWidget">
<property name="columnCount">
<number>2</number>
</property>
<column>
<property name="text">
<string>Attribute</string>
</property>
</column>
<column>
<property name="text">
<string>Color</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsColorButton</class>
<extends>QToolButton</extends>
<header>qgscolorbutton.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>txtDisplayName</tabstop>
<tabstop>displayFieldComboBox</tabstop>