Index: src/app/qgslabelpropertydialog.cpp =================================================================== --- src/app/qgslabelpropertydialog.cpp (Revision 15400) +++ src/app/qgslabelpropertydialog.cpp (Arbeitskopie) @@ -18,6 +18,7 @@ #include "qgslabelpropertydialog.h" #include "qgsmaplayerregistry.h" #include "qgsmaprenderer.h" +#include "qgsvectorlayer.h" #include #include Index: src/app/qgsmaptoollabel.cpp =================================================================== --- src/app/qgsmaptoollabel.cpp (Revision 15400) +++ src/app/qgsmaptoollabel.cpp (Arbeitskopie) @@ -280,6 +280,14 @@ 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,8 +364,15 @@ 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,9 +389,25 @@ 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() ) { return false; Index: src/app/qgsmaptoollabel.h =================================================================== --- src/app/qgsmaptoollabel.h (Revision 15400) +++ src/app/qgsmaptoollabel.h (Arbeitskopie) @@ -31,11 +31,16 @@ 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; Index: src/app/qgsvectorlayerproperties.h =================================================================== --- src/app/qgsvectorlayerproperties.h (Revision 15400) +++ src/app/qgsvectorlayerproperties.h (Arbeitskopie) @@ -106,6 +106,12 @@ 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_mFindMaximumValueButton_clicked(); + void on_mBackgroundColorButton_clicked(); void enableLabelOptions( bool theFlag ); void addAttribute(); @@ -120,6 +126,9 @@ 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 +173,14 @@ 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; Index: src/app/qgsvectorlayerproperties.cpp =================================================================== --- src/app/qgsvectorlayerproperties.cpp (Revision 15400) +++ src/app/qgsvectorlayerproperties.cpp (Arbeitskopie) @@ -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 @@ addJoinToTreeWidget( joins[i] ); } + initDiagramTab(); + //for each overlay plugin create a new tab int position; QList overlayPluginList = overlayPlugins(); @@ -678,6 +684,72 @@ } + //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() ); + ds.backgroundColor = mBackgroundColorButton->color(); + + 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 +1315,18 @@ 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 +1422,229 @@ { 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_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::initDiagramTab() +{ + if( !layer ) + { + mDiagramPage->setEnabled( false ); + } + + 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 ) + { + mDisplayDiagramsCheckBox->setChecked( false ); + mFixedSizeCheckBox->setChecked( true ); + + //insert reasonable default for placement + switch( layerType ) + { + case QGis::Point: + mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( 1 )); + break; + case QGis::Line: + mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( 3 )); + mLineOptionsComboBox->setCurrentIndex( mLineOptionsComboBox->findData( 2 ) ); + break; + case QGis::Polygon: + mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( 1 )); + 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 ); + mDiagramSizeSpinBox->setValue( ( size.width() + size.height() ) / 2.0 ); + + 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) ) ); +} Index: src/app/qgsmaptoolmovelabel.cpp =================================================================== --- src/app/qgsmaptoolmovelabel.cpp (Revision 15400) +++ src/app/qgsmaptoolmovelabel.cpp (Arbeitskopie) @@ -40,13 +40,13 @@ } 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(); Index: src/app/qgisapp.cpp =================================================================== --- src/app/qgisapp.cpp (Revision 15400) +++ src/app/qgisapp.cpp (Arbeitskopie) @@ -5554,14 +5554,17 @@ 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 || Index: src/plugins/grass/qgsgrassedittools.cpp =================================================================== --- src/plugins/grass/qgsgrassedittools.cpp (Revision 15400) +++ src/plugins/grass/qgsgrassedittools.cpp (Arbeitskopie) @@ -22,6 +22,7 @@ #include "qgisinterface.h" #include "qgslogger.h" #include "qgsmapcanvas.h" +#include "qgsvectorlayer.h" #include "qgsvertexmarker.h" #include Index: src/analysis/interpolation/qgsinterpolator.cpp =================================================================== --- src/analysis/interpolation/qgsinterpolator.cpp (Revision 15400) +++ src/analysis/interpolation/qgsinterpolator.cpp (Arbeitskopie) @@ -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 ) Index: src/gui/qgsmaptip.cpp =================================================================== --- src/gui/qgsmaptip.cpp (Revision 15400) +++ src/gui/qgsmaptip.cpp (Arbeitskopie) @@ -16,6 +16,7 @@ #include #include #include +#include #include // Qt includes Index: src/core/qgsdiagramrendererv2.h =================================================================== --- src/core/qgsdiagramrendererv2.h (Revision 0) +++ src/core/qgsdiagramrendererv2.h (Revision 0) @@ -0,0 +1,204 @@ +#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 +{ + QFont font; + QList< QColor > categoryColors; + QList< int > categoryIndices; + QSizeF size; //size in mm + QColor backgroundColor; + + 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 Index: src/core/qgsmaprenderer.h =================================================================== --- src/core/qgsmaprenderer.h (Revision 15400) +++ src/core/qgsmaprenderer.h (Arbeitskopie) @@ -39,11 +39,13 @@ 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 @@ double height; QString layerID; bool upsideDown; + bool isDiagram; }; /** Labeling engine interface. @@ -70,8 +73,12 @@ //! 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 Index: src/core/qgspallabeling.cpp =================================================================== --- src/core/qgspallabeling.cpp (Revision 15400) +++ src/core/qgspallabeling.cpp (Arbeitskopie) @@ -38,6 +38,8 @@ #include #include +#include "qgsdiagram.h" +#include "qgsdiagramrendererv2.h" #include "qgslabelsearchtree.h" #include #include @@ -54,7 +56,7 @@ 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 ); } @@ -100,14 +102,24 @@ 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; }; // ------------- @@ -414,7 +426,6 @@ labelY = qAbs( ptSize.y() - ptZero.y() ); } - void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext& context ) { QString labelText = f.attributeMap()[fieldIndex].toString(); @@ -743,14 +754,116 @@ 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 ) { QgsPalLayerSettings& lyr = mActiveLayers[layer]; 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 ) { mMapRenderer = mr; @@ -779,6 +892,7 @@ mPal->setPolyP( mCandPolygon ); mActiveLayers.clear(); + mActiveDiagramLayers.clear(); } void QgsPalLabeling::exit() @@ -867,18 +981,42 @@ std::list::iterator it = labels->begin(); for ( ; it != labels->end(); ++it ) { + 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; - QgsPalGeometry* palGeometry = dynamic_cast< QgsPalGeometry* >(( *it )->getFeaturePart()->getUserGeometry() ); - if ( !palGeometry ) - { - continue; - } - //apply data defined settings for the label //font size QVariant dataDefinedSize = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Size ); @@ -969,9 +1107,18 @@ 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 ) Index: src/core/qgsrendercontext.h =================================================================== --- src/core/qgsrendercontext.h (Revision 15400) +++ src/core/qgsrendercontext.h (Arbeitskopie) @@ -41,6 +41,7 @@ //getters QPainter* painter() {return mPainter;} + const QPainter* constPainter() const { return mPainter; } const QgsCoordinateTransform* coordinateTransform() const {return mCoordTransform;} Index: src/core/qgspallabeling.h =================================================================== --- src/core/qgspallabeling.h (Revision 15400) +++ src/core/qgspallabeling.h (Arbeitskopie) @@ -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 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 @@ 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 @@ protected: // hashtable of layer settings, being filled during labeling QHash mActiveLayers; + // hashtable of active diagram layers + QHash mActiveDiagramLayers; QgsPalLayerSettings mInvalidLayerSettings; QgsMapRenderer* mMapRenderer; Index: src/core/qgslabelsearchtree.h =================================================================== --- src/core/qgslabelsearchtree.h (Revision 15400) +++ src/core/qgslabelsearchtree.h (Arbeitskopie) @@ -44,7 +44,7 @@ /**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; Index: src/core/qgsvectorlayer.cpp =================================================================== --- src/core/qgsvectorlayer.cpp (Revision 15400) +++ src/core/qgsvectorlayer.cpp (Arbeitskopie) @@ -112,7 +112,8 @@ mLabelOn( false ), mVertexMarkerOnlyForSelection( false ), mFetching( false ), - mJoinBuffer( 0 ) + mJoinBuffer( 0 ), + mDiagramRenderer( 0 ) { mActions = new QgsAttributeAction( this ); @@ -755,8 +756,17 @@ 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 ) { @@ -822,8 +832,17 @@ } 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 ) { @@ -950,22 +969,8 @@ } 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() ); @@ -1012,22 +1017,7 @@ 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() ); @@ -1093,11 +1083,17 @@ //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; } } @@ -1304,6 +1300,12 @@ } } +void QgsVectorLayer::setDiagramRenderer( QgsDiagramRendererV2* r ) +{ + delete mDiagramRenderer; + mDiagramRenderer = r; +} + QGis::GeometryType QgsVectorLayer::geometryType() const { if ( mDataProvider ) @@ -2938,6 +2940,30 @@ 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 @@ -3110,6 +3136,12 @@ } mLabel->writeXML( node, doc ); + + if( mDiagramRenderer ) + { + mDiagramRenderer->writeXML( mapLayerNode, doc ); + mDiagramLayerSettings.writeXML( mapLayerNode, doc ); + } } //edit types @@ -5132,3 +5164,49 @@ 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; + } + } + } +} Index: src/core/qgsdiagram.h =================================================================== --- src/core/qgsdiagram.h (Revision 0) +++ src/core/qgsdiagram.h (Revision 0) @@ -0,0 +1,69 @@ +#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; +}; + +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 Index: src/core/qgsdiagram.cpp =================================================================== --- src/core/qgsdiagram.cpp (Revision 0) +++ src/core/qgsdiagram.cpp (Revision 0) @@ -0,0 +1,188 @@ +#include "qgsdiagram.h" +#include "qgsdiagramrendererv2.h" +#include "qgsrendercontext.h" + +#include + +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; + } + + //convert from mm to painter units + double w = s.size.width() * c.scaleFactor(); + double h = s.size.height() * c.scaleFactor(); + + 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( QColor( 0, 0, 0 ) ); + p->setPen( mPen ); + mBrush.setColor( s.backgroundColor ); + p->setBrush( mBrush ); + p->setFont( s.font ); + + //draw shapes + QPointF center( baseX + w / 2.0, baseY + h / 2.0 ); + double r1 = w / 2.0; double r2 = h / 2.0; + QList intersect; //intersections between shape and separation lines + + switch( mShape ) + { + case Circle: + p->drawEllipse( baseX, baseY, w, h ); + //draw separator lines + 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) ); + } + } + break; + case Rectangle: + break; + case Triangle: + default: + break; + } + + //draw text + p->setFont( s.font ); + QFontMetricsF fontMetrics( s.font ); + + 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::NoPen ); +} + +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 to painter units + double w = s.size.width() * c.scaleFactor(); + double h = s.size.height() * c.scaleFactor(); + + double baseX = position.x(); + double baseY = position.y() - h; + + 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; + } +} Index: src/core/qgsvectorlayer.h =================================================================== --- src/core/qgsvectorlayer.h (Revision 15400) +++ src/core/qgsvectorlayer.h (Arbeitskopie) @@ -25,6 +25,7 @@ #include #include "qgis.h" +#include "qgsdiagramrendererv2.h" #include "qgsmaplayer.h" #include "qgsfeature.h" #include "qgssnapper.h" @@ -48,7 +49,6 @@ class QgsSingleSymbolRendererV2; class QgsRectangle; class QgsVectorLayerJoinBuffer; - class QgsFeatureRendererV2; typedef QList QgsAttributeList; @@ -208,6 +208,13 @@ /** 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 +811,11 @@ /**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 +943,12 @@ //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 Index: src/core/qgsvectordataprovider.h =================================================================== --- src/core/qgsvectordataprovider.h (Revision 15400) +++ src/core/qgsvectordataprovider.h (Arbeitskopie) @@ -25,9 +25,14 @@ //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. * Index: src/core/CMakeLists.txt =================================================================== --- src/core/CMakeLists.txt (Revision 15400) +++ src/core/CMakeLists.txt (Arbeitskopie) @@ -46,6 +46,8 @@ qgscontexthelp.cpp qgscoordinatetransform.cpp qgsdatasourceuri.cpp + qgsdiagram.cpp + qgsdiagramrendererv2.cpp qgsdistancearea.cpp qgsfeature.cpp qgsfield.cpp Index: src/core/qgslabelsearchtree.cpp =================================================================== --- src/core/qgslabelsearchtree.cpp (Revision 15400) +++ src/core/qgslabelsearchtree.cpp (Arbeitskopie) @@ -27,7 +27,7 @@ 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 @@ 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; } Index: src/core/qgsdiagramrendererv2.cpp =================================================================== --- src/core/qgsdiagramrendererv2.cpp (Revision 0) +++ src/core/qgsdiagramrendererv2.cpp (Revision 0) @@ -0,0 +1,305 @@ +#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() ); + + categoryColors.clear(); + QStringList colorList = elem.attribute("colors").split("/"); + QStringList::const_iterator colorIt = colorList.constBegin(); + for(; colorIt != colorList.constEnd(); ++colorIt ) + { + categoryColors.append( QColor(*colorIt) ); + } + + 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() ); + + 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 ) +{ + QSizeF size = diagramSize( attributes, c ); + 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 ); +} Index: src/mapserver/qgsfilter.cpp =================================================================== --- src/mapserver/qgsfilter.cpp (Revision 15400) +++ src/mapserver/qgsfilter.cpp (Arbeitskopie) @@ -20,6 +20,7 @@ #include "qgscomparisonfilter.h" #include "qgslogicalfilter.h" #include "qgsvectordataprovider.h" +#include "qgsvectorlayer.h" #include #include Index: src/providers/grass/qgsgrassprovider.h =================================================================== --- src/providers/grass/qgsgrassprovider.h (Revision 15400) +++ src/providers/grass/qgsgrassprovider.h (Arbeitskopie) @@ -21,6 +21,7 @@ #include #include "qgsvectordataprovider.h" +#include /* Update. * Vectors are updated (reloaded) if: Index: src/providers/sqlanywhere/qgssqlanywhereprovider.h =================================================================== --- src/providers/sqlanywhere/qgssqlanywhereprovider.h (Revision 15400) +++ src/providers/sqlanywhere/qgssqlanywhereprovider.h (Arbeitskopie) @@ -19,6 +19,7 @@ #ifndef QGSSQLANYWHEREPROVIDER_H #define QGSSQLANYWHEREPROVIDER_H +#include "qgscoordinatereferencesystem.h" #include "qgsdatasourceuri.h" #include "qgsvectordataprovider.h" #include "qgsrectangle.h" Index: src/providers/delimitedtext/qgsdelimitedtextprovider.h =================================================================== --- src/providers/delimitedtext/qgsdelimitedtextprovider.h (Revision 15400) +++ src/providers/delimitedtext/qgsdelimitedtextprovider.h (Arbeitskopie) @@ -18,7 +18,7 @@ /* $Id$ */ #include "qgsvectordataprovider.h" - +#include "qgscoordinatereferencesystem.h" #include class QgsFeature; Index: src/providers/postgres/qgspostgresprovider.cpp =================================================================== --- src/providers/postgres/qgspostgresprovider.cpp (Revision 15400) +++ src/providers/postgres/qgspostgresprovider.cpp (Arbeitskopie) @@ -41,6 +41,7 @@ #include "qgslogger.h" #include "qgscredentials.h" +#include const QString POSTGRES_KEY = "postgres"; const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider"; Index: src/providers/memory/qgsmemoryprovider.h =================================================================== --- src/providers/memory/qgsmemoryprovider.h (Revision 15400) +++ src/providers/memory/qgsmemoryprovider.h (Arbeitskopie) @@ -14,6 +14,7 @@ ***************************************************************************/ #include "qgsvectordataprovider.h" +#include "qgscoordinatereferencesystem.h" typedef QMap QgsFeatureMap; Index: src/providers/osm/osmprovider.h =================================================================== --- src/providers/osm/osmprovider.h (Revision 15400) +++ src/providers/osm/osmprovider.h (Arbeitskopie) @@ -13,11 +13,12 @@ ***************************************************************************/ #include "qgsvectordataprovider.h" - +#include "qgsvectorlayer.h" #include #include + /** * Quantum GIS provider for OpenStreetMap data. */ Index: src/ui/qgsvectorlayerpropertiesbase.ui =================================================================== --- src/ui/qgsvectorlayerpropertiesbase.ui (Revision 15400) +++ src/ui/qgsvectorlayerpropertiesbase.ui (Arbeitskopie) @@ -6,8 +6,8 @@ 0 0 - 591 - 426 + 537 + 523 @@ -21,7 +21,7 @@ true - + @@ -53,7 +53,7 @@ - + Qt::Horizontal @@ -63,10 +63,10 @@ - + - 0 + 7 @@ -372,7 +372,7 @@ 0 0 - 432 + 501 419 @@ -679,11 +679,376 @@ + + + + :/images/themes/default/propertyicons/diagram.png:/images/themes/default/propertyicons/diagram.png + + + Diagrams + + + + + + Display diagrams + + + + + + + + 0 + 0 + + + + Font... + + + + + + + 6 + + + 0 + + + + + Diagram type + + + + + + + + + + + + + + Background color + + + + + + + + 0 + 0 + + + + + 25 + 0 + + + + + + + + + + + + + + + Priority + + + + + + + Qt::Horizontal + + + + + + + + + Size + + + + + + Fixed size + + + + + + + + + + Qt::Horizontal + + + + 335 + 20 + + + + + + + + Scale linearly between 0 and the following attribute value / diagram size: + + + true + + + + + + + + + Attribute + + + + + + + + + + Find maximum value + + + + + + + + + + Size + + + + + + + 10000000 + + + + + + + + + + + + Position + + + + + + + + Placement + + + + + + + + + + + + + + Line Options + + + + + + + + + + + + + + Distance + + + + + + + + + + + + Date defined position + + + + + + + + + + 0 + 0 + + + + x + + + + + + + + + + + + + + + 0 + 0 + + + + y + + + + + + + + + + + + + + + Attributes + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + :/images/themes/default/symbologyRemove.png:/images/themes/default/symbologyRemove.png + + + + + + + + 0 + 0 + + + + + + + + :/images/themes/default/symbologyAdd.png:/images/themes/default/symbologyAdd.png + + + + + + + Qt::Horizontal + + + + 241 + 23 + + + + + + + + 2 + + + + Attribute + + + + + Color + + + + + + + + + QgsColorButton + QToolButton +
qgscolorbutton.h
+
+
txtDisplayName displayFieldComboBox