allow for expressions in symbol rotation and scale

the single, graduated and categorised symbol renderers have been
refactored to avoid use of raw pointers (auto_ptr are used instead, they
are deprecated in c++11 but the change for unique_ptr is an easy one and
they clearly state the design intend: exclusive ownership)

2 general use function to quote and unquote strings for/from xml have
been added to qgis.h
This commit is contained in:
vmora 2014-01-14 17:23:16 +01:00
parent a31ebb474a
commit 7d404d97ca
19 changed files with 366 additions and 318 deletions

View File

@ -123,5 +123,9 @@ class QgsCategorizedSymbolRendererV2 : QgsFeatureRendererV2
void rebuildHash();
QgsSymbolV2* symbolForValue( QVariant value );
private:
QgsCategorizedSymbolRendererV2( const QgsCategorizedSymbolRendererV2 & );
QgsCategorizedSymbolRendererV2 & operator=( const QgsCategorizedSymbolRendererV2 & );
};

View File

@ -147,4 +147,8 @@ class QgsGraduatedSymbolRendererV2 : QgsFeatureRendererV2
protected:
QgsSymbolV2* symbolForValue( double value );
private:
QgsGraduatedSymbolRendererV2( const QgsGraduatedSymbolRendererV2 & );
QgsGraduatedSymbolRendererV2 & operator=( const QgsGraduatedSymbolRendererV2 & );
};

View File

@ -65,4 +65,8 @@ class QgsPointDisplacementRenderer : QgsFeatureRendererV2
void setTolerance( double t );
double tolerance() const;
private:
QgsPointDisplacementRenderer( const QgsPointDisplacementRenderer & );
QgsPointDisplacementRenderer & operator=( const QgsPointDisplacementRenderer & );
};

View File

@ -170,4 +170,8 @@ class QgsFeatureRendererV2
static const unsigned char* _getPolygon( QPolygonF& pts, QList<QPolygonF>& holes, QgsRenderContext& context, const unsigned char* wkb );
void setScaleMethodToSymbol( QgsSymbolV2* symbol, int scaleMethod );
private:
QgsFeatureRendererV2( const QgsFeatureRendererV2 & );
QgsFeatureRendererV2 & operator=( const QgsFeatureRendererV2 & );
};

View File

@ -201,4 +201,8 @@ class QgsRuleBasedRendererV2 : QgsFeatureRendererV2
static void refineRuleRanges( QgsRuleBasedRendererV2::Rule* initialRule, QgsGraduatedSymbolRendererV2* r );
//! take a rule and create a list of new rules with intervals of scales given by the passed scale denominators
static void refineRuleScales( QgsRuleBasedRendererV2::Rule* initialRule, QList<int> scales );
private:
QgsRuleBasedRendererV2( const QgsRuleBasedRendererV2 & );
QgsRuleBasedRendererV2 & operator=( const QgsRuleBasedRendererV2 & );
};

View File

@ -60,4 +60,8 @@ class QgsSingleSymbolRendererV2 : QgsFeatureRendererV2
//! return a list of item text / symbol
//! @note: this method was added in version 1.5
// virtual QgsLegendSymbolList legendSymbolItems();
private:
QgsSingleSymbolRendererV2( const QgsSingleSymbolRendererV2 & );
QgsSingleSymbolRendererV2 & operator=( const QgsSingleSymbolRendererV2 & );
};

View File

@ -414,4 +414,27 @@ typedef unsigned long long qgssize;
#endif
#endif
inline
QString qgsXmlEncode( QString str )
{
// string passed as value to avoid internal copy
str.replace( "&", "&amp;" );
str.replace( "\"", "&quot;" );
str.replace( "'", "&apos;" );
str.replace( "<", "&lt;" );
str.replace( ">", "&gt;" );
return str;
}
inline
QString qgsXmlDecode( QString str )
{
// string passed as value to avoid internal copy
str.replace( "&amp;", "&" );
str.replace( "&quot;", "\"" );
str.replace( "&apos;", "'" );
str.replace( "&lt;", "<" );
str.replace( "&gt;", ">" );
return str;
}
#endif

View File

@ -29,41 +29,37 @@
#include <QSettings> // for legend
QgsRendererCategoryV2::QgsRendererCategoryV2()
: mValue(), mSymbol( 0 ), mLabel()
{
}
QgsRendererCategoryV2::QgsRendererCategoryV2( QVariant value, QgsSymbolV2* symbol, QString label )
: mValue( value ), mSymbol( symbol ), mLabel( label )
: mValue( value )
, mSymbol( symbol )
, mLabel( label )
{
}
QgsRendererCategoryV2::QgsRendererCategoryV2( const QgsRendererCategoryV2& cat )
: mValue( cat.mValue ), mSymbol( 0 ), mLabel( cat.mLabel )
: mValue( cat.mValue )
, mSymbol( cat.mSymbol.get() ? cat.mSymbol->clone() : NULL )
, mLabel( cat.mLabel )
{
if ( cat.mSymbol )
{
mSymbol = cat.mSymbol->clone();
}
}
QgsRendererCategoryV2::~QgsRendererCategoryV2()
// copy+swap idion, the copy is done through the 'pass by value'
QgsRendererCategoryV2& QgsRendererCategoryV2::operator=( QgsRendererCategoryV2 cat )
{
delete mSymbol;
}
QgsRendererCategoryV2& QgsRendererCategoryV2::operator=( const QgsRendererCategoryV2 & cat )
{
mValue = cat.mValue;
mLabel = cat.mLabel;
mSymbol = 0;
if ( cat.mSymbol )
{
mSymbol = cat.mSymbol->clone();
}
swap( cat );
return *this;
}
void QgsRendererCategoryV2::swap( QgsRendererCategoryV2 & cat )
{
std::swap( mValue, cat.mValue );
std::swap( mSymbol, cat.mSymbol );
std::swap( mLabel, cat.mLabel );
}
QVariant QgsRendererCategoryV2::value() const
{
return mValue;
@ -71,7 +67,7 @@ QVariant QgsRendererCategoryV2::value() const
QgsSymbolV2* QgsRendererCategoryV2::symbol() const
{
return mSymbol;
return mSymbol.get();
}
QString QgsRendererCategoryV2::label() const
@ -86,10 +82,7 @@ void QgsRendererCategoryV2::setValue( const QVariant &value )
void QgsRendererCategoryV2::setSymbol( QgsSymbolV2* s )
{
if ( mSymbol == s )
return;
delete mSymbol;
mSymbol = s;
if ( mSymbol.get() != s ) mSymbol.reset( s );
}
void QgsRendererCategoryV2::setLabel( const QString &label )
@ -104,7 +97,7 @@ QString QgsRendererCategoryV2::dump() const
void QgsRendererCategoryV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
if ( !mSymbol.get() || props.value( "attribute", "" ).isEmpty() )
return;
QString attrName = props[ "attribute" ];
@ -135,16 +128,11 @@ void QgsRendererCategoryV2::toSld( QDomDocument &doc, QDomElement &element, QgsS
///////////////////
QgsCategorizedSymbolRendererV2::QgsCategorizedSymbolRendererV2( QString attrName, QgsCategoryList categories )
: QgsFeatureRendererV2( "categorizedSymbol" ),
mAttrName( attrName ),
mCategories( categories ),
mSourceSymbol( NULL ),
mSourceColorRamp( NULL ),
mInvertedColorRamp( false ),
mScaleMethod( DEFAULT_SCALE_METHOD ),
mExpression( 0 ),
mRotationFieldIdx( -1 ),
mSizeScaleFieldIdx( -1 )
: QgsFeatureRendererV2( "categorizedSymbol" )
, mAttrName( attrName )
, mCategories( categories )
, mInvertedColorRamp( false )
, mScaleMethod( DEFAULT_SCALE_METHOD )
{
for ( int i = 0; i < mCategories.count(); ++i )
{
@ -160,9 +148,6 @@ QgsCategorizedSymbolRendererV2::QgsCategorizedSymbolRendererV2( QString attrName
QgsCategorizedSymbolRendererV2::~QgsCategorizedSymbolRendererV2()
{
mCategories.clear(); // this should also call destructors of symbols
delete mSourceSymbol;
delete mSourceColorRamp;
}
void QgsCategorizedSymbolRendererV2::rebuildHash()
@ -202,7 +187,7 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& featu
QVariant value;
if ( mAttrNum == -1 )
{
Q_ASSERT( mExpression );
Q_ASSERT( mExpression.get() );
value = mExpression->evaluate( &feature );
}
else
@ -218,16 +203,12 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& featu
return symbolForValue( QVariant( "" ) );
}
if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
if ( !mRotation.get() && !mSizeScale.get() )
return symbol; // no data-defined rotation/scaling - just return the symbol
// find out rotation, size scale
double rotation = 0;
double sizeScale = 1;
if ( mRotationFieldIdx != -1 )
rotation = attrs[mRotationFieldIdx].toDouble();
if ( mSizeScaleFieldIdx != -1 )
sizeScale = attrs[mSizeScaleFieldIdx].toDouble();
const double rotation = mRotation.get() ? mRotation->evaluate( feature ).toDouble() : 0;
const double sizeScale = mSizeScale.get() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
// take a temporary symbol (or create it if doesn't exist)
QgsSymbolV2* tempSymbol = mTempSymbols[attrs[mAttrNum].toString()];
@ -236,17 +217,14 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& featu
if ( tempSymbol->type() == QgsSymbolV2::Marker )
{
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
if ( mRotationFieldIdx != -1 )
markerSymbol->setAngle( rotation );
if ( mSizeScaleFieldIdx != -1 )
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
markerSymbol->setAngle( rotation );
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
markerSymbol->setScaleMethod( mScaleMethod );
}
else if ( tempSymbol->type() == QgsSymbolV2::Line )
{
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
if ( mSizeScaleFieldIdx != -1 )
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
}
return tempSymbol;
@ -370,23 +348,20 @@ void QgsCategorizedSymbolRendererV2::startRender( QgsRenderContext& context, con
mAttrNum = vlayer ? vlayer->fieldNameIndex( mAttrName ) : -1;
if ( mAttrNum == -1 )
{
mExpression = new QgsExpression( mAttrName );
mExpression.reset( new QgsExpression( mAttrName ) );
mExpression->prepare( vlayer->pendingFields() );
}
mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );
QgsCategoryList::iterator it = mCategories.begin();
for ( ; it != mCategories.end(); ++it )
{
it->symbol()->startRender( context, vlayer );
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
if ( mRotation.get() || mSizeScale.get() )
{
QgsSymbolV2* tempSymbol = it->symbol()->clone();
tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
tempSymbol->setRenderHints(( mRotation.get() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
( mSizeScale.get() ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
tempSymbol->startRender( context, vlayer );
mTempSymbols[ it->value().toString()] = tempSymbol;
}
@ -408,25 +383,15 @@ void QgsCategorizedSymbolRendererV2::stopRender( QgsRenderContext& context )
delete it2.value();
}
mTempSymbols.clear();
delete mExpression;
mExpression.reset();
}
QList<QString> QgsCategorizedSymbolRendererV2::usedAttributes()
{
QSet<QString> attributes;
QgsExpression exp( mAttrName );
foreach ( QString attr, exp.referencedColumns() )
{
attributes << attr;
}
if ( !mRotationField.isEmpty() )
{
attributes.insert( mRotationField );
}
if ( !mSizeScaleField.isEmpty() )
{
attributes.insert( mSizeScaleField );
}
QSet<QString> attributes( exp.referencedColumns().toSet() );
if ( mRotation.get() ) attributes.unite( mRotation->referencedColumns().toSet() );
if ( mSizeScale.get() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
QgsCategoryList::const_iterator catIt = mCategories.constBegin();
for ( ; catIt != mCategories.constEnd(); ++catIt )
@ -451,9 +416,9 @@ QString QgsCategorizedSymbolRendererV2::dump() const
QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone()
{
QgsCategorizedSymbolRendererV2* r = new QgsCategorizedSymbolRendererV2( mAttrName, mCategories );
if ( mSourceSymbol )
if ( mSourceSymbol.get() )
r->setSourceSymbol( mSourceSymbol->clone() );
if ( mSourceColorRamp )
if ( mSourceColorRamp.get() )
{
r->setSourceColorRamp( mSourceColorRamp->clone() );
r->setInvertedColorRamp( mInvertedColorRamp );
@ -469,10 +434,10 @@ void QgsCategorizedSymbolRendererV2::toSld( QDomDocument &doc, QDomElement &elem
{
QgsStringMap props;
props[ "attribute" ] = mAttrName;
if ( !mRotationField.isEmpty() )
props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
if ( !mSizeScaleField.isEmpty() )
props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
if ( !mRotation.get() )
props[ "angle" ] = qgsXmlEncode( mRotation->expression() ).append( "\"" ).prepend( "\"" );
if ( !mSizeScale.get() )
props[ "scale" ] = qgsXmlEncode( mSizeScale->expression() ).append( "\"" ).prepend( "\"" );
// create a Rule for each range
for ( QgsCategoryList::const_iterator it = mCategories.constBegin(); it != mCategories.constEnd(); ++it )
@ -551,12 +516,12 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::create( QDomElement& eleme
QDomElement rotationElem = element.firstChildElement( "rotation" );
if ( !rotationElem.isNull() )
r->setRotationField( rotationElem.attribute( "field" ) );
r->setRotationField( qgsXmlDecode( rotationElem.attribute( "field" ) ) );
QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
if ( !sizeScaleElem.isNull() )
{
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
r->setSizeScaleField( qgsXmlDecode( sizeScaleElem.attribute( "field" ) ) );
r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
}
@ -597,18 +562,18 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
rendererElem.appendChild( symbolsElem );
// save source symbol
if ( mSourceSymbol )
if ( mSourceSymbol.get() )
{
QgsSymbolV2Map sourceSymbols;
sourceSymbols.insert( "0", mSourceSymbol );
sourceSymbols.insert( "0", mSourceSymbol.get() );
QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
rendererElem.appendChild( sourceSymbolElem );
}
// save source color ramp
if ( mSourceColorRamp )
if ( mSourceColorRamp.get() )
{
QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp, doc );
QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.get(), doc );
rendererElem.appendChild( colorRampElem );
QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
invertedElem.setAttribute( "value", mInvertedColorRamp );
@ -616,11 +581,13 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
}
QDomElement rotationElem = doc.createElement( "rotation" );
rotationElem.setAttribute( "field", mRotationField );
if ( mRotation.get() )
rotationElem.setAttribute( "field", qgsXmlEncode( mRotation->expression() ) );
rendererElem.appendChild( rotationElem );
QDomElement sizeScaleElem = doc.createElement( "sizescale" );
sizeScaleElem.setAttribute( "field", mSizeScaleField );
if ( mSizeScale.get() )
sizeScaleElem.setAttribute( "field", qgsXmlEncode( mSizeScale->expression() ) );
sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
rendererElem.appendChild( sizeScaleElem );
@ -673,22 +640,20 @@ QgsLegendSymbolList QgsCategorizedSymbolRendererV2::legendSymbolItems( double sc
QgsSymbolV2* QgsCategorizedSymbolRendererV2::sourceSymbol()
{
return mSourceSymbol;
return mSourceSymbol.get();
}
void QgsCategorizedSymbolRendererV2::setSourceSymbol( QgsSymbolV2* sym )
{
delete mSourceSymbol;
mSourceSymbol = sym;
mSourceSymbol.reset( sym );
}
QgsVectorColorRampV2* QgsCategorizedSymbolRendererV2::sourceColorRamp()
{
return mSourceColorRamp;
return mSourceColorRamp.get();
}
void QgsCategorizedSymbolRendererV2::setSourceColorRamp( QgsVectorColorRampV2* ramp )
{
delete mSourceColorRamp;
mSourceColorRamp = ramp;
mSourceColorRamp.reset( ramp );
}
void QgsCategorizedSymbolRendererV2::updateSymbols( QgsSymbolV2 * sym )

View File

@ -20,6 +20,7 @@
#include "qgsexpression.h"
#include <QHash>
#include <memory>
class QgsVectorColorRampV2;
class QgsVectorLayer;
@ -36,9 +37,7 @@ class CORE_EXPORT QgsRendererCategoryV2
//! copy constructor
QgsRendererCategoryV2( const QgsRendererCategoryV2& cat );
~QgsRendererCategoryV2();
QgsRendererCategoryV2& operator=( const QgsRendererCategoryV2& cat );
QgsRendererCategoryV2& operator=( QgsRendererCategoryV2 cat );
QVariant value() const;
QgsSymbolV2* symbol() const;
@ -55,8 +54,10 @@ class CORE_EXPORT QgsRendererCategoryV2
protected:
QVariant mValue;
QgsSymbolV2* mSymbol;
std::auto_ptr<QgsSymbolV2> mSymbol;
QString mLabel;
void swap( QgsRendererCategoryV2 & other );
};
typedef QList<QgsRendererCategoryV2> QgsCategoryList;
@ -137,14 +138,22 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
void setInvertedColorRamp( bool inverted ) { mInvertedColorRamp = inverted; }
//! @note added in 1.6
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
void setRotationField( QString expression )
{
mRotation.reset( expression.isEmpty() ? NULL : new QgsExpression( expression ) );
Q_ASSERT( !mRotation.get() || !mRotation->hasParserError() );
}
//! @note added in 1.6
QString rotationField() const { return mRotationField; }
QString rotationField() const { return mRotation.get() ? mRotation->expression() : "";}
//! @note added in 1.6
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
void setSizeScaleField( QString expression )
{
mSizeScale.reset( expression.isEmpty() ? NULL : new QgsExpression( expression ) );
Q_ASSERT( !mSizeScale.get() || !mSizeScale->hasParserError() );
}
//! @note added in 1.6
QString sizeScaleField() const { return mSizeScaleField; }
QString sizeScaleField() const { return mSizeScale.get() ? mSizeScale->expression() : ""; }
//! @note added in 2.0
void setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod );
@ -154,17 +163,16 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
protected:
QString mAttrName;
QgsCategoryList mCategories;
QgsSymbolV2* mSourceSymbol;
QgsVectorColorRampV2* mSourceColorRamp;
std::auto_ptr<QgsSymbolV2> mSourceSymbol;
std::auto_ptr<QgsVectorColorRampV2> mSourceColorRamp;
bool mInvertedColorRamp;
QString mRotationField;
QString mSizeScaleField;
std::auto_ptr<QgsExpression> mRotation;
std::auto_ptr<QgsExpression> mSizeScale;
QgsSymbolV2::ScaleMethod mScaleMethod;
QgsExpression* mExpression;
std::auto_ptr<QgsExpression> mExpression;
//! attribute index (derived from attribute name in startRender)
int mAttrNum;
int mRotationFieldIdx, mSizeScaleFieldIdx;
//! hashtable for faster access to symbols
QHash<QString, QgsSymbolV2*> mSymbolHash;

View File

@ -46,29 +46,26 @@ QgsRendererRangeV2::QgsRendererRangeV2( double lowerValue, double upperValue, Qg
QgsRendererRangeV2::QgsRendererRangeV2( const QgsRendererRangeV2& range )
: mLowerValue( range.mLowerValue )
, mUpperValue( range.mUpperValue )
, mSymbol( range.mSymbol.get() ? range.mSymbol->clone() : NULL )
, mLabel( range.mLabel )
{
mSymbol = range.mSymbol->clone();
}
QgsRendererRangeV2::~QgsRendererRangeV2()
// cpy and swap idiom, note that the cpy is done with 'pass by value'
QgsRendererRangeV2& QgsRendererRangeV2::operator=( QgsRendererRangeV2 range )
{
delete mSymbol;
}
QgsRendererRangeV2& QgsRendererRangeV2::operator=( const QgsRendererRangeV2 & range )
{
mLowerValue = range.mLowerValue;
mUpperValue = range.mUpperValue;
mLabel = range.mLabel;
mSymbol = 0;
if ( range.mSymbol )
{
mSymbol = range.mSymbol->clone();
}
swap( range );
return *this;
}
void QgsRendererRangeV2::swap( QgsRendererRangeV2 & other )
{
std::swap( mLowerValue, other.mLowerValue );
std::swap( mUpperValue, other.mUpperValue );
std::swap( mSymbol, other.mSymbol );
std::swap( mLabel, other.mLabel );
}
double QgsRendererRangeV2::lowerValue() const
{
return mLowerValue;
@ -81,7 +78,7 @@ double QgsRendererRangeV2::upperValue() const
QgsSymbolV2* QgsRendererRangeV2::symbol() const
{
return mSymbol;
return mSymbol.get();
}
QString QgsRendererRangeV2::label() const
@ -91,10 +88,7 @@ QString QgsRendererRangeV2::label() const
void QgsRendererRangeV2::setSymbol( QgsSymbolV2* s )
{
if ( mSymbol == s )
return;
delete mSymbol;
mSymbol = s;
if ( mSymbol.get() != s ) mSymbol.reset( s );
}
void QgsRendererRangeV2::setLabel( QString label )
@ -119,7 +113,7 @@ QString QgsRendererRangeV2::dump() const
void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
if ( !mSymbol.get() || props.value( "attribute", "" ).isEmpty() )
return;
QString attrName = props[ "attribute" ];
@ -154,12 +148,8 @@ QgsGraduatedSymbolRendererV2::QgsGraduatedSymbolRendererV2( QString attrName, Qg
mAttrName( attrName ),
mRanges( ranges ),
mMode( Custom ),
mSourceSymbol( NULL ),
mSourceColorRamp( NULL ),
mInvertedColorRamp( false ),
mScaleMethod( DEFAULT_SCALE_METHOD ),
mRotationFieldIdx( -1 ),
mSizeScaleFieldIdx( -1 )
mScaleMethod( DEFAULT_SCALE_METHOD )
{
// TODO: check ranges for sanity (NULL symbols, invalid ranges)
}
@ -167,8 +157,6 @@ QgsGraduatedSymbolRendererV2::QgsGraduatedSymbolRendererV2( QString attrName, Qg
QgsGraduatedSymbolRendererV2::~QgsGraduatedSymbolRendererV2()
{
mRanges.clear(); // should delete all the symbols
delete mSourceSymbol;
delete mSourceColorRamp;
}
QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForValue( double value )
@ -204,16 +192,12 @@ QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForFeature( QgsFeature& feature
if ( symbol == NULL )
return NULL;
if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
if ( !mRotation.get() && !mSizeScale.get() )
return symbol; // no data-defined rotation/scaling - just return the symbol
// find out rotation, size scale
double rotation = 0;
double sizeScale = 1;
if ( mRotationFieldIdx != -1 )
rotation = attrs[mRotationFieldIdx].toDouble();
if ( mSizeScaleFieldIdx != -1 )
sizeScale = attrs[mSizeScaleFieldIdx].toDouble();
const double rotation = mRotation.get() ? mRotation->evaluate( feature ).toDouble() : 0;
const double sizeScale = mSizeScale.get() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
// take a temporary symbol (or create it if doesn't exist)
QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
@ -222,17 +206,14 @@ QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForFeature( QgsFeature& feature
if ( tempSymbol->type() == QgsSymbolV2::Marker )
{
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
if ( mRotationFieldIdx != -1 )
markerSymbol->setAngle( rotation );
if ( mSizeScaleFieldIdx != -1 )
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
markerSymbol->setAngle( rotation );
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
markerSymbol->setScaleMethod( mScaleMethod );
}
else if ( tempSymbol->type() == QgsSymbolV2::Line )
{
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
if ( mSizeScaleFieldIdx != -1 )
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
}
return tempSymbol;
}
@ -244,23 +225,20 @@ void QgsGraduatedSymbolRendererV2::startRender( QgsRenderContext& context, const
if ( mAttrNum == -1 )
{
mExpression = new QgsExpression( mAttrName );
mExpression.reset( new QgsExpression( mAttrName ) );
mExpression->prepare( vlayer->pendingFields() );
}
mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );
QgsRangeList::iterator it = mRanges.begin();
for ( ; it != mRanges.end(); ++it )
{
it->symbol()->startRender( context, vlayer );
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
if ( mRotation.get() || mSizeScale.get() )
{
QgsSymbolV2* tempSymbol = it->symbol()->clone();
tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
tempSymbol->setRenderHints(( mRotation.get() ? QgsSymbolV2::DataDefinedRotation : 0 ) |
( mSizeScale.get() ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
tempSymbol->startRender( context, vlayer );
mTempSymbols[ it->symbol()] = tempSymbol;
}
@ -285,26 +263,15 @@ void QgsGraduatedSymbolRendererV2::stopRender( QgsRenderContext& context )
QList<QString> QgsGraduatedSymbolRendererV2::usedAttributes()
{
QSet<QString> attributes;
QgsExpression exp( mAttrName );
foreach ( QString attr, exp.referencedColumns() )
{
attributes << attr;
}
if ( !mRotationField.isEmpty() )
{
attributes.insert( mRotationField );
}
if ( !mSizeScaleField.isEmpty() )
{
attributes.insert( mSizeScaleField );
}
QSet<QString> attributes( exp.referencedColumns().toSet() );
if ( mRotation.get() ) attributes.unite( mRotation->referencedColumns().toSet() );
if ( mSizeScale.get() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
QgsSymbolV2* symbol = 0;
QgsRangeList::const_iterator range_it = mRanges.constBegin();
for ( ; range_it != mRanges.constEnd(); ++range_it )
{
symbol = range_it->symbol();
QgsSymbolV2* symbol = range_it->symbol();
if ( symbol )
{
attributes.unite( symbol->usedAttributes() );
@ -357,9 +324,9 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::clone()
{
QgsGraduatedSymbolRendererV2* r = new QgsGraduatedSymbolRendererV2( mAttrName, mRanges );
r->setMode( mMode );
if ( mSourceSymbol )
if ( mSourceSymbol.get() )
r->setSourceSymbol( mSourceSymbol->clone() );
if ( mSourceColorRamp )
if ( mSourceColorRamp.get() )
{
r->setSourceColorRamp( mSourceColorRamp->clone() );
r->setInvertedColorRamp( mInvertedColorRamp );
@ -375,10 +342,10 @@ void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &elemen
{
QgsStringMap props;
props[ "attribute" ] = mAttrName;
if ( !mRotationField.isEmpty() )
props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
if ( !mSizeScaleField.isEmpty() )
props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
if ( !mRotation.get() )
props[ "angle" ] = qgsXmlEncode( mRotation->expression() ).append( "\"" ).prepend( "\"" );
if ( !mSizeScale.get() )
props[ "scale" ] = qgsXmlEncode( mSizeScale->expression() ).append( "\"" ).prepend( "\"" );
// create a Rule for each range
for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); ++it )
@ -994,10 +961,8 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::create( QDomElement& element
QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
if ( !sizeScaleElem.isNull() )
{
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
}
r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
// TODO: symbol levels
return r;
@ -1037,18 +1002,18 @@ QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
rendererElem.appendChild( symbolsElem );
// save source symbol
if ( mSourceSymbol )
if ( mSourceSymbol.get() )
{
QgsSymbolV2Map sourceSymbols;
sourceSymbols.insert( "0", mSourceSymbol );
sourceSymbols.insert( "0", mSourceSymbol.get() );
QDomElement sourceSymbolElem = QgsSymbolLayerV2Utils::saveSymbols( sourceSymbols, "source-symbol", doc );
rendererElem.appendChild( sourceSymbolElem );
}
// save source color ramp
if ( mSourceColorRamp )
if ( mSourceColorRamp.get() )
{
QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp, doc );
QDomElement colorRampElem = QgsSymbolLayerV2Utils::saveColorRamp( "[source]", mSourceColorRamp.get(), doc );
rendererElem.appendChild( colorRampElem );
QDomElement invertedElem = doc.createElement( "invertedcolorramp" );
invertedElem.setAttribute( "value", mInvertedColorRamp );
@ -1075,11 +1040,13 @@ QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
}
QDomElement rotationElem = doc.createElement( "rotation" );
rotationElem.setAttribute( "field", mRotationField );
if ( mRotation.get() )
rotationElem.setAttribute( "field", qgsXmlEncode( mRotation->expression() ) );
rendererElem.appendChild( rotationElem );
QDomElement sizeScaleElem = doc.createElement( "sizescale" );
sizeScaleElem.setAttribute( "field", mSizeScaleField );
if ( mSizeScale.get() )
sizeScaleElem.setAttribute( "field", qgsXmlEncode( mSizeScale->expression() ) );
sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
rendererElem.appendChild( sizeScaleElem );
@ -1124,7 +1091,7 @@ QgsLegendSymbolList QgsGraduatedSymbolRendererV2::legendSymbolItems( double scal
if ( rule.isEmpty() || range.label() == rule )
{
QgsSymbolV2* symbol;
if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
if ( !mRotation.get() && !mSizeScale.get() )
{
symbol = range.symbol();
}
@ -1140,22 +1107,21 @@ QgsLegendSymbolList QgsGraduatedSymbolRendererV2::legendSymbolItems( double scal
QgsSymbolV2* QgsGraduatedSymbolRendererV2::sourceSymbol()
{
return mSourceSymbol;
return mSourceSymbol.get();
}
void QgsGraduatedSymbolRendererV2::setSourceSymbol( QgsSymbolV2* sym )
{
delete mSourceSymbol;
mSourceSymbol = sym;
mSourceSymbol.reset( sym );
}
QgsVectorColorRampV2* QgsGraduatedSymbolRendererV2::sourceColorRamp()
{
return mSourceColorRamp;
return mSourceColorRamp.get();
}
void QgsGraduatedSymbolRendererV2::setSourceColorRamp( QgsVectorColorRampV2* ramp )
{
delete mSourceColorRamp;
mSourceColorRamp = ramp;
mSourceColorRamp.reset( ramp );
}
void QgsGraduatedSymbolRendererV2::updateColorRamp( QgsVectorColorRampV2 *ramp, bool inverted )

View File

@ -18,6 +18,7 @@
#include "qgssymbolv2.h"
#include "qgsrendererv2.h"
#include "qgsexpression.h"
#include <memory>
class CORE_EXPORT QgsRendererRangeV2
{
@ -26,9 +27,9 @@ class CORE_EXPORT QgsRendererRangeV2
QgsRendererRangeV2( double lowerValue, double upperValue, QgsSymbolV2* symbol, QString label );
QgsRendererRangeV2( const QgsRendererRangeV2& range );
~QgsRendererRangeV2();
// defaut dtor is ok
QgsRendererRangeV2& operator=( const QgsRendererRangeV2& range );
QgsRendererRangeV2& operator=( QgsRendererRangeV2 range );
double lowerValue() const;
double upperValue() const;
@ -48,8 +49,11 @@ class CORE_EXPORT QgsRendererRangeV2
protected:
double mLowerValue, mUpperValue;
QgsSymbolV2* mSymbol;
std::auto_ptr<QgsSymbolV2> mSymbol;
QString mLabel;
// for cpy+swap idiom
void swap( QgsRendererRangeV2 & other );
};
typedef QList<QgsRendererRangeV2> QgsRangeList;
@ -61,6 +65,7 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
{
public:
QgsGraduatedSymbolRendererV2( QString attrName = QString(), QgsRangeList ranges = QgsRangeList() );
QgsGraduatedSymbolRendererV2( const QgsGraduatedSymbolRendererV2 & other );
virtual ~QgsGraduatedSymbolRendererV2();
@ -159,14 +164,22 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
void updateSymbols( QgsSymbolV2* sym );
//! @note added in 1.6
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
void setRotationField( QString expression )
{
mRotation.reset( expression.isEmpty() ? NULL : new QgsExpression( expression ) );
Q_ASSERT( !mRotation.get() || !mRotation->hasParserError() );
}
//! @note added in 1.6
QString rotationField() const { return mRotationField; }
QString rotationField() const { return mRotation.get() ? mRotation->expression() : "";}
//! @note added in 1.6
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
void setSizeScaleField( QString expression )
{
mSizeScale.reset( expression.isEmpty() ? NULL : new QgsExpression( expression ) );
Q_ASSERT( !mSizeScale.get() || !mSizeScale->hasParserError() );
}
//! @note added in 1.6
QString sizeScaleField() const { return mSizeScaleField; }
QString sizeScaleField() const { return mSizeScale.get() ? mSizeScale->expression() : ""; }
//! @note added in 2.0
void setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod );
@ -178,21 +191,21 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
QString mAttrName;
QgsRangeList mRanges;
Mode mMode;
QgsSymbolV2* mSourceSymbol;
QgsVectorColorRampV2* mSourceColorRamp;
std::auto_ptr<QgsSymbolV2> mSourceSymbol;
std::auto_ptr<QgsVectorColorRampV2> mSourceColorRamp;
bool mInvertedColorRamp;
QString mRotationField;
QString mSizeScaleField;
std::auto_ptr<QgsExpression> mRotation;
std::auto_ptr<QgsExpression> mSizeScale;
QgsSymbolV2::ScaleMethod mScaleMethod;
QgsExpression* mExpression;
std::auto_ptr<QgsExpression> mExpression;
//! attribute index (derived from attribute name in startRender)
int mAttrNum;
int mRotationFieldIdx, mSizeScaleFieldIdx;
//! temporary symbols, used for data-defined rotation and scaling
QHash<QgsSymbolV2*, QgsSymbolV2*> mTempSymbols;
QgsSymbolV2* symbolForValue( double value );
};
#endif // QGSGRADUATEDSYMBOLRENDERERV2_H

View File

@ -204,6 +204,9 @@ class CORE_EXPORT QgsFeatureRendererV2
int mCurrentVertexMarkerType;
/** The current size of editing marker */
int mCurrentVertexMarkerSize;
private:
Q_DISABLE_COPY( QgsFeatureRendererV2 )
};
class QgsRendererV2Widget; // why does SIP fail, when this isn't here

View File

@ -27,79 +27,89 @@
#include <QDomElement>
QgsSingleSymbolRendererV2::QgsSingleSymbolRendererV2( QgsSymbolV2* symbol )
: QgsFeatureRendererV2( "singleSymbol" ), mScaleMethod( DEFAULT_SCALE_METHOD ), mRotationFieldIdx( -1 ),
mSizeScaleFieldIdx( -1 ), mTempSymbol( NULL )
: QgsFeatureRendererV2( "singleSymbol" )
, mSymbol( symbol )
, mScaleMethod( DEFAULT_SCALE_METHOD )
{
Q_ASSERT( symbol );
mSymbol = symbol;
}
// we need to clone symbol
QgsSingleSymbolRendererV2::QgsSingleSymbolRendererV2( const QgsSingleSymbolRendererV2 & src )
: QgsFeatureRendererV2( "singleSymbol" )
, mSymbol( src.mSymbol.get() ? src.mSymbol->clone() : NULL )
, mRotation( src.mRotation.get() ? new QgsExpression( src.mRotation->expression() ) : NULL )
, mSizeScale( src.mSizeScale.get() ? new QgsExpression( src.mSizeScale->expression() ) : NULL )
, mScaleMethod( src.mScaleMethod )
, mTempSymbol( src.mTempSymbol.get() ? src.mTempSymbol->clone() : NULL )
{
}
// this is a copy + swap idiom implementation
// the copy is done with the 'pass by value'
QgsSingleSymbolRendererV2 & QgsSingleSymbolRendererV2::operator=( QgsSingleSymbolRendererV2 other )
{
swap( other );
return *this;
}
void QgsSingleSymbolRendererV2::swap( QgsSingleSymbolRendererV2 & other )
{
std::swap( mSymbol, other.mSymbol );
std::swap( mRotation, other.mRotation );
std::swap( mSizeScale, other.mSizeScale );
std::swap( mScaleMethod, other.mScaleMethod );
std::swap( mTempSymbol, other.mTempSymbol );
std::swap( mOrigSize, other.mOrigSize );
}
QgsSingleSymbolRendererV2::~QgsSingleSymbolRendererV2()
{
delete mSymbol;
}
QgsSymbolV2* QgsSingleSymbolRendererV2::symbolForFeature( QgsFeature& feature )
{
if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
return mSymbol;
if ( !mRotation.get() && !mSizeScale.get() ) return mSymbol.get();
double rotation = 0;
double sizeScale = 1;
if ( mRotationFieldIdx != -1 )
{
rotation = feature.attribute( mRotationFieldIdx ).toDouble();
}
if ( mSizeScaleFieldIdx != -1 )
{
sizeScale = feature.attribute( mSizeScaleFieldIdx ).toDouble();
}
const double rotation = mRotation.get() ? mRotation->evaluate( feature ).toDouble() : 0;
const double sizeScale = mSizeScale.get() ? mSizeScale->evaluate( feature ).toDouble() : 1.;
if ( mTempSymbol->type() == QgsSymbolV2::Marker )
{
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol );
if ( mRotationFieldIdx != -1 )
markerSymbol->setAngle( rotation );
if ( mSizeScaleFieldIdx != -1 )
markerSymbol->setSize( sizeScale * mOrigSize );
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol.get() );
markerSymbol->setAngle( rotation );
markerSymbol->setSize( sizeScale * mOrigSize );
markerSymbol->setScaleMethod( mScaleMethod );
}
else if ( mTempSymbol->type() == QgsSymbolV2::Line )
{
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol );
if ( mSizeScaleFieldIdx != -1 )
lineSymbol->setWidth( sizeScale * mOrigSize );
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol.get() );
lineSymbol->setWidth( sizeScale * mOrigSize );
}
else if ( mTempSymbol->type() == QgsSymbolV2::Fill )
{
QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol );
if ( mRotationFieldIdx != -1 )
fillSymbol->setAngle( rotation );
QgsFillSymbolV2* fillSymbol = static_cast<QgsFillSymbolV2*>( mTempSymbol.get() );
fillSymbol->setAngle( rotation );
}
return mTempSymbol;
return mTempSymbol.get();
}
void QgsSingleSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
if ( !mSymbol )
{
return;
}
mRotationFieldIdx = mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField );
mSizeScaleFieldIdx = mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField );
if ( !mSymbol.get() ) return;
mSymbol->startRender( context, vlayer );
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
if ( mRotation.get() || mSizeScale.get() )
{
// we are going to need a temporary symbol
mTempSymbol = mSymbol->clone();
mTempSymbol.reset( mSymbol->clone() );
int hints = 0;
if ( mRotationFieldIdx != -1 )
if ( mRotation.get() )
hints |= QgsSymbolV2::DataDefinedRotation;
if ( mSizeScaleFieldIdx != -1 )
if ( mSizeScale.get() )
hints |= QgsSymbolV2::DataDefinedSizeScale;
mTempSymbol->setRenderHints( hints );
@ -107,11 +117,11 @@ void QgsSingleSymbolRendererV2::startRender( QgsRenderContext& context, const Qg
if ( mSymbol->type() == QgsSymbolV2::Marker )
{
mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol )->size();
mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol.get() )->size();
}
else if ( mSymbol->type() == QgsSymbolV2::Line )
{
mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol )->width();
mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol.get() )->width();
}
else
{
@ -122,67 +132,47 @@ void QgsSingleSymbolRendererV2::startRender( QgsRenderContext& context, const Qg
void QgsSingleSymbolRendererV2::stopRender( QgsRenderContext& context )
{
if ( !mSymbol )
{
return;
}
if ( !mSymbol.get() ) return;
mSymbol->stopRender( context );
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
if ( mRotation.get() || mSizeScale.get() )
{
// we are going to need a temporary symbol
mTempSymbol->stopRender( context );
delete mTempSymbol;
mTempSymbol = NULL;
mTempSymbol.reset();
}
}
QList<QString> QgsSingleSymbolRendererV2::usedAttributes()
{
QSet<QString> attributes;
if ( mSymbol )
{
attributes.unite( mSymbol->usedAttributes() );
}
if ( !mRotationField.isEmpty() )
{
attributes.insert( mRotationField );
}
if ( !mSizeScaleField.isEmpty() )
{
attributes.insert( mSizeScaleField );
}
if ( mSymbol.get() ) attributes.unite( mSymbol->usedAttributes() );
if ( mRotation.get() ) attributes.unite( mRotation->referencedColumns().toSet() );
if ( mSizeScale.get() ) attributes.unite( mSizeScale->referencedColumns().toSet() );
return attributes.toList();
}
QgsSymbolV2* QgsSingleSymbolRendererV2::symbol() const
{
return mSymbol;
return mSymbol.get();
}
void QgsSingleSymbolRendererV2::setSymbol( QgsSymbolV2* s )
{
Q_ASSERT( s );
delete mSymbol;
mSymbol = s;
mSymbol.reset( s );
}
void QgsSingleSymbolRendererV2::setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod )
{
mScaleMethod = scaleMethod;
setScaleMethodToSymbol( mSymbol, scaleMethod );
setScaleMethodToSymbol( mSymbol.get(), scaleMethod );
}
QString QgsSingleSymbolRendererV2::dump() const
{
if ( mSymbol )
{
return QString( "SINGLE: %1" ).arg( mSymbol->dump() );
}
else
{
return "";
}
return mSymbol.get() ? QString( "SINGLE: %1" ).arg( mSymbol->dump() ) : "" ;
}
QgsFeatureRendererV2* QgsSingleSymbolRendererV2::clone()
@ -198,10 +188,10 @@ QgsFeatureRendererV2* QgsSingleSymbolRendererV2::clone()
void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
{
QgsStringMap props;
if ( !mRotationField.isEmpty() )
props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
if ( !mSizeScaleField.isEmpty() )
props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );
if ( mRotation.get() )
props[ "angle" ] = qgsXmlEncode( mRotation->expression() ).append( "\"" ).prepend( "\"" );
if ( mSizeScale.get() )
props[ "scale" ] = qgsXmlEncode( mSizeScale->expression() ).append( "\"" ).prepend( "\"" );
QDomElement ruleElem = doc.createElement( "se:Rule" );
element.appendChild( ruleElem );
@ -210,13 +200,13 @@ void QgsSingleSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element )
nameElem.appendChild( doc.createTextNode( "Single symbol" ) );
ruleElem.appendChild( nameElem );
mSymbol->toSld( doc, ruleElem, props );
if ( mSymbol.get() ) mSymbol->toSld( doc, ruleElem, props );
}
QgsSymbolV2List QgsSingleSymbolRendererV2::symbols()
{
QgsSymbolV2List lst;
lst.append( mSymbol );
lst.append( mSymbol.get() );
return lst;
}
@ -238,12 +228,12 @@ QgsFeatureRendererV2* QgsSingleSymbolRendererV2::create( QDomElement& element )
QDomElement rotationElem = element.firstChildElement( "rotation" );
if ( !rotationElem.isNull() )
r->setRotationField( rotationElem.attribute( "field" ) );
r->setRotationField( qgsXmlDecode( rotationElem.attribute( "field" ) ) );
QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
if ( !sizeScaleElem.isNull() )
{
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
r->setSizeScaleField( qgsXmlDecode( sizeScaleElem.attribute( "field" ) ) );
r->setScaleMethod( QgsSymbolLayerV2Utils::decodeScaleMethod( sizeScaleElem.attribute( "scalemethod" ) ) );
}
@ -346,16 +336,18 @@ QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
rendererElem.setAttribute( "symbollevels", ( mUsingSymbolLevels ? "1" : "0" ) );
QgsSymbolV2Map symbols;
symbols["0"] = mSymbol;
symbols["0"] = mSymbol.get();
QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
rendererElem.appendChild( symbolsElem );
QDomElement rotationElem = doc.createElement( "rotation" );
rotationElem.setAttribute( "field", mRotationField );
if ( mRotation.get() )
rotationElem.setAttribute( "field", qgsXmlEncode( mRotation->expression() ) );
rendererElem.appendChild( rotationElem );
QDomElement sizeScaleElem = doc.createElement( "sizescale" );
sizeScaleElem.setAttribute( "field", mSizeScaleField );
if ( mSizeScale.get() )
sizeScaleElem.setAttribute( "field", qgsXmlEncode( mSizeScale->expression() ) );
sizeScaleElem.setAttribute( "scalemethod", QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod ) );
rendererElem.appendChild( sizeScaleElem );
@ -365,9 +357,9 @@ QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
QgsLegendSymbologyList QgsSingleSymbolRendererV2::legendSymbologyItems( QSize iconSize )
{
QgsLegendSymbologyList lst;
if ( mSymbol )
if ( mSymbol.get() )
{
QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol, iconSize );
QPixmap pix = QgsSymbolLayerV2Utils::symbolPreviewPixmap( mSymbol.get(), iconSize );
lst << qMakePair( QString(), pix );
}
return lst;
@ -378,6 +370,6 @@ QgsLegendSymbolList QgsSingleSymbolRendererV2::legendSymbolItems( double scaleDe
Q_UNUSED( scaleDenominator );
Q_UNUSED( rule );
QgsLegendSymbolList lst;
lst << qMakePair( QString(), mSymbol );
lst << qMakePair( QString(), mSymbol.get() );
return lst;
}

View File

@ -18,12 +18,17 @@
#include "qgis.h"
#include "qgsrendererv2.h"
#include "qgssymbolv2.h"
#include "qgsexpression.h"
#include <memory>
class CORE_EXPORT QgsSingleSymbolRendererV2 : public QgsFeatureRendererV2
{
public:
QgsSingleSymbolRendererV2( QgsSymbolV2* symbol );
QgsSingleSymbolRendererV2( const QgsSingleSymbolRendererV2 & );
QgsSingleSymbolRendererV2 & operator=( QgsSingleSymbolRendererV2 other );
virtual ~QgsSingleSymbolRendererV2();
@ -39,14 +44,22 @@ class CORE_EXPORT QgsSingleSymbolRendererV2 : public QgsFeatureRendererV2
void setSymbol( QgsSymbolV2* s );
//! @note added in 1.5
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
void setRotationField( QString expression )
{
mRotation.reset( expression.isEmpty() ? NULL : new QgsExpression( expression ) );
Q_ASSERT( !mRotation.get() || !mRotation->hasParserError() );
}
//! @note added in 1.5
QString rotationField() const { return mRotationField; }
QString rotationField() const { return mRotation.get() ? mRotation->expression() : ""; }
//! @note added in 1.5
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
void setSizeScaleField( QString expression )
{
mSizeScale.reset( expression.isEmpty() ? NULL : new QgsExpression( expression ) );
Q_ASSERT( !mSizeScale.get() || !mSizeScale->hasParserError() );
}
//! @note added in 1.5
QString sizeScaleField() const { return mSizeScaleField; }
QString sizeScaleField() const { return mSizeScale.get() ? mSizeScale->expression() : ""; }
//! @note added in 2.0
void setScaleMethod( QgsSymbolV2::ScaleMethod scaleMethod );
@ -81,15 +94,17 @@ class CORE_EXPORT QgsSingleSymbolRendererV2 : public QgsFeatureRendererV2
virtual QgsLegendSymbolList legendSymbolItems( double scaleDenominator = -1, QString rule = "" );
protected:
QgsSymbolV2* mSymbol;
QString mRotationField;
QString mSizeScaleField;
std::auto_ptr<QgsSymbolV2> mSymbol;
std::auto_ptr<QgsExpression> mRotation;
std::auto_ptr<QgsExpression> mSizeScale;
QgsSymbolV2::ScaleMethod mScaleMethod;
// temporary stuff for rendering
int mRotationFieldIdx, mSizeScaleFieldIdx;
QgsSymbolV2* mTempSymbol;
std::auto_ptr<QgsSymbolV2> mTempSymbol;
double mOrigSize;
// for copy and swap idiom for assignment operator
void swap( QgsSingleSymbolRendererV2 & other );
};

View File

@ -419,7 +419,7 @@ QgsCategorizedSymbolRendererV2Widget::QgsCategorizedSymbolRendererV2Widget( QgsV
advMenu->addAction( tr( "Symbol levels..." ), this, SLOT( showSymbolLevels() ) );
mDataDefinedMenus = new QgsRendererV2DataDefinedMenus( advMenu, mLayer->pendingFields(),
mDataDefinedMenus = new QgsRendererV2DataDefinedMenus( advMenu, mLayer,
mRenderer->rotationField(), mRenderer->sizeScaleField(), mRenderer->scaleMethod() );
connect( mDataDefinedMenus, SIGNAL( rotationFieldChanged( QString ) ), this, SLOT( rotationFieldChanged( QString ) ) );
connect( mDataDefinedMenus, SIGNAL( sizeScaleFieldChanged( QString ) ), this, SLOT( sizeScaleFieldChanged( QString ) ) );

View File

@ -408,7 +408,7 @@ QgsGraduatedSymbolRendererV2Widget::QgsGraduatedSymbolRendererV2Widget( QgsVecto
advMenu->addAction( tr( "Symbol levels..." ), this, SLOT( showSymbolLevels() ) );
mDataDefinedMenus = new QgsRendererV2DataDefinedMenus( advMenu, mLayer->pendingFields(),
mDataDefinedMenus = new QgsRendererV2DataDefinedMenus( advMenu, mLayer,
mRenderer->rotationField(), mRenderer->sizeScaleField(), mRenderer->scaleMethod() );
connect( mDataDefinedMenus, SIGNAL( rotationFieldChanged( QString ) ), this, SLOT( rotationFieldChanged( QString ) ) );
connect( mDataDefinedMenus, SIGNAL( sizeScaleFieldChanged( QString ) ), this, SLOT( sizeScaleFieldChanged( QString ) ) );

View File

@ -16,10 +16,12 @@
#include "qgssymbolv2.h"
#include "qgsvectorlayer.h"
#include <QColorDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <QMenu>
#include "qgssymbollevelsv2dialog.h"
#include "qgsexpressionbuilderdialog.h"
QgsRendererV2Widget::QgsRendererV2Widget( QgsVectorLayer* layer, QgsStyleV2* style )
@ -179,8 +181,8 @@ void QgsRendererV2Widget::showSymbolLevelsDialog( QgsFeatureRendererV2* r )
#include "qgsfield.h"
#include <QMenu>
QgsRendererV2DataDefinedMenus::QgsRendererV2DataDefinedMenus( QMenu* menu, const QgsFields& flds, QString rotationField, QString sizeScaleField, QgsSymbolV2::ScaleMethod scaleMethod )
: QObject( menu ), mFlds( flds )
QgsRendererV2DataDefinedMenus::QgsRendererV2DataDefinedMenus( QMenu* menu, QgsVectorLayer* layer, QString rotationField, QString sizeScaleField, QgsSymbolV2::ScaleMethod scaleMethod )
: QObject( menu ), mLayer( layer )
{
mRotationMenu = new QMenu( tr( "Rotation field" ) );
mSizeScaleMenu = new QMenu( tr( "Size scale field" ) );
@ -189,8 +191,8 @@ QgsRendererV2DataDefinedMenus::QgsRendererV2DataDefinedMenus( QMenu* menu, const
mSizeAttributeActionGroup = new QActionGroup( mSizeScaleMenu );
mSizeMethodActionGroup = new QActionGroup( mSizeScaleMenu );
populateMenu( mRotationMenu, SLOT( rotationFieldSelected( QAction* a ) ), rotationField, mRotationAttributeActionGroup );
populateMenu( mSizeScaleMenu, SLOT( sizeScaleFieldSelected( QAction* a ) ), sizeScaleField, mSizeAttributeActionGroup );
populateMenu( mRotationMenu, rotationField, mRotationAttributeActionGroup );
populateMenu( mSizeScaleMenu, sizeScaleField, mSizeAttributeActionGroup );
mSizeScaleMenu->addSeparator();
@ -213,6 +215,10 @@ QgsRendererV2DataDefinedMenus::QgsRendererV2DataDefinedMenus( QMenu* menu, const
menu->addMenu( mRotationMenu );
menu->addMenu( mSizeScaleMenu );
connect( mSizeMethodActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( scaleMethodSelected( QAction* ) ) );
connect( mRotationAttributeActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( rotationFieldSelected( QAction* ) ) );
connect( mSizeAttributeActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( sizeScaleFieldSelected( QAction* ) ) );
}
QgsRendererV2DataDefinedMenus::~QgsRendererV2DataDefinedMenus()
@ -224,19 +230,23 @@ QgsRendererV2DataDefinedMenus::~QgsRendererV2DataDefinedMenus()
delete mSizeScaleMenu;
}
void QgsRendererV2DataDefinedMenus::populateMenu( QMenu* menu, const char* slot, QString fieldName, QActionGroup *actionGroup )
void QgsRendererV2DataDefinedMenus::populateMenu( QMenu* menu, QString fieldName, QActionGroup *actionGroup )
{
Q_UNUSED( slot );
QAction* aExpr = new QAction( tr( "- expression -" ), actionGroup );
aExpr->setCheckable( true );
menu->addAction( aExpr );
menu->addSeparator();
QAction* aNo = new QAction( tr( "- no field -" ), actionGroup );
aNo->setCheckable( true );
menu->addAction( aNo );
menu->addSeparator();
bool hasField = false;
const QgsFields & flds = mLayer->pendingFields();
//const QgsFieldMap& flds = mLayer->pendingFields();
for ( int idx = 0; idx < mFlds.count(); ++idx )
for ( int idx = 0; idx < flds.count(); ++idx )
{
const QgsField& fld = mFlds[idx];
const QgsField& fld = flds[idx];
if ( fld.type() == QVariant::Int || fld.type() == QVariant::Double )
{
QAction* a = new QAction( fld.name(), actionGroup );
@ -252,12 +262,17 @@ void QgsRendererV2DataDefinedMenus::populateMenu( QMenu* menu, const char* slot,
if ( !hasField )
{
aNo->setChecked( true );
if ( fieldName.isEmpty() )
{
aNo->setChecked( true );
}
else
{
aExpr->setChecked( true );
aExpr->setText( tr( "- expression -" ) + fieldName );
}
}
connect( mSizeMethodActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( scaleMethodSelected( QAction* ) ) );
connect( mRotationAttributeActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( rotationFieldSelected( QAction* ) ) );
connect( mSizeAttributeActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( sizeScaleFieldSelected( QAction* ) ) );
}
void QgsRendererV2DataDefinedMenus::rotationFieldSelected( QAction* a )
@ -270,7 +285,19 @@ void QgsRendererV2DataDefinedMenus::rotationFieldSelected( QAction* a )
updateMenu( mRotationAttributeActionGroup, fldName );
#endif
if ( fldName == tr( "- no field -" ) )
{
fldName = QString();
}
else if ( fldName.startsWith( tr( "- expression -" ) ) )
{
QString expr( fldName );
expr.replace( 0, tr( "- expression -" ).length(), "" );
QgsExpressionBuilderDialog dialog( mLayer, expr );
if ( !dialog.exec() ) return;
fldName = dialog.expressionText();
Q_ASSERT( !QgsExpression( fldName ).hasParserError() );
a->setText( tr( "- expression -" ) + fldName );
}
emit rotationFieldChanged( fldName );
}
@ -285,7 +312,19 @@ void QgsRendererV2DataDefinedMenus::sizeScaleFieldSelected( QAction* a )
updateMenu( mSizeAttributeActionGroup, fldName );
#endif
if ( fldName == tr( "- no field -" ) )
{
fldName = QString();
}
else if ( fldName.startsWith( tr( "- expression -" ) ) )
{
QString expr( fldName );
expr.replace( 0, tr( "- expression -" ).length(), "" );
QgsExpressionBuilderDialog dialog( mLayer, expr );
if ( !dialog.exec() ) return;
fldName = dialog.expressionText();
Q_ASSERT( !QgsExpression( fldName ).hasParserError() );
a->setText( tr( "- expression -" ) + fldName );
}
emit sizeScaleFieldChanged( fldName );
}

View File

@ -98,10 +98,10 @@ class QgsRendererV2DataDefinedMenus : public QObject
public:
QgsRendererV2DataDefinedMenus( QMenu* menu, const QgsFields& flds, QString rotationField, QString sizeScaleField, QgsSymbolV2::ScaleMethod scaleMethod );
QgsRendererV2DataDefinedMenus( QMenu* menu, QgsVectorLayer* layer, QString rotationField, QString sizeScaleField, QgsSymbolV2::ScaleMethod scaleMethod );
~QgsRendererV2DataDefinedMenus();
void populateMenu( QMenu* menu, const char* slot, QString fieldName, QActionGroup *actionGroup );
void populateMenu( QMenu* menu, QString fieldName, QActionGroup *actionGroup );
#if 0
void updateMenu( QActionGroup* actionGroup, QString fieldName );
#endif
@ -123,7 +123,7 @@ class QgsRendererV2DataDefinedMenus : public QObject
QActionGroup *mSizeMethodActionGroup;
QActionGroup *mRotationAttributeActionGroup;
QActionGroup *mSizeAttributeActionGroup;
const QgsFields& mFlds;
QgsVectorLayer* mLayer;
};
#endif // QGSRENDERERV2WIDGET_H

View File

@ -66,7 +66,7 @@ QgsSingleSymbolRendererV2Widget::QgsSingleSymbolRendererV2Widget( QgsVectorLayer
advMenu->addAction( tr( "Symbol levels..." ), this, SLOT( showSymbolLevels() ) );
mDataDefinedMenus = new QgsRendererV2DataDefinedMenus( advMenu, mLayer->pendingFields(),
mDataDefinedMenus = new QgsRendererV2DataDefinedMenus( advMenu, mLayer,
mRenderer->rotationField(), mRenderer->sizeScaleField(), mRenderer->scaleMethod() );
connect( mDataDefinedMenus, SIGNAL( rotationFieldChanged( QString ) ), this, SLOT( rotationFieldChanged( QString ) ) );
connect( mDataDefinedMenus, SIGNAL( sizeScaleFieldChanged( QString ) ), this, SLOT( sizeScaleFieldChanged( QString ) ) );