From c3ac6df9ee74524de71c3dfcd47f194de126a58c Mon Sep 17 00:00:00 2001 From: mhugent Date: Tue, 15 Mar 2011 16:43:23 +0000 Subject: [PATCH] [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 --- python/core/qgsdiagramrendererv2.sip | 160 ++++++ .../interpolation/qgsinterpolator.cpp | 1 + src/app/qgisapp.cpp | 7 +- src/app/qgslabelpropertydialog.cpp | 1 + src/app/qgsmaptoollabel.cpp | 35 +- src/app/qgsmaptoollabel.h | 9 +- src/app/qgsmaptoolmovelabel.cpp | 4 +- src/app/qgsvectorlayerproperties.cpp | 372 +++++++++++++ src/app/qgsvectorlayerproperties.h | 15 + src/core/CMakeLists.txt | 2 + src/core/qgsdiagram.cpp | 283 ++++++++++ src/core/qgsdiagram.h | 74 +++ src/core/qgsdiagramrendererv2.cpp | 342 ++++++++++++ src/core/qgsdiagramrendererv2.h | 219 ++++++++ src/core/qgslabelsearchtree.cpp | 4 +- src/core/qgslabelsearchtree.h | 2 +- src/core/qgsmaprenderer.h | 13 +- src/core/qgspallabeling.cpp | 167 +++++- src/core/qgspallabeling.h | 11 +- src/core/qgsrendercontext.h | 1 + src/core/qgsvectordataprovider.h | 7 +- src/core/qgsvectorlayer.cpp | 158 ++++-- src/core/qgsvectorlayer.h | 22 +- src/gui/qgsmaptip.cpp | 1 + src/plugins/CMakeLists.txt | 4 +- src/plugins/grass/qgsgrassedittools.cpp | 1 + .../qgsdelimitedtextprovider.cpp | 1 - .../delimitedtext/qgsdelimitedtextprovider.h | 1 + src/providers/grass/qgsgrassprovider.h | 1 + src/providers/memory/qgsmemoryprovider.h | 1 + src/providers/osm/osmprovider.cpp | 1 + src/providers/osm/osmprovider.h | 1 + .../postgres/qgspostgresprovider.cpp | 1 + .../sqlanywhere/qgssqlanywhereprovider.h | 1 + src/ui/qgsvectorlayerpropertiesbase.ui | 525 +++++++++++++++++- 35 files changed, 2371 insertions(+), 77 deletions(-) create mode 100644 python/core/qgsdiagramrendererv2.sip create mode 100644 src/core/qgsdiagram.cpp create mode 100644 src/core/qgsdiagram.h create mode 100644 src/core/qgsdiagramrendererv2.cpp create mode 100644 src/core/qgsdiagramrendererv2.h diff --git a/python/core/qgsdiagramrendererv2.sip b/python/core/qgsdiagramrendererv2.sip new file mode 100644 index 00000000000..e63ada5a003 --- /dev/null +++ b/python/core/qgsdiagramrendererv2.sip @@ -0,0 +1,160 @@ +struct QgsDiagramLayerSettings +{ +%TypeHeaderCode +#include +%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 +%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 +%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 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 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 +%End + public: + QgsSingleCategoryDiagramRenderer(); + ~QgsSingleCategoryDiagramRenderer(); + + QString rendererName() const; + + QList diagramAttributes() const; + + void setDiagramSettings( const QgsDiagramSettings& s ); + + QList diagramSettings() const; + + void readXML( const QDomElement& elem ); + void writeXML( QDomElement& layerElem, QDomDocument& doc ) const; +}; + +class QgsLinearlyInterpolatedDiagramRenderer: QgsDiagramRendererV2 +{ +%TypeHeaderCode +#include +%End + public: + QgsLinearlyInterpolatedDiagramRenderer(); + ~QgsLinearlyInterpolatedDiagramRenderer(); + + /**Returns list with all diagram settings in the renderer*/ + QList diagramSettings() const; + + void setDiagramSettings( const QgsDiagramSettings& s ); + + QList 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; +}; diff --git a/src/analysis/interpolation/qgsinterpolator.cpp b/src/analysis/interpolation/qgsinterpolator.cpp index 0edb28c1a18..02743751120 100644 --- a/src/analysis/interpolation/qgsinterpolator.cpp +++ b/src/analysis/interpolation/qgsinterpolator.cpp @@ -17,6 +17,7 @@ #include "qgsinterpolator.h" #include "qgsvectordataprovider.h" +#include "qgsvectorlayer.h" #include "qgsgeometry.h" QgsInterpolator::QgsInterpolator( const QList& layerData ): mDataIsCached( false ), mLayerData( layerData ) diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index ddfb38d38e6..ce8e6ea2bcd 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -5663,14 +5663,17 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer ) for ( QMap::iterator it = layers.begin(); it != layers.end(); it++ ) { QgsVectorLayer *vlayer = qobject_cast( 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( mMapTools.mMoveLabel ) && - qobject_cast( mMapTools.mMoveLabel )->layerIsMoveable( vlayer, colX, colY ) ); + ( qobject_cast( mMapTools.mMoveLabel )->labelMoveable( vlayer, colX, colY ) + || qobject_cast( mMapTools.mMoveLabel )->diagramMoveable( vlayer, colX, colY ) ) + ); enableRotate = enableRotate || diff --git a/src/app/qgslabelpropertydialog.cpp b/src/app/qgslabelpropertydialog.cpp index 22b4969abfc..73ea83beda9 100644 --- a/src/app/qgslabelpropertydialog.cpp +++ b/src/app/qgslabelpropertydialog.cpp @@ -18,6 +18,7 @@ #include "qgslabelpropertydialog.h" #include "qgsmaplayerregistry.h" #include "qgsmaprenderer.h" +#include "qgsvectorlayer.h" #include #include diff --git a/src/app/qgsmaptoollabel.cpp b/src/app/qgsmaptoollabel.cpp index a49df0faac8..d3cad775a80 100644 --- a/src/app/qgsmaptoollabel.cpp +++ b/src/app/qgsmaptoollabel.cpp @@ -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( 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( ml ); if ( !vlayer || !vlayer->isEditable() ) diff --git a/src/app/qgsmaptoollabel.h b/src/app/qgsmaptoollabel.h index 4b42777078e..ad9c32e5680 100644 --- a/src/app/qgsmaptoollabel.h +++ b/src/app/qgsmaptoollabel.h @@ -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; diff --git a/src/app/qgsmaptoolmovelabel.cpp b/src/app/qgsmaptoolmovelabel.cpp index f6db3ac1d46..f96ff040d96 100644 --- a/src/app/qgsmaptoolmovelabel.cpp +++ b/src/app/qgsmaptoolmovelabel.cpp @@ -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(); diff --git a/src/app/qgsvectorlayerproperties.cpp b/src/app/qgsvectorlayerproperties.cpp index f993ced5620..a04a6b90aa6 100644 --- a/src/app/qgsvectorlayerproperties.cpp +++ b/src/app/qgsvectorlayerproperties.cpp @@ -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 #include #include +#include #include #include #include #include +#include #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 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 categoryColors; + QList 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::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 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( 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 ) ) ); +} diff --git a/src/app/qgsvectorlayerproperties.h b/src/app/qgsvectorlayerproperties.h index 42055ed5caf..2273c1eef2f 100644 --- a/src/app/qgsvectorlayerproperties.h +++ b/src/app/qgsvectorlayerproperties.h @@ -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 mRanges; QMap > 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 overlayPlugins() const; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3a9a955d8a8..0e2373808a7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -46,6 +46,8 @@ SET(QGIS_CORE_SRCS qgscontexthelp.cpp qgscoordinatetransform.cpp qgsdatasourceuri.cpp + qgsdiagram.cpp + qgsdiagramrendererv2.cpp qgsdistancearea.cpp qgsfeature.cpp qgsfield.cpp diff --git a/src/core/qgsdiagram.cpp b/src/core/qgsdiagram.cpp new file mode 100644 index 00000000000..a565a82c2fd --- /dev/null +++ b/src/core/qgsdiagram.cpp @@ -0,0 +1,283 @@ +#include "qgsdiagram.h" +#include "qgsdiagramrendererv2.h" +#include "qgsrendercontext.h" + +#include + +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 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 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& 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 values; + double currentVal = 0; + double valSum = 0; + + QList::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::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; + } +} diff --git a/src/core/qgsdiagram.h b/src/core/qgsdiagram.h new file mode 100644 index 00000000000..a6fec76a625 --- /dev/null +++ b/src/core/qgsdiagram.h @@ -0,0 +1,74 @@ +#ifndef QGSDIAGRAM_H +#define QGSDIAGRAM_H + +#include "qgsfeature.h" +#include + +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& 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 diff --git a/src/core/qgsdiagramrendererv2.cpp b/src/core/qgsdiagramrendererv2.cpp new file mode 100644 index 00000000000..c2ae7c62a33 --- /dev/null +++ b/src/core/qgsdiagramrendererv2.cpp @@ -0,0 +1,342 @@ +#include "qgsdiagramrendererv2.h" +#include "qgsdiagram.h" +#include "qgsrendercontext.h" +#include +#include + + +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 QgsSingleCategoryDiagramRenderer::diagramSettings() const +{ + QList 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 QgsLinearlyInterpolatedDiagramRenderer::diagramSettings() const +{ + QList 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 QgsLinearlyInterpolatedDiagramRenderer::diagramAttributes() const +{ + QList 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 ); +} diff --git a/src/core/qgsdiagramrendererv2.h b/src/core/qgsdiagramrendererv2.h new file mode 100644 index 00000000000..76c37d3244b --- /dev/null +++ b/src/core/qgsdiagramrendererv2.h @@ -0,0 +1,219 @@ +#ifndef QGSDIAGRAMRENDERERV2_H +#define QGSDIAGRAMRENDERERV2_H + +#include +#include +#include +#include +#include +#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 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 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 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 diagramAttributes() const { return mSettings.categoryIndices; } + + void setDiagramSettings( const QgsDiagramSettings& s ) { mSettings = s; } + + QList 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 diagramSettings() const; + + void setDiagramSettings( const QgsDiagramSettings& s ) { mSettings = s; } + + QList 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 diff --git a/src/core/qgslabelsearchtree.cpp b/src/core/qgslabelsearchtree.cpp index a64059b9cdc..9c807619e39 100644 --- a/src/core/qgslabelsearchtree.cpp +++ b/src/core/qgslabelsearchtree.cpp @@ -27,7 +27,7 @@ void QgsLabelSearchTree::label( const QgsPoint& p, QList& 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; } diff --git a/src/core/qgslabelsearchtree.h b/src/core/qgslabelsearchtree.h index 9227ed7101a..2039defb375 100644 --- a/src/core/qgslabelsearchtree.h +++ b/src/core/qgslabelsearchtree.h @@ -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 mSpatialIndex; diff --git a/src/core/qgsmaprenderer.h b/src/core/qgsmaprenderer.h index 0812bdf32ee..d064f64719c 100644 --- a/src/core/qgsmaprenderer.h +++ b/src/core/qgsmaprenderer.h @@ -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& 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 diff --git a/src/core/qgspallabeling.cpp b/src/core/qgspallabeling.cpp index b11ad8f8e65..666e6434baa 100644 --- a/src/core/qgspallabeling.cpp +++ b/src/core/qgspallabeling.cpp @@ -38,6 +38,8 @@ #include #include +#include "qgsdiagram.h" +#include "qgsdiagramrendererv2.h" #include "qgslabelsearchtree.h" #include #include @@ -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& 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::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 diagramAttrib = dr->diagramAttributes(); + QList::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::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::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::iterator dIt = mActiveDiagramLayers.begin(); + for ( ; dIt != mActiveDiagramLayers.end(); ++dIt ) + { + QgsDiagramLayerSettings& dls = dIt.value(); + for ( QList::iterator git = dls.geometries.begin(); git != dls.geometries.end(); ++git ) + { + delete *git; + } + dls.geometries.clear(); + } } QList QgsPalLabeling::labelsAtPosition( const QgsPoint& p ) diff --git a/src/core/qgspallabeling.h b/src/core/qgspallabeling.h index 7e3baebb87f..bd9e6bc992a 100644 --- a/src/core/qgspallabeling.h +++ b/src/core/qgspallabeling.h @@ -23,14 +23,17 @@ class QFontMetricsF; class QPainter; +class QgsGeometry; class QgsMapRenderer; class QgsRectangle; class QgsCoordinateTransform; class QgsLabelSearchTree; +struct QgsDiagramLayerSettings; #include #include #include +#include #include #include @@ -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& 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 mActiveLayers; + // hashtable of active diagram layers + QHash mActiveDiagramLayers; QgsPalLayerSettings mInvalidLayerSettings; QgsMapRenderer* mMapRenderer; diff --git a/src/core/qgsrendercontext.h b/src/core/qgsrendercontext.h index 2682dbc4bfe..fe8417f47b5 100644 --- a/src/core/qgsrendercontext.h +++ b/src/core/qgsrendercontext.h @@ -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;} diff --git a/src/core/qgsvectordataprovider.h b/src/core/qgsvectordataprovider.h index e724e6d9c75..b830ee4e67f 100644 --- a/src/core/qgsvectordataprovider.h +++ b/src/core/qgsvectordataprovider.h @@ -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 QgsAttributeList; +typedef QSet QgsFeatureIds; +typedef QSet QgsAttributeIds; /** \ingroup core * This is the base class for vector data providers. diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 556bbbfac80..31141d1787e 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -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 attrIndex; - if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) ) - { - QSet::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 attrIndex; - if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) ) - { - QSet::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 attrIndex; + if ( rendererContext.labelingEngine()->prepareLayer( this, attrIndex, rendererContext ) ) + { + QSet::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 att = mDiagramRenderer->diagramAttributes(); + QList::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; + } + } + } +} diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index ebf347affab..2fe53771d92 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -24,7 +24,10 @@ #include #include + + #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 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 diff --git a/src/gui/qgsmaptip.cpp b/src/gui/qgsmaptip.cpp index 9a4a395df0e..8c45590d504 100644 --- a/src/gui/qgsmaptip.cpp +++ b/src/gui/qgsmaptip.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include // Qt includes diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index aa8c27ef8b7..5e4eb437367 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -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 diff --git a/src/plugins/grass/qgsgrassedittools.cpp b/src/plugins/grass/qgsgrassedittools.cpp index 9c97fe15f87..3a509c075b6 100644 --- a/src/plugins/grass/qgsgrassedittools.cpp +++ b/src/plugins/grass/qgsgrassedittools.cpp @@ -22,6 +22,7 @@ #include "qgisinterface.h" #include "qgslogger.h" #include "qgsmapcanvas.h" +#include "qgsvectorlayer.h" #include "qgsvertexmarker.h" #include diff --git a/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp b/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp index d432028450e..7cef0d07c99 100644 --- a/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp +++ b/src/providers/delimitedtext/qgsdelimitedtextprovider.cpp @@ -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"; diff --git a/src/providers/delimitedtext/qgsdelimitedtextprovider.h b/src/providers/delimitedtext/qgsdelimitedtextprovider.h index fd883fd39e5..59b3b405838 100644 --- a/src/providers/delimitedtext/qgsdelimitedtextprovider.h +++ b/src/providers/delimitedtext/qgsdelimitedtextprovider.h @@ -18,6 +18,7 @@ /* $Id$ */ #include "qgsvectordataprovider.h" +#include "qgscoordinatereferencesystem.h" #include diff --git a/src/providers/grass/qgsgrassprovider.h b/src/providers/grass/qgsgrassprovider.h index ebf8d0a037c..e342320a807 100644 --- a/src/providers/grass/qgsgrassprovider.h +++ b/src/providers/grass/qgsgrassprovider.h @@ -21,6 +21,7 @@ class QgsField; #include #include "qgsvectordataprovider.h" +#include /* Update. * Vectors are updated (reloaded) if: diff --git a/src/providers/memory/qgsmemoryprovider.h b/src/providers/memory/qgsmemoryprovider.h index 108f48318ff..bed4a03b16c 100644 --- a/src/providers/memory/qgsmemoryprovider.h +++ b/src/providers/memory/qgsmemoryprovider.h @@ -14,6 +14,7 @@ ***************************************************************************/ #include "qgsvectordataprovider.h" +#include "qgscoordinatereferencesystem.h" typedef QMap QgsFeatureMap; diff --git a/src/providers/osm/osmprovider.cpp b/src/providers/osm/osmprovider.cpp index c33ea392c58..b0a21eb35bc 100644 --- a/src/providers/osm/osmprovider.cpp +++ b/src/providers/osm/osmprovider.cpp @@ -21,6 +21,7 @@ #include "qgsgeometry.h" #include "qgslogger.h" #include "qgsvectordataprovider.h" +#include "qgsvectorlayer.h" #include "qgsapplication.h" #include diff --git a/src/providers/osm/osmprovider.h b/src/providers/osm/osmprovider.h index 0e4944dddb7..07726a7eab2 100644 --- a/src/providers/osm/osmprovider.h +++ b/src/providers/osm/osmprovider.h @@ -17,6 +17,7 @@ #include #include +class QgsVectorLayer; /** * Quantum GIS provider for OpenStreetMap data. diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index 047962af4cf..c5367a5a15c 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -41,6 +41,7 @@ #include "qgslogger.h" #include "qgscredentials.h" +#include const QString POSTGRES_KEY = "postgres"; const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider"; diff --git a/src/providers/sqlanywhere/qgssqlanywhereprovider.h b/src/providers/sqlanywhere/qgssqlanywhereprovider.h index 576ab9ecaf2..4b188a01219 100644 --- a/src/providers/sqlanywhere/qgssqlanywhereprovider.h +++ b/src/providers/sqlanywhere/qgssqlanywhereprovider.h @@ -19,6 +19,7 @@ #ifndef QGSSQLANYWHEREPROVIDER_H #define QGSSQLANYWHEREPROVIDER_H +#include "qgscoordinatereferencesystem.h" #include "qgsdatasourceuri.h" #include "qgsvectordataprovider.h" #include "qgsrectangle.h" diff --git a/src/ui/qgsvectorlayerpropertiesbase.ui b/src/ui/qgsvectorlayerpropertiesbase.ui index 413b65bf1c5..8ce91ad9960 100644 --- a/src/ui/qgsvectorlayerpropertiesbase.ui +++ b/src/ui/qgsvectorlayerpropertiesbase.ui @@ -6,8 +6,8 @@ 0 0 - 591 - 426 + 670 + 625 @@ -21,7 +21,7 @@ true - + @@ -53,7 +53,7 @@ - + Qt::Horizontal @@ -63,7 +63,7 @@ - + 0 @@ -372,8 +372,8 @@ 0 0 - 432 - 419 + 648 + 501 @@ -679,11 +679,522 @@ + + + + :/images/themes/default/propertyicons/diagram.png:/images/themes/default/propertyicons/diagram.png + + + Diagrams + + + + + + Display diagrams + + + + + + + 6 + + + 0 + + + + + Diagram type + + + + + + + + + + + + + + Priority: + + + + + + + Low + + + + + + + 10 + + + Qt::Horizontal + + + false + + + false + + + QSlider::TicksBelow + + + 1 + + + + + + + High + + + + + + + + + Appearance + + + + + + + + Scale dependent visibility + + + + + + + Minimum + + + + + + + + + + Maximum + + + + + + + + + + + + + + + + Background color + + + + + + + + 0 + 0 + + + + + 25 + 0 + + + + + + + + + + + + + + + + + Pen color + + + + + + + + 0 + 0 + + + + + 25 + 0 + + + + + + + + + + + + + + + Pen width + + + + + + + 99999.990000000005239 + + + + + + + + + + 0 + 0 + + + + Font... + + + + + + + mDiagramFontButton + + mPenWidthSpinBox + mPenWidthLabel + mPenWidthLabel + + + + + + Size + + + + + + Fixed size + + + + + + + 9999999.990000000223517 + + + + + + + Qt::Horizontal + + + + 335 + 20 + + + + + + + + Scale linearly between 0 and the following attribute value / diagram size: + + + true + + + + + + + + + Attribute + + + + + + + + + + Find maximum value + + + + + + + + + + Size + + + + + + + 10000000 + + + + + + + + + + + Size units + + + + + + + + + + + + + + + Position + + + + + + + + Placement + + + + + + + + + + + + + + Line Options + + + + + + + + + + + + + + Distance + + + + + + + + + + + + Date defined position + + + + + + + + + + 0 + 0 + + + + x + + + + + + + + + + + + + + + 0 + 0 + + + + y + + + + + + + + + + + + + + + Attributes + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + + 241 + 23 + + + + + + + + + 0 + 0 + + + + + + + + :/images/themes/default/symbologyRemove.png:/images/themes/default/symbologyRemove.png + + + + + + + + 0 + 0 + + + + + + + + :/images/themes/default/symbologyAdd.png:/images/themes/default/symbologyAdd.png + + + + + + + 2 + + + + Attribute + + + + + Color + + + + + + + + + QgsColorButton + QToolButton +
qgscolorbutton.h
+
+
txtDisplayName displayFieldComboBox