37 changes: 24 additions & 13 deletions src/app/qgsmaptoolfeatureaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ void QgsMapToolFeatureAction::canvasReleaseEvent( QMouseEvent *e )
return;
}

if ( !mCanvas->layers().contains( layer ) )
{
// do not run actions on hidden layers
return;
}

QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
if ( vlayer->actions()->size() == 0 )
{
Expand Down Expand Up @@ -110,7 +116,7 @@ bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y )
if ( identifyValue <= 0.0 )
identifyValue = QGis::DEFAULT_IDENTIFY_RADIUS;

QgsFeature feat;
QgsFeatureList featList;

// toLayerCoordinates will throw an exception for an 'invalid' point.
// For example, if you project a world map onto a globe using EPSG 2163
Expand All @@ -130,10 +136,8 @@ bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y )

layer->select( layer->pendingAllAttributesList(), r, true, true );
QgsFeature f;
if ( layer->nextFeature( f ) )
feat = QgsFeature( f );
else
return false;
while ( layer->nextFeature( f ) )
featList << QgsFeature( f );
}
catch ( QgsCsException & cse )
{
Expand All @@ -142,15 +146,22 @@ bool QgsMapToolFeatureAction::doAction( QgsVectorLayer *layer, int x, int y )
QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
}

int action = layer->actions()->defaultAction();
if ( featList.size() == 0 )
return false;

// define custom substitutions: layer id and clicked coords
QMap<QString, QVariant> substitutionMap;
substitutionMap.insert( "$layerid", layer->id() );
point = toLayerCoordinates( layer, point );
substitutionMap.insert( "$clickx", point.x() );
substitutionMap.insert( "$clicky", point.y() );
foreach ( QgsFeature feat, featList )
{
int actionIdx = layer->actions()->defaultAction();

// define custom substitutions: layer id and clicked coords
QMap<QString, QVariant> substitutionMap;
substitutionMap.insert( "$layerid", layer->id() );
point = toLayerCoordinates( layer, point );
substitutionMap.insert( "$clickx", point.x() );
substitutionMap.insert( "$clicky", point.y() );

layer->actions()->doAction( actionIdx, feat, &substitutionMap );
}

layer->actions()->doAction( action, feat, &substitutionMap );
return true;
}
107 changes: 72 additions & 35 deletions src/app/qgsmaptoolrotatepointsymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#include "qgsmapcanvas.h"
#include "qgspointrotationitem.h"
#include "qgsrenderer.h"
#include "qgsrendererv2.h"
#include "qgssymbol.h"
#include "qgssymbolv2.h"
#include "qgsvectorlayer.h"
#include <QGraphicsPixmapItem>
#include <QMessageBox>
Expand Down Expand Up @@ -222,37 +224,54 @@ void QgsMapToolRotatePointSymbols::canvasReleaseEvent( QMouseEvent *e )
mCanvas->refresh();
}

int QgsMapToolRotatePointSymbols::layerRotationAttributes( const QgsVectorLayer* vl, QList<int>& attList )
int QgsMapToolRotatePointSymbols::layerRotationAttributes( QgsVectorLayer* vl, QList<int>& attList )
{
attList.clear();
if ( !vl )
{
return 1;
}

//get renderer
//old symbology
const QgsRenderer* layerRenderer = vl->renderer();
if ( !layerRenderer )
if ( layerRenderer )
{
return 2;
}
//get renderer symbols
const QList<QgsSymbol*> rendererSymbols = layerRenderer->symbols();
int currentRotationAttribute;

//get renderer symbols
const QList<QgsSymbol*> rendererSymbols = layerRenderer->symbols();
int currentRotationAttribute;
QList<QgsSymbol*>::const_iterator symbolIt = rendererSymbols.constBegin();
for ( ; symbolIt != rendererSymbols.constEnd(); ++symbolIt )
{
currentRotationAttribute = ( *symbolIt )->rotationClassificationField();
if ( currentRotationAttribute >= 0 )
{
attList.push_back( currentRotationAttribute );
}
}
return 0;
}

QList<QgsSymbol*>::const_iterator symbolIt = rendererSymbols.constBegin();
for ( ; symbolIt != rendererSymbols.constEnd(); ++symbolIt )
//new symbology
const QgsFeatureRendererV2* symbologyNgRenderer = vl->rendererV2();
if ( symbologyNgRenderer )
{
currentRotationAttribute = ( *symbolIt )->rotationClassificationField();
if ( currentRotationAttribute >= 0 )
//rotation field is supported for QgsSingleSymbolRendererV2, QgsCategorizedRendererV2, QgsUniqueCategorizedRendererV2
QString rotationFieldName = symbologyNgRenderer->rotationField();

if ( !rotationFieldName.isEmpty() )
{
attList.push_back( currentRotationAttribute );
attList.push_back( vl->fieldNameIndex( rotationFieldName ) );
}
return 0;
}
return 0;

//no renderer
return 2;
}



double QgsMapToolRotatePointSymbols::calculateAzimut( const QPoint& mousePos )
{
int dx = mousePos.x() - mSnappedPoint.x();
Expand All @@ -267,10 +286,25 @@ void QgsMapToolRotatePointSymbols::createPixmapItem( QgsFeature& f )
return;
}

if ( mActiveLayer && mActiveLayer->renderer() )
//get reference to current render context
QgsMapRenderer* mapRenderer = mCanvas->mapRenderer();
if ( !mapRenderer )
{
return;
}
QgsRenderContext* renderContext = mCanvas->mapRenderer()->rendererContext();
if ( !renderContext )
{
return;
}

//get the image that is used for that symbol, but without point rotation
QImage pointImage;
QgsRenderer* r = 0;
QgsFeatureRendererV2* rv2 = 0;

if ( mActiveLayer && mActiveLayer->renderer() ) //old symbology
{
//get the image that is used for that symbol, but without point rotation
QImage pointImage;
//copy renderer
QgsRenderer* r = mActiveLayer->renderer()->clone();

Expand All @@ -282,32 +316,35 @@ void QgsMapToolRotatePointSymbols::createPixmapItem( QgsFeature& f )
( *it )->setRotationClassificationField( -1 );
}

r->renderFeature( *renderContext, f, &pointImage, false );
}
else if ( mActiveLayer && mActiveLayer->rendererV2() ) //symbology-ng
{
rv2 = mActiveLayer->rendererV2()->clone();
rv2->setRotationField( "" );
rv2->startRender( *renderContext, mActiveLayer );

//get reference to current render context
QgsMapRenderer* mapRenderer = mCanvas->mapRenderer();
if ( !mapRenderer )
{
delete r;
return;
}
QgsRenderContext* renderContext = mCanvas->mapRenderer()->rendererContext(); //todo: check if pointers are not 0
if ( !renderContext )
QgsSymbolV2* symbolV2 = rv2->symbolForFeature( f );
if ( symbolV2 )
{
delete r;
return;
pointImage = symbolV2->bigSymbolPreviewImage();
}

r->renderFeature( *renderContext, f, &pointImage, false );
mRotationItem = new QgsPointRotationItem( mCanvas );
mRotationItem->setSymbol( pointImage );
delete r;
rv2->stopRender( *renderContext );
}

mRotationItem = new QgsPointRotationItem( mCanvas );
mRotationItem->setSymbol( pointImage );
delete r;
delete rv2;
}

void QgsMapToolRotatePointSymbols::setPixmapItemRotation( double rotation )
{
mRotationItem->setSymbolRotation( rotation );
mRotationItem->update();
if ( mRotationItem )
{
mRotationItem->setSymbolRotation( rotation );
mRotationItem->update();
}
}

int QgsMapToolRotatePointSymbols::roundTo15Degrees( double n )
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmaptoolrotatepointsymbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class QgsMapToolRotatePointSymbols: public QgsMapToolEdit
@param vl the point vector layer
@param attList out: the list containing the rotation indices
@return 0 in case of success*/
static int layerRotationAttributes( const QgsVectorLayer* vl, QList<int>& attList );
static int layerRotationAttributes( QgsVectorLayer* vl, QList<int>& attList );
void drawArrow( double azimut ) const;
/**Calculates the azimut between mousePos and mSnappedPoint*/
double calculateAzimut( const QPoint& mousePos );
Expand Down
39 changes: 31 additions & 8 deletions src/app/qgsvectorlayerproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -950,14 +950,25 @@ void QgsVectorLayerProperties::on_pbnLoadStyle_clicked()
{
QSettings myQSettings; // where we keep last used filter in persistent state
QString myLastUsedDir = myQSettings.value( "style/lastStyleDir", "." ).toString();
QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer properties from style file (.qml)" ), myLastUsedDir, tr( "QGIS Layer Style File (*.qml)" ) );
QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer properties from style file" ), myLastUsedDir,
tr( "QGIS Layer Style File" ) + " (*.qml);;" + tr( "SLD File" ) + " (*.sld)" );
if ( myFileName.isNull() )
{
return;
}

QString myMessage;
bool defaultLoadedFlag = false;
QString myMessage = layer->loadNamedStyle( myFileName, defaultLoadedFlag );

if ( myFileName.endsWith( ".sld", Qt::CaseInsensitive ) )
{
// load from SLD
myMessage = layer->loadSldStyle( myFileName, defaultLoadedFlag );
}
else
{
myMessage = layer->loadNamedStyle( myFileName, defaultLoadedFlag );
}
//reset if the default style was loaded ok only
if ( defaultLoadedFlag )
{
Expand All @@ -966,7 +977,7 @@ void QgsVectorLayerProperties::on_pbnLoadStyle_clicked()
else
{
//let the user know what went wrong
QMessageBox::information( this, tr( "Saved Style" ), myMessage );
QMessageBox::information( this, tr( "Load Style" ), myMessage );
}

QFileInfo myFI( myFileName );
Expand All @@ -979,22 +990,34 @@ void QgsVectorLayerProperties::on_pbnSaveStyleAs_clicked()
{
QSettings myQSettings; // where we keep last used filter in persistent state
QString myLastUsedDir = myQSettings.value( "style/lastStyleDir", "." ).toString();
QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer properties as style file (.qml)" ), myLastUsedDir, tr( "QGIS Layer Style File (*.qml)" ) );
QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer properties as style file" ), myLastUsedDir,
tr( "QGIS Layer Style File" ) + " (*.qml);;" + tr( "SLD File" ) + " (*.sld)" );
if ( myOutputFileName.isNull() ) //dialog canceled
{
return;
}

apply(); // make sure the qml to save is uptodate

QString myMessage;
bool defaultLoadedFlag = false;

//ensure the user never omitted the extension from the file name
if ( !myOutputFileName.endsWith( ".qml", Qt::CaseInsensitive ) )
if ( myOutputFileName.endsWith( ".sld", Qt::CaseInsensitive ) )
{
// convert to SLD
myMessage = layer->saveSldStyle( myOutputFileName, defaultLoadedFlag );
}
else
{
myOutputFileName += ".qml";
if ( !myOutputFileName.endsWith( ".qml", Qt::CaseInsensitive ) )
{
myOutputFileName += ".qml";
}

myMessage = layer->saveNamedStyle( myOutputFileName, defaultLoadedFlag );
}

bool defaultLoadedFlag = false;
QString myMessage = layer->saveNamedStyle( myOutputFileName, defaultLoadedFlag );
//reset if the default style was loaded ok only
if ( defaultLoadedFlag )
{
Expand Down
7 changes: 3 additions & 4 deletions src/core/composer/qgscomposeritem.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,21 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
/** Whether this item has a frame or not.
* @returns true if there is a frame around this item, otherwise false.
* @note introduced since 1.8
* @see hasFrame
*/
bool hasFrame() const {return mFrame;}
/** Set whether this item has a frame drawn around it or not.
* @returns void
* @note deprecated since 1.8 don't use!
* @see hasFrame
* @see setFrameEnabled
*/
Q_DECL_DEPRECATED void setFrame( bool drawFrame ) { setFrameEnabled( drawFrame );}
/** Set whether this item has a frame drawn around it or not.
* @param drawFrame draw frame
* @returns nothing
* @note deprecated since 1.8
* @note introduced in 1.8
* @see hasFrame
*/
Q_DECL_DEPRECATED void setFrameEnabled( bool drawFrame ) {mFrame = drawFrame;}
void setFrameEnabled( bool drawFrame ) {mFrame = drawFrame;}

/**Composite operations for item groups do nothing per default*/
virtual void addItem( QgsComposerItem* item ) { Q_UNUSED( item ); }
Expand Down
19 changes: 11 additions & 8 deletions src/core/qgsattributeaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ void QgsAttributeAction::doAction( int index, QgsFeature &feat, int defaultValue
{
QMap<QString, QVariant> substitutionMap;
if ( defaultValueIndex >= 0 )
substitutionMap.insert( "$currfield", QVariant( defaultValueIndex ) );
{
if ( feat.attributeMap().contains( defaultValueIndex ) )
substitutionMap.insert( "$currfield", feat.attributeMap()[ defaultValueIndex ] );
}

doAction( index, feat, &substitutionMap );
}
Expand Down Expand Up @@ -203,26 +206,26 @@ QString QgsAttributeAction::expandAction( QString action, QgsFeature &feat, cons
index = pos + rx.matchedLength();

QString to_replace = rx.cap( 1 ).trimmed();
QgsDebugMsg( "Found expression:" + to_replace );
QgsDebugMsg( "Found expression: " + to_replace );

if ( substitutionMap && substitutionMap->contains( to_replace ) )
{
expr_action += action.mid( start, pos - start ) + substitutionMap->value( to_replace ).toString();
continue;
}

QgsExpression* exp = new QgsExpression( to_replace );
if ( exp->hasParserError() )
QgsExpression exp( to_replace );
if ( exp.hasParserError() )
{
QgsDebugMsg( "Expression parser error:" + exp->parserErrorString() );
QgsDebugMsg( "Expression parser error: " + exp.parserErrorString() );
expr_action += action.mid( start, index - start );
continue;
}

QVariant result = exp->evaluate( &feat, mLayer->pendingFields() );
if ( exp->hasEvalError() )
QVariant result = exp.evaluate( &feat, mLayer->pendingFields() );
if ( exp.hasEvalError() )
{
QgsDebugMsg( "Expression parser eval error:" + exp->evalErrorString() );
QgsDebugMsg( "Expression parser eval error: " + exp.evalErrorString() );
expr_action += action.mid( start, index - start );
continue;
}
Expand Down
17 changes: 17 additions & 0 deletions src/core/qgscoordinatereferencesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ QgsCoordinateReferenceSystem& QgsCoordinateReferenceSystem::operator=( const Qgs
mProjectionAcronym = srs.mProjectionAcronym;
mEllipsoidAcronym = srs.mEllipsoidAcronym;
mGeoFlag = srs.mGeoFlag;
mAxisInverted = srs.mAxisInverted;
mMapUnits = srs.mMapUnits;
mSRID = srs.mSRID;
mAuthId = srs.mAuthId;
Expand Down Expand Up @@ -264,6 +265,7 @@ bool QgsCoordinateReferenceSystem::loadFromDb( QString db, QString expression, Q
mSRID = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 5 ) ).toLong();
mAuthId = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 6 ) );
mGeoFlag = QString::fromUtf8(( char * )sqlite3_column_text( myPreparedStatement, 7 ) ).toInt() != 0;
mAxisInverted = -1;

if ( mSrsId >= USER_CRS_START_ID && mAuthId.isEmpty() )
{
Expand Down Expand Up @@ -291,6 +293,21 @@ bool QgsCoordinateReferenceSystem::loadFromDb( QString db, QString expression, Q
return mIsValidFlag;
}

bool QgsCoordinateReferenceSystem::axisInverted() const
{
if ( mAxisInverted == -1 )
{
OGRAxisOrientation orientation;
const char *axis0 = OSRGetAxis( mCRS, mGeoFlag ? "GEOGCS" : "PROJCS", 0, &orientation );
mAxisInverted = mGeoFlag
? (orientation == OAO_East || orientation == OAO_West || orientation == OAO_Other )
: (orientation == OAO_North || orientation == OAO_South );
QgsDebugMsg( QString( "srid:%1 axis0:%2 orientation:%3 inverted:%4" ).arg( mSRID ).arg( axis0 ).arg( OSRAxisEnumToName( orientation ) ).arg( mAxisInverted ) );
}

return mAxisInverted != 0;
}

bool QgsCoordinateReferenceSystem::createFromWkt( QString theWkt )
{
mIsValidFlag = false;
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgscoordinatereferencesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
*/
bool geographicFlag() const;

/*! return if axis is inverted (eg. for WMS 1.3)
* @return bool Whether this is crs axis is inverted
* @note added in 1.9.90
*/
bool axisInverted() const;

/*! Get the units that the projection is in
* @return QGis::UnitType that gives the units for the coordinate system
*/
Expand Down Expand Up @@ -434,6 +440,9 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
QString mValidationHint;
mutable QString mWkt;

//!Whether this is a coordinate system has inverted axis
mutable int mAxisInverted;

static CUSTOM_CRS_VALIDATION mCustomSrsValidation;
};

Expand Down
585 changes: 585 additions & 0 deletions src/core/qgsexpression.cpp

Large diffs are not rendered by default.

39 changes: 39 additions & 0 deletions src/core/qgsexpression.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ class CORE_EXPORT QgsExpression
static const char* BinaryOperatorText[];
static const char* UnaryOperatorText[];

static const char* BinaryOgcOperatorText[];
static const char* UnaryOgcOperatorText[];

typedef QVariant( *FcnEval )( const QVariantList& values, QgsFeature* f, QgsExpression* parent );

Expand Down Expand Up @@ -226,6 +228,9 @@ class CORE_EXPORT QgsExpression

virtual QString dump() const = 0;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const { Q_UNUSED( doc ); Q_UNUSED( element ); }
static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );

virtual QStringList referencedColumns() const = 0;
virtual bool needsGeometry() const = 0;

Expand All @@ -243,6 +248,8 @@ class CORE_EXPORT QgsExpression
QList<Node*> list() { return mList; }

virtual QString dump() const;
virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;

protected:
QList<Node*> mList;
};
Expand All @@ -259,6 +266,10 @@ class CORE_EXPORT QgsExpression
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );

virtual QStringList referencedColumns() const { return mOperand->referencedColumns(); }
virtual bool needsGeometry() const { return mOperand->needsGeometry(); }
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand All @@ -281,6 +292,10 @@ class CORE_EXPORT QgsExpression
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );

virtual QStringList referencedColumns() const { return mOpLeft->referencedColumns() + mOpRight->referencedColumns(); }
virtual bool needsGeometry() const { return mOpLeft->needsGeometry() || mOpRight->needsGeometry(); }
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand Down Expand Up @@ -308,6 +323,9 @@ class CORE_EXPORT QgsExpression
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;

virtual QStringList referencedColumns() const { QStringList lst( mNode->referencedColumns() ); foreach( Node* n, mList->list() ) lst.append( n->referencedColumns() ); return lst; }
virtual bool needsGeometry() const { bool needs = false; foreach( Node* n, mList->list() ) needs |= n->needsGeometry(); return needs; }
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand All @@ -331,6 +349,10 @@ class CORE_EXPORT QgsExpression
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );

virtual QStringList referencedColumns() const { QStringList lst; if ( !mArgs ) return lst; foreach( Node* n, mArgs->list() ) lst.append( n->referencedColumns() ); return lst; }
virtual bool needsGeometry() const { bool needs = BuiltinFunctions()[mFnIndex].mUsesGeometry; if ( mArgs ) { foreach( Node* n, mArgs->list() ) needs |= n->needsGeometry(); } return needs; }
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand All @@ -351,6 +373,10 @@ class CORE_EXPORT QgsExpression
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );

virtual QStringList referencedColumns() const { return QStringList(); }
virtual bool needsGeometry() const { return false; }
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand All @@ -369,6 +395,10 @@ class CORE_EXPORT QgsExpression
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
static QgsExpression::Node* createFromOgcFilter( QDomElement &element, QString &errorMessage );

virtual QStringList referencedColumns() const { return QStringList( mName ); }
virtual bool needsGeometry() const { return false; }
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand Down Expand Up @@ -399,6 +429,9 @@ class CORE_EXPORT QgsExpression
virtual QVariant eval( QgsExpression* parent, QgsFeature* f );
virtual bool prepare( QgsExpression* parent, const QgsFieldMap& fields );
virtual QString dump() const;

virtual void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;

virtual QStringList referencedColumns() const;
virtual bool needsGeometry() const;
virtual void accept( Visitor& v ) { v.visit( this ); }
Expand Down Expand Up @@ -428,7 +461,13 @@ class CORE_EXPORT QgsExpression
/** entry function for the visitor pattern */
void acceptVisitor( Visitor& v );

// convert from/to OGC Filter
void toOgcFilter( QDomDocument &doc, QDomElement &element ) const;
static QgsExpression* createFromOgcFilter( QDomElement &element );

protected:
// internally used to create an empty expression
QgsExpression() : mRootNode( NULL ), mRowNumber( 0 ), mCalc( NULL ) {}

QString mExpression;
Node* mRootNode;
Expand Down
8 changes: 5 additions & 3 deletions src/core/qgsexpressionlexer.ll
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "qgsexpression.h"
#include "qgsexpressionparser.hpp"
#include <QRegExp>

#include <QLocale>

// if not defined, searches for isatty()
// which doesn't in MSVC compiler
Expand Down Expand Up @@ -85,6 +85,8 @@ static QString stripColumnRef(QString text)
return text;
}

// C locale for correct parsing of numbers even if the system locale is different
static QLocale cLocale("C");

%}

Expand Down Expand Up @@ -152,8 +154,8 @@ string "'"{str_char}*"'"
"," { return COMMA; }
{num_float} { exp_lval.numberFloat = atof(yytext); return NUMBER_FLOAT; }
{num_int} { exp_lval.numberInt = atoi(yytext); return NUMBER_INT; }
{num_float} { exp_lval.numberFloat = cLocale.toDouble( QString::fromAscii(yytext) ); return NUMBER_FLOAT; }
{num_int} { exp_lval.numberInt = cLocale.toInt( QString::fromAscii(yytext), 0, 10); return NUMBER_INT; }
{string} { TEXT_FILTER(stripText); return STRING; }
Expand Down
139 changes: 139 additions & 0 deletions src/core/qgsmaplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,146 @@ QString QgsMapLayer::saveNamedStyle( const QString theURI, bool & theResultFlag
return myErrorMessage;
}

QString QgsMapLayer::saveSldStyle( const QString theURI, bool & theResultFlag )
{
QDomDocument myDocument = QDomDocument();

QDomNode header = myDocument.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
myDocument.appendChild( header );

// Create the root element
QDomElement root = myDocument.createElementNS( "http://www.opengis.net/sld", "StyledLayerDescriptor" );
root.setAttribute( "version", "1.1.0" );
root.setAttribute( "xsi:schemaLocation", "http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd" );
root.setAttribute( "xmlns:ogc", "http://www.opengis.net/ogc" );
root.setAttribute( "xmlns:se", "http://www.opengis.net/se" );
root.setAttribute( "xmlns:xlink", "http://www.w3.org/1999/xlink" );
root.setAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" );
myDocument.appendChild( root );

// Create the NamedLayer element
QDomElement namedLayerNode = myDocument.createElement( "NamedLayer" );
root.appendChild( namedLayerNode );

QString errorMsg;
QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( this );
if ( !vlayer )
{
theResultFlag = false;
return tr( "Could not save symbology because:\n%1" ).arg( "Non-vector layers not supported yet" );
}

if ( !vlayer->writeSld( namedLayerNode, myDocument, errorMsg ) )
{
theResultFlag = false;
return tr( "Could not save symbology because:\n%1" ).arg( errorMsg );
}

// check if the uri is a file or ends with .sld,
// which indicates that it should become one
QString filename;
if ( vlayer->providerType() == "ogr" )
{
QStringList theURIParts = theURI.split( "|" );
filename = theURIParts[0];
}
else if ( vlayer->providerType() == "delimitedtext" )
{
filename = QUrl::fromEncoded( theURI.toAscii() ).toLocalFile();
}
else
{
filename = theURI;
}

QFileInfo myFileInfo( filename );
if ( myFileInfo.exists() || filename.endsWith( ".sld", Qt::CaseInsensitive ) )
{
QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
if ( !myDirInfo.isWritable() )
{
return tr( "The directory containing your dataset needs to be writable!" );
}

// now construct the file name for our .sld style file
QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".sld";

QFile myFile( myFileName );
if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
{
QTextStream myFileStream( &myFile );
// save as utf-8 with 2 spaces for indents
myDocument.save( myFileStream, 2 );
myFile.close();
theResultFlag = true;
return tr( "Created default style file as %1" ).arg( myFileName );
}
}

theResultFlag = false;
return tr( "ERROR: Failed to created SLD style file as %1. Check file permissions and retry." ).arg( filename );
}

QString QgsMapLayer::loadSldStyle( const QString theURI, bool &theResultFlag )
{
QgsDebugMsg( "Entered." );

theResultFlag = false;

QDomDocument myDocument;

// location of problem associated with errorMsg
int line, column;
QString myErrorMessage;

QFile myFile( theURI );
if ( myFile.open( QFile::ReadOnly ) )
{
// read file
theResultFlag = myDocument.setContent( &myFile, true, &myErrorMessage, &line, &column );
if ( !theResultFlag )
myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
myFile.close();
}
else
{
myErrorMessage = tr( "Unable to open file %1" ).arg( theURI );
}

if ( !theResultFlag )
{
return myErrorMessage;
}

// check for root SLD element
QDomElement myRoot = myDocument.firstChildElement( "StyledLayerDescriptor" );
if ( myRoot.isNull() )
{
myErrorMessage = QString( "Error: StyledLayerDescriptor element not found in %1" ).arg( theURI );
theResultFlag = false;
return myErrorMessage;
}

// now get the style node out and pass it over to the layer
// to deserialise...
QDomElement namedLayerElem = myRoot.firstChildElement( "NamedLayer" );
if ( namedLayerElem.isNull() )
{
myErrorMessage = QString( "Info: NamedLayer element not found." );
theResultFlag = false;
return myErrorMessage;
}

QString errorMsg;
theResultFlag = readSld( namedLayerElem, errorMsg );
if ( !theResultFlag )
{
myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( theURI ).arg( errorMsg );
return myErrorMessage;
}

return "";
}


QUndoStack* QgsMapLayer::undoStack()
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsmaplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
*/
virtual QString saveNamedStyle( const QString theURI, bool & theResultFlag );

virtual QString saveSldStyle( const QString theURI, bool & theResultFlag );
virtual QString loadSldStyle( const QString theURI, bool &theResultFlag );

virtual bool readSld( const QDomNode& node, QString& errorMessage )
{ Q_UNUSED( node ); errorMessage = QString( "Layer type %1 not supported" ).arg( type() ); return false; }


/** Read the symbology for the current layer from the Dom node supplied.
* @param node node that will contain the symbology definition for this layer.
* @param errorMessage reference to string that will be updated with any error messages
Expand Down
56 changes: 53 additions & 3 deletions src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab
bool drawMarker = ( mEditable && ( !vertexMarkerOnlyForSelection || sel ) );

// render feature
mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker );
bool rendered = mRendererV2->renderFeature( fet, rendererContext, -1, sel, drawMarker );

if ( mEditable )
{
Expand All @@ -753,7 +753,7 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab
}

// labeling - register feature
if ( mRendererV2->symbolForFeature( fet ) != NULL && rendererContext.labelingEngine() )
if ( rendered && rendererContext.labelingEngine() )
{
if ( labeling )
{
Expand All @@ -776,6 +776,8 @@ void QgsVectorLayer::drawRendererV2( QgsRenderContext& rendererContext, bool lab
#endif //Q_WS_MAC
}

stopRendererV2( rendererContext, NULL );

#ifndef Q_WS_MAC
QgsDebugMsg( QString( "Total features processed %1" ).arg( featureCount ) );
#endif
Expand Down Expand Up @@ -977,7 +979,8 @@ bool QgsVectorLayer::draw( QgsRenderContext& rendererContext )

select( attributes, rendererContext.extent() );

if ( mRendererV2->usingSymbolLevels() )
if ( ( mRendererV2->capabilities() & QgsFeatureRendererV2::SymbolLevels )
&& mRendererV2->usingSymbolLevels() )
drawRendererV2Levels( rendererContext, labeling );
else
drawRendererV2( rendererContext, labeling );
Expand Down Expand Up @@ -3388,6 +3391,53 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
return true;
}

bool QgsVectorLayer::readSld( const QDomNode& node, QString& errorMessage )
{
// get the Name element
QDomElement nameElem = node.firstChildElement( "Name" );
if ( nameElem.isNull() )
{
errorMessage = "Warning: Name element not found within NamedLayer while it's required.";
}

if ( hasGeometryType() )
{
setUsingRendererV2( true );

QgsFeatureRendererV2* r = QgsFeatureRendererV2::loadSld( node, geometryType(), errorMessage );
if ( !r )
return false;

setRendererV2( r );
}
return true;
}


bool QgsVectorLayer::writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const
{
Q_UNUSED( errorMessage );

// store the Name element
QDomElement nameNode = doc.createElement( "se:Name" );
nameNode.appendChild( doc.createTextNode( name() ) );
node.appendChild( nameNode );

if ( hasGeometryType() )
{
if ( mUsingRendererV2 )
{
node.appendChild( mRendererV2->writeSld( doc, *this ) );
}
else
{
node.appendChild( doc.createComment( "Old Renderer not supported yet" ) );
return false;
}
}
return true;
}


bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry* geom )
{
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectorlayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
*/
bool writeSymbology( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;

bool writeSld( QDomNode& node, QDomDocument& doc, QString& errorMessage ) const;
bool readSld( const QDomNode& node, QString& errorMessage );

/**
* Number of features in the layer. This is necessary if features are
Expand Down
47 changes: 47 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,36 @@ QString QgsRendererCategoryV2::dump()
return QString( "%1::%2::%3\n" ).arg( mValue.toString() ).arg( mLabel ).arg( mSymbol->dump() );
}

void QgsRendererCategoryV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
return;

QString attrName = props[ "attribute" ];

QDomElement ruleElem = doc.createElement( "se:Rule" );
element.appendChild( ruleElem );

QDomElement nameElem = doc.createElement( "se:Name" );
nameElem.appendChild( doc.createTextNode( mLabel ) );
ruleElem.appendChild( nameElem );

QDomElement descrElem = doc.createElement( "se:Description" );
QString descrStr = QString( "%1 is '%2'" ).arg( attrName ).arg( mValue.toString() );
descrElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
ruleElem.appendChild( descrElem );

// create the ogc:Filter for the range
QDomElement filterElem = doc.createElement( "ogc:Filter" );
QString filterFunc = QString( "%1 = '%2'" )
.arg( attrName.replace( "\"", "\"\"" ) )
.arg( mValue.toString().replace( "'", "''" ) );
QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, filterFunc );
ruleElem.appendChild( filterElem );

mSymbol->toSld( doc, ruleElem, props );
}

///////////////////

QgsCategorizedSymbolRendererV2::QgsCategorizedSymbolRendererV2( QString attrName, QgsCategoryList categories )
Expand Down Expand Up @@ -331,6 +361,23 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone()
return r;
}

void QgsCategorizedSymbolRendererV2::toSld( QDomDocument &doc, QDomElement &element ) const
{
QgsStringMap props;
props[ "attribute" ] = mAttrName;
if ( !mRotationField.isEmpty() )
props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
if ( !mSizeScaleField.isEmpty() )
props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );

// create a Rule for each range
for ( QgsCategoryList::const_iterator it = mCategories.constBegin(); it != mCategories.constEnd(); it++ )
{
QgsStringMap catProps( props );
it->toSld( doc, element, catProps );
}
}

QgsSymbolV2List QgsCategorizedSymbolRendererV2::symbols()
{
QgsSymbolV2List lst;
Expand Down
9 changes: 9 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef QGSCATEGORIZEDSYMBOLRENDERERV2_H
#define QGSCATEGORIZEDSYMBOLRENDERERV2_H

#include "qgssymbolv2.h"
#include "qgsrendererv2.h"

#include <QHash>
Expand Down Expand Up @@ -32,6 +33,8 @@ class CORE_EXPORT QgsRendererCategoryV2
// debugging
QString dump();

void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;

protected:
QVariant mValue;
QgsSymbolV2* mSymbol;
Expand Down Expand Up @@ -60,6 +63,12 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2

virtual QgsFeatureRendererV2* clone();

virtual void toSld( QDomDocument& doc, QDomElement &element ) const;

//! returns bitwise OR-ed capabilities of the renderer
//! \note added in 2.0
virtual int capabilities() { return SymbolLevels | RotationField; }

virtual QgsSymbolV2List symbols();

const QgsCategoryList& categories() { return mCategories; }
Expand Down
113 changes: 113 additions & 0 deletions src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@
#include "qgsfeature.h"
#include "qgsrendercontext.h"
#include "qgsvectorlayer.h"
#include "qgslogger.h"

#include <QPainter>
#include <QSet>
#include <QDomDocument>
#include <QDomElement>

QgsEllipseSymbolLayerV2::QgsEllipseSymbolLayerV2(): mSymbolName( "circle" ), mSymbolWidth( 4 ), mSymbolHeight( 3 ),
mFillColor( Qt::black ), mOutlineColor( Qt::white ), mOutlineWidth( 0 )
Expand Down Expand Up @@ -187,6 +191,115 @@ QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::clone() const
return QgsEllipseSymbolLayerV2::create( properties() );
}

void QgsEllipseSymbolLayerV2::toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
QDomElement symbolizerElem = doc.createElement( "se:PointSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

// <Geometry>
QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

writeSldMarker( doc, symbolizerElem, props );
}

void QgsEllipseSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
// <Graphic>
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mSymbolName, mFillColor, mOutlineColor, mOutlineWidth, mSymbolWidth );

// store w/h factor in a <VendorOption>
double widthHeightFactor = mSymbolWidth / mSymbolHeight;
QDomElement factorElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "widthHeightFactor", QString::number( widthHeightFactor ) );
graphicElem.appendChild( factorElem );

// <Rotation>
QString angleFunc = props.value( "angle", "" );
if ( angleFunc.isEmpty() ) // symbol has no angle set
{
if ( !mRotationField.isEmpty() )
angleFunc = mRotationField;
else if ( !doubleNear( mAngle, 0.0 ) )
angleFunc = QString::number( mAngle );
}
else if ( !mRotationField.isEmpty() )
{
// the symbol has an angle and the symbol layer have a rotation
// property set
angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mRotationField );
}
else if ( !doubleNear( mAngle, 0.0 ) )
{
// both the symbol and the symbol layer have angle value set
bool ok;
double angle = angleFunc.toDouble( &ok );
if ( !ok )
{
// its a string (probably a property name or a function)
angleFunc = QString( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
}
else if ( !doubleNear( angle + mAngle, 0.0 ) )
{
// it's a double value
angleFunc = QString::number( angle + mAngle );
}
}
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );
}

QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QDomElement graphicElem = element.firstChildElement( "Graphic" );
if( graphicElem.isNull() )
return NULL;

QString name = "circle";
QColor color, borderColor;
double borderWidth, size;
double widthHeightFactor = 1.0;

QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( graphicElem );
for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
{
if ( it.key() == "widthHeightFactor" )
{
bool ok;
double v = it.value().toDouble( &ok );
if ( ok && !doubleNear( v, 0.0 ) && v > 0 )
widthHeightFactor = v;
}
}

if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderWidth, size ) )
return NULL;

double angle = 0.0;
QString angleFunc;
if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
{
bool ok;
double d = angleFunc.toDouble( &ok );
if ( ok )
angle = d;
}

QgsEllipseSymbolLayerV2 *m = new QgsEllipseSymbolLayerV2();
m->setSymbolName( name );
m->setColor( color );
m->setOutlineColor( borderColor );
m->setOutlineWidth( borderWidth );
m->setSymbolWidth( size );
m->setSymbolHeight( size / widthHeightFactor );
m->setAngle( angle );
return m;
}

QgsStringMap QgsEllipseSymbolLayerV2::properties() const
{
QgsStringMap map;
Expand Down
4 changes: 4 additions & 0 deletions src/core/symbology-ng/qgsellipsesymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class CORE_EXPORT QgsEllipseSymbolLayerV2: public QgsMarkerSymbolLayerV2
~QgsEllipseSymbolLayerV2();

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

void renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context );
QString layerType() const;
Expand All @@ -20,6 +21,9 @@ class CORE_EXPORT QgsEllipseSymbolLayerV2: public QgsMarkerSymbolLayerV2
QgsSymbolLayerV2* clone() const;
QgsStringMap properties() const;

void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;
void writeSldMarker( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;

void setSymbolName( const QString& name ) { mSymbolName = name; }
QString symbolName() const { return mSymbolName; }

Expand Down
291 changes: 291 additions & 0 deletions src/core/symbology-ng/qgsfillsymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
#include "qgsrendercontext.h"
#include "qgsproject.h"
#include "qgssvgcache.h"
#include "qgslogger.h"

#include <QPainter>
#include <QFile>
#include <QSvgRenderer>
#include <QDomDocument>
#include <QDomElement>

QgsSimpleFillSymbolLayerV2::QgsSimpleFillSymbolLayerV2( QColor color, Qt::BrushStyle style, QColor borderColor, Qt::PenStyle borderStyle, double borderWidth )
: mBrushStyle( style ), mBorderColor( borderColor ), mBorderStyle( borderStyle ), mBorderWidth( borderWidth )
Expand Down Expand Up @@ -117,6 +120,63 @@ QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::clone() const
return sl;
}

void QgsSimpleFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
if ( mBrushStyle == Qt::NoBrush && mBorderStyle == Qt::NoPen )
return;

QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

// <Geometry>
QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

if ( mBrushStyle != Qt::NoBrush )
{
// <Fill>
QDomElement fillElem = doc.createElement( "se:Fill" );
symbolizerElem.appendChild( fillElem );
QgsSymbolLayerV2Utils::fillToSld( doc, fillElem, mBrushStyle, mColor );
}

if ( mBorderStyle != Qt::NoPen )
{
// <Stroke>
QDomElement strokeElem = doc.createElement( "se:Stroke" );
symbolizerElem.appendChild( strokeElem );
QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, mBorderStyle, mBorderColor, mBorderWidth );
}

// <se:Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, symbolizerElem, mOffset );
}

QgsSymbolLayerV2* QgsSimpleFillSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QColor color, borderColor;
Qt::BrushStyle fillStyle;
Qt::PenStyle borderStyle;
double borderWidth;

QDomElement fillElem = element.firstChildElement( "Fill" );
QgsSymbolLayerV2Utils::fillFromSld( fillElem, fillStyle, color );

QDomElement strokeElem = element.firstChildElement( "Stroke" );
QgsSymbolLayerV2Utils::lineFromSld( strokeElem, borderStyle, borderColor, borderWidth );

QPointF offset;
QgsSymbolLayerV2Utils::displacementFromSldElement( element, offset );

QgsSimpleFillSymbolLayerV2* sl = new QgsSimpleFillSymbolLayerV2( color, fillStyle, borderColor, borderStyle, borderWidth );
sl->setOffset( offset );
return sl;
}


//QgsImageFillSymbolLayer

QgsImageFillSymbolLayer::QgsImageFillSymbolLayer(): mOutlineWidth( 0.0 ), mOutline( 0 )
Expand Down Expand Up @@ -380,6 +440,123 @@ QgsSymbolLayerV2* QgsSVGFillSymbolLayer::clone() const
return clonedLayer;
}

void QgsSVGFillSymbolLayer::toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

QDomElement fillElem = doc.createElement( "se:Fill" );
symbolizerElem.appendChild( fillElem );

QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
fillElem.appendChild( graphicFillElem );

QDomElement graphicElem = doc.createElement( "se:Graphic" );
graphicFillElem.appendChild( graphicElem );

if ( !mSvgFilePath.isEmpty() )
{
QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mSvgFilePath, "image/svg+xml", mSvgFillColor, mPatternWidth );
}
else
{
// TODO: create svg from data
// <se:InlineContent>
symbolizerElem.appendChild( doc.createComment( "SVG from data not implemented yet" ) );
}

if ( mSvgOutlineColor.isValid() || mSvgOutlineWidth >= 0 )
{
QgsSymbolLayerV2Utils::lineToSld( doc, graphicElem, Qt::SolidLine, mSvgOutlineColor, mSvgOutlineWidth );
}

// <Rotation>
QString angleFunc;
bool ok;
double angle = props.value( "angle", "0" ).toDouble( &ok );
if ( !ok )
{
angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
}
else if ( angle + mAngle != 0 )
{
angleFunc = QString::number( angle + mAngle );
}
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

if ( mOutline )
{
// the outline sub symbol should be stored within the Stroke element,
// but it will be stored in a separated LineSymbolizer because it could
// have more than one layer
mOutline->toSld( doc, element, props );
}
}

QgsSymbolLayerV2* QgsSVGFillSymbolLayer::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QString path, mimeType;
QColor fillColor, borderColor;
Qt::PenStyle penStyle;
double size, borderWidth;

QDomElement fillElem = element.firstChildElement( "Fill" );
if( fillElem.isNull() )
return NULL;

QDomElement graphicFillElem = fillElem.firstChildElement( "GraphicFill" );
if( graphicFillElem.isNull() )
return NULL;

QDomElement graphicElem = graphicFillElem.firstChildElement( "Graphic" );
if( graphicElem.isNull() )
return NULL;

if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
return NULL;

if ( mimeType != "image/svg+xml" )
return NULL;

QgsSymbolLayerV2Utils::lineFromSld( graphicElem, penStyle, borderColor, borderWidth );

double angle = 0.0;
QString angleFunc;
if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
{
bool ok;
double d = angleFunc.toDouble( &ok );
if ( ok )
angle = d;
}

QgsSVGFillSymbolLayer* sl = new QgsSVGFillSymbolLayer( path, size, angle );
sl->setSvgFillColor( fillColor );
sl->setSvgOutlineColor( borderColor );
sl->setSvgOutlineWidth( borderWidth );

// try to get the outline
QDomElement strokeElem = element.firstChildElement( "Stroke" );
if ( !strokeElem.isNull() )
{
QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createLineLayerFromSld( strokeElem );
if ( l )
{
QgsSymbolLayerV2List layers;
layers.append( l );
sl->setSubSymbol( new QgsLineSymbolV2( layers ) );
}
}

return sl;
}

void QgsSVGFillSymbolLayer::storeViewBox()
{
if ( !mSvgData.isEmpty() )
Expand Down Expand Up @@ -630,6 +807,52 @@ QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::clone() const
return clonedLayer;
}

void QgsLinePatternFillSymbolLayer::toSld(QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

// <Geometry>
QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

QDomElement fillElem = doc.createElement( "se:Fill" );
symbolizerElem.appendChild( fillElem );

QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
fillElem.appendChild( graphicFillElem );

QDomElement graphicElem = doc.createElement( "se:Graphic" );
graphicFillElem.appendChild( graphicElem );

QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "horline", QColor(), mColor, mLineWidth, mDistance );

// <Rotation>
QString angleFunc;
bool ok;
double angle = props.value( "angle", "0" ).toDouble( &ok );
if ( !ok )
{
angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mLineAngle );
}
else if ( angle + mLineAngle != 0 )
{
angleFunc = QString::number( angle + mLineAngle );
}
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <se:Displacement>
QPointF lineOffset( qSin( mLineAngle ) * mOffset, qCos( mLineAngle ) * mOffset );
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, lineOffset );
}

QgsSymbolLayerV2* QgsLinePatternFillSymbolLayer::createFromSld( QDomElement &element )
{
Q_UNUSED( element );
return NULL;
}

////////////////////////

QgsPointPatternFillSymbolLayer::QgsPointPatternFillSymbolLayer(): QgsImageFillSymbolLayer(), mMarkerSymbol( 0 ), mDistanceX( 15 ),
Expand Down Expand Up @@ -765,6 +988,49 @@ QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::clone() const
return clonedLayer;
}

void QgsPointPatternFillSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
for ( int i = 0; i < mMarkerSymbol->symbolLayerCount(); i++ )
{
QDomElement symbolizerElem = doc.createElement( "se:PolygonSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

// <Geometry>
QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

QDomElement fillElem = doc.createElement( "se:Fill" );
symbolizerElem.appendChild( fillElem );

QDomElement graphicFillElem = doc.createElement( "se:GraphicFill" );
fillElem.appendChild( graphicFillElem );

// store distanceX, distanceY, displacementX, displacementY in a <VendorOption>
QString dist = QgsSymbolLayerV2Utils::encodePoint( QPointF( mDistanceX, mDistanceY ) );
QDomElement distanceElem = QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "distance", dist );
symbolizerElem.appendChild( distanceElem );

QgsSymbolLayerV2 *layer = mMarkerSymbol->symbolLayer( i );
QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
if ( !markerLayer )
{
QString errorMsg = QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->layerType() );
graphicFillElem.appendChild( doc.createComment( errorMsg ) );
}
else
{
markerLayer->writeSldMarker( doc, graphicFillElem, props );
}
}
}

QgsSymbolLayerV2* QgsPointPatternFillSymbolLayer::createFromSld( QDomElement &element )
{
Q_UNUSED( element );
return NULL;
}

bool QgsPointPatternFillSymbolLayer::setSubSymbol( QgsSymbolV2* symbol )
{
if ( !symbol )
Expand Down Expand Up @@ -859,6 +1125,31 @@ QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
return x;
}

void QgsCentroidFillSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
// SLD 1.0 specs says: "if a line, polygon, or raster geometry is
// used with PointSymbolizer, then the semantic is to use the centroid
// of the geometry, or any similar representative point.
mMarker->toSld( doc, element, props );
}

QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createMarkerLayerFromSld( element );
if ( !l )
return NULL;

QgsSymbolLayerV2List layers;
layers.append( l );
QgsMarkerSymbolV2 *marker = new QgsMarkerSymbolV2( layers );

QgsCentroidFillSymbolLayerV2* x = new QgsCentroidFillSymbolLayerV2();
x->setSubSymbol( marker );
return x;
}


QgsSymbolV2* QgsCentroidFillSymbolLayerV2::subSymbol()
{
Expand Down
16 changes: 16 additions & 0 deletions src/core/symbology-ng/qgsfillsymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class CORE_EXPORT QgsSimpleFillSymbolLayerV2 : public QgsFillSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -40,6 +41,8 @@ class CORE_EXPORT QgsSimpleFillSymbolLayerV2 : public QgsFillSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

Qt::BrushStyle brushStyle() const { return mBrushStyle; }
void setBrushStyle( Qt::BrushStyle style ) { mBrushStyle = style; }

Expand Down Expand Up @@ -97,6 +100,7 @@ class CORE_EXPORT QgsSVGFillSymbolLayer: public QgsImageFillSymbolLayer
~QgsSVGFillSymbolLayer();

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -109,6 +113,8 @@ class CORE_EXPORT QgsSVGFillSymbolLayer: public QgsImageFillSymbolLayer

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

//getters and setters
void setSvgFilePath( const QString& svgPath );
QString svgFilePath() const { return mSvgFilePath; }
Expand Down Expand Up @@ -151,6 +157,7 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer
~QgsLinePatternFillSymbolLayer();

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

QString layerType() const;

Expand All @@ -162,6 +169,8 @@ class CORE_EXPORT QgsLinePatternFillSymbolLayer: public QgsImageFillSymbolLayer

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

//getters and setters
void setLineAngle( double a ) { mLineAngle = a; }
double lineAngle() const { return mLineAngle; }
Expand Down Expand Up @@ -193,6 +202,8 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer
~QgsPointPatternFillSymbolLayer();

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

QString layerType() const;

void startRender( QgsSymbolV2RenderContext& context );
Expand All @@ -203,6 +214,8 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

//getters and setters
double distanceX() const { return mDistanceX; }
void setDistanceX( double d ) { mDistanceX = d; }
Expand Down Expand Up @@ -236,6 +249,7 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -251,6 +265,8 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

void setColor( const QColor& color );

QgsSymbolV2* subSymbol();
Expand Down
46 changes: 46 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,35 @@ QString QgsRendererRangeV2::dump()
return QString( "%1 - %2::%3::%4\n" ).arg( mLowerValue ).arg( mUpperValue ).arg( mLabel ).arg( mSymbol->dump() );
}

void QgsRendererRangeV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
if ( !mSymbol || props.value( "attribute", "" ).isEmpty() )
return;

QString attrName = props[ "attribute" ];

QDomElement ruleElem = doc.createElement( "se:Rule" );
element.appendChild( ruleElem );

QDomElement nameElem = doc.createElement( "se:Name" );
nameElem.appendChild( doc.createTextNode( mLabel ) );
ruleElem.appendChild( nameElem );

QDomElement descrElem = doc.createElement( "se:Description" );
QString descrStr = QString( "range: %1 - %2" ).arg( mLowerValue ).arg( mUpperValue );
descrElem.appendChild( doc.createTextNode( !mLabel.isEmpty() ? mLabel : descrStr ) );
ruleElem.appendChild( descrElem );

// create the ogc:Filter for the range
QDomElement filterElem = doc.createElement( "ogc:Filter" );
QString filterFunc = QString( "%1 > %2 AND %1 <= %3" )
.arg( attrName.replace( "\"", "\"\"" ) )
.arg( mLowerValue ).arg( mUpperValue );
QgsSymbolLayerV2Utils::createFunctionElement( doc, filterElem, filterFunc );

mSymbol->toSld( doc, ruleElem, props );
}

///////////

QgsGraduatedSymbolRendererV2::QgsGraduatedSymbolRendererV2( QString attrName, QgsRangeList ranges )
Expand Down Expand Up @@ -302,6 +331,23 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::clone()
return r;
}

void QgsGraduatedSymbolRendererV2::toSld( QDomDocument& doc, QDomElement &element ) const
{
QgsStringMap props;
props[ "attribute" ] = mAttrName;
if ( !mRotationField.isEmpty() )
props[ "angle" ] = QString( mRotationField ).append( "\"" ).prepend( "\"" );
if ( !mSizeScaleField.isEmpty() )
props[ "scale" ] = QString( mSizeScaleField ).append( "\"" ).prepend( "\"" );

// create a Rule for each range
for ( QgsRangeList::const_iterator it = mRanges.constBegin(); it != mRanges.constEnd(); it++ )
{
QgsStringMap catProps( props );
it->toSld( doc, element, catProps );
}
}

QgsSymbolV2List QgsGraduatedSymbolRendererV2::symbols()
{
QgsSymbolV2List lst;
Expand Down
9 changes: 9 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef QGSGRADUATEDSYMBOLRENDERERV2_H
#define QGSGRADUATEDSYMBOLRENDERERV2_H

#include "qgssymbolv2.h"
#include "qgsrendererv2.h"

class CORE_EXPORT QgsRendererRangeV2
Expand All @@ -25,6 +26,8 @@ class CORE_EXPORT QgsRendererRangeV2
// debugging
QString dump();

void toSld( QDomDocument& doc, QDomElement &element, QgsStringMap props ) const;

protected:
double mLowerValue, mUpperValue;
QgsSymbolV2* mSymbol;
Expand Down Expand Up @@ -55,6 +58,12 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2

virtual QgsFeatureRendererV2* clone();

virtual void toSld( QDomDocument& doc, QDomElement &element ) const;

//! returns bitwise OR-ed capabilities of the renderer
//! \note added in 2.0
virtual int capabilities() { return SymbolLevels | RotationField; }

virtual QgsSymbolV2List symbols();

QString classAttribute() const { return mAttrName; }
Expand Down
253 changes: 253 additions & 0 deletions src/core/symbology-ng/qgslinesymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
#include "qgssymbollayerv2utils.h"

#include "qgsrendercontext.h"
#include "qgslogger.h"

#include <QPainter>
#include <QDomDocument>
#include <QDomElement>

#include <cmath>

Expand Down Expand Up @@ -148,6 +151,77 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::clone() const
return l;
}

void QgsSimpleLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
if ( mPenStyle == Qt::NoPen )
return;

QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

// <Geometry>
QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

// <Stroke>
QDomElement strokeElem = doc.createElement( "se:Stroke" );
symbolizerElem.appendChild( strokeElem );

Qt::PenStyle penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
QgsSymbolLayerV2Utils::lineToSld( doc, strokeElem, penStyle, mColor, mWidth,
&mPenJoinStyle, &mPenCapStyle, &mCustomDashVector );

// <se:PerpendicularOffset>
if ( mOffset != 0 )
{
QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
symbolizerElem.appendChild( perpOffsetElem );
}
}

QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QDomElement strokeElem = element.firstChildElement( "Stroke" );
if ( strokeElem.isNull() )
return NULL;

Qt::PenStyle penStyle;
QColor color;
double width;
Qt::PenJoinStyle penJoinStyle;
Qt::PenCapStyle penCapStyle;
QVector<qreal> customDashVector;

if ( !QgsSymbolLayerV2Utils::lineFromSld( strokeElem, penStyle,
color, width,
&penJoinStyle, &penCapStyle,
&customDashVector ) )
return NULL;

double offset = 0.0;
QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
if ( !perpOffsetElem.isNull() )
{
bool ok;
double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
if ( ok )
offset = d;
}

QgsSimpleLineSymbolLayerV2* l = new QgsSimpleLineSymbolLayerV2( color, width, penStyle );
l->setOffset( offset );
l->setPenJoinStyle( penJoinStyle );
l->setPenCapStyle( penCapStyle );
l->setUseCustomDashPattern( penStyle == Qt::CustomDashLine );
l->setCustomDashVector( customDashVector );
return l;
}



/////////

Expand Down Expand Up @@ -574,6 +648,154 @@ QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::clone() const
return x;
}

void QgsMarkerLineSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
for ( int i = 0; i < mMarker->symbolLayerCount(); i++ )
{
QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

// <Geometry>
QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom", "" ) );

QString gap;
switch( mPlacement )
{
case FirstVertex:
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "firstPoint" ) );
break;
case LastVertex:
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
break;
case CentralPoint:
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "centralPoint" ) );
break;
case Vertex:
// no way to get line/polygon's vertices, use a VendorOption
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "points" ) );
break;
default:
gap = QString::number( mInterval );
break;
}

if( !mRotateMarker )
{
// markers in LineSymbolizer must be drawn following the line orientation,
// use a VendorOption when no marker rotation
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "rotateMarker", "0" ) );
}

// <Stroke>
QDomElement strokeElem = doc.createElement( "se:Stroke" );
symbolizerElem.appendChild( strokeElem );

// <GraphicStroke>
QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
strokeElem.appendChild( graphicStrokeElem );

QgsSymbolLayerV2 *layer = mMarker->symbolLayer( i );
QgsMarkerSymbolLayerV2 *markerLayer = static_cast<QgsMarkerSymbolLayerV2 *>( layer );
if ( !markerLayer )
{
graphicStrokeElem.appendChild( doc.createComment( QString( "MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( markerLayer->layerType() ) ) );
}
else
{
markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
}

if ( !gap.isEmpty() )
{
QDomElement gapElem = doc.createElement( "se:Gap" );
QgsSymbolLayerV2Utils::createFunctionElement( doc, gapElem, gap );
graphicStrokeElem.appendChild( gapElem );
}

if ( !doubleNear( mOffset, 0.0 ) )
{
QDomElement perpOffsetElem = doc.createElement( "se:PerpendicularOffset" );
perpOffsetElem.appendChild( doc.createTextNode( QString::number( mOffset ) ) );
symbolizerElem.appendChild( perpOffsetElem );
}
}
}

QgsSymbolLayerV2* QgsMarkerLineSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QDomElement strokeElem = element.firstChildElement( "Stroke" );
if ( strokeElem.isNull() )
return NULL;

QDomElement graphicStrokeElem = strokeElem.firstChildElement( "GraphicStroke" );
if ( graphicStrokeElem.isNull() )
return NULL;

// retrieve vendor options
bool rotateMarker = true;
Placement placement = Interval;

QgsStringMap vendorOptions = QgsSymbolLayerV2Utils::getVendorOptionList( element );
for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
{
if ( it.key() == "placement" )
{
if ( it.value() == "points" ) placement = Vertex;
else if ( it.value() == "firstPoint" ) placement = FirstVertex;
else if ( it.value() == "lastPoint" ) placement = LastVertex;
else if ( it.value() == "centralPoint" ) placement = CentralPoint;
}
else if ( it.value() == "rotateMarker" )
{
rotateMarker = it.value() == "0";
}
}

QgsMarkerSymbolV2 *marker = 0;

QgsSymbolLayerV2 *l = QgsSymbolLayerV2Utils::createMarkerLayerFromSld( graphicStrokeElem );
if ( l )
{
QgsSymbolLayerV2List layers;
layers.append( l );
marker = new QgsMarkerSymbolV2( layers );
}

double interval = 0.0;
QDomElement gapElem = element.firstChildElement( "Gap" );
if ( !gapElem.isNull() )
{
bool ok;
double d = gapElem.firstChild().nodeValue().toDouble( &ok );
if ( ok )
interval = d;
}

double offset = 0.0;
QDomElement perpOffsetElem = element.firstChildElement( "PerpendicularOffset" );
if ( !perpOffsetElem.isNull() )
{
bool ok;
double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
if ( ok )
offset = d;
}

QgsMarkerLineSymbolLayerV2* x = new QgsMarkerLineSymbolLayerV2( rotateMarker );
x->setPlacement( placement );
if ( !doubleNear( interval, 0.0 ) && interval > 0 )
x->setInterval( interval );
if ( marker )
x->setSubSymbol( marker );
if ( !doubleNear( offset, 0.0 ) )
x->setOffset( offset );
return x;
}

void QgsMarkerLineSymbolLayerV2::setWidth( double width )
{
mMarker->setSize( width );
Expand Down Expand Up @@ -683,3 +905,34 @@ QgsSymbolLayerV2* QgsLineDecorationSymbolLayerV2::clone() const
{
return new QgsLineDecorationSymbolLayerV2( mColor, mWidth );
}

void QgsLineDecorationSymbolLayerV2::toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
QDomElement symbolizerElem = doc.createElement( "se:LineSymbolizer" );
if ( !props.value( "uom", "" ).isEmpty() )
symbolizerElem.setAttribute( "uom", props.value( "uom", "" ) );
element.appendChild( symbolizerElem );

QgsSymbolLayerV2Utils::createGeometryElement( doc, symbolizerElem, props.value( "geom" , "" ) );

// <Stroke>
QDomElement strokeElem = doc.createElement( "se:Stroke" );
symbolizerElem.appendChild( strokeElem );

// <GraphicStroke>
QDomElement graphicStrokeElem = doc.createElement( "se:GraphicStroke" );
strokeElem.appendChild( graphicStrokeElem );

// <Graphic>
QDomElement graphicElem = doc.createElement( "se:Graphic" );
graphicStrokeElem.appendChild( graphicElem );

// <Mark>
QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, "arrowhead", QColor(), mColor, mWidth, mWidth*8 );

// <Rotation>
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, props.value( "angle", "" ) );

// use <VendorOption> to draw the decoration at end of the line
symbolizerElem.appendChild( QgsSymbolLayerV2Utils::createVendorOptionElement( doc, "placement", "lastPoint" ) );
}
9 changes: 9 additions & 0 deletions src/core/symbology-ng/qgslinesymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -39,6 +40,8 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

// new stuff

Qt::PenStyle penStyle() const { return mPenStyle; }
Expand Down Expand Up @@ -97,6 +100,7 @@ class CORE_EXPORT QgsMarkerLineSymbolLayerV2 : public QgsLineSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -112,6 +116,8 @@ class CORE_EXPORT QgsMarkerLineSymbolLayerV2 : public QgsLineSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

void setColor( const QColor& color );

QgsSymbolV2* subSymbol();
Expand Down Expand Up @@ -163,6 +169,7 @@ class CORE_EXPORT QgsLineDecorationSymbolLayerV2 : public QgsLineSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -178,6 +185,8 @@ class CORE_EXPORT QgsLineDecorationSymbolLayerV2 : public QgsLineSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void toSld( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

protected:
QPen mPen;
QPen mSelPen;
Expand Down
203 changes: 201 additions & 2 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include <QSvgRenderer>
#include <QFileInfo>
#include <QDir>
#include <QDomDocument>
#include <QDomElement>

#include <cmath>

Expand All @@ -34,6 +36,8 @@ static QPointF _rotatedOffset( const QPointF& offset, double angle )

QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( QString name, QColor color, QColor borderColor, double size, double angle )
{
if ( name == "rectangle" )
name = "square";
mName = name;
mColor = color;
mBorderColor = borderColor;
Expand Down Expand Up @@ -222,7 +226,7 @@ bool QgsSimpleMarkerSymbolLayerV2::prepareShape()
{
mPolygon.clear();

if ( mName == "rectangle" )
if ( mName == "square" )
{
mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
return true;
Expand Down Expand Up @@ -324,7 +328,7 @@ bool QgsSimpleMarkerSymbolLayerV2::preparePath()
mPath.lineTo( 0, 1 ); // vertical
return true;
}
else if ( mName == "cross2" )
else if ( mName == "x" || mName == "cross2" )
{
mPath.moveTo( -1, -1 );
mPath.lineTo( 1, 1 );
Expand Down Expand Up @@ -426,6 +430,66 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
return m;
}

void QgsSimpleMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
// <Graphic>
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QgsSymbolLayerV2Utils::wellKnownMarkerToSld( doc, graphicElem, mName, mColor, mBorderColor, -1, mSize );

// <Rotation>
QString angleFunc;
bool ok;
double angle = props.value( "angle", "0" ).toDouble( &ok );
if ( !ok )
{
angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
}
else if ( angle + mAngle != 0 )
{
angleFunc = QString::number( angle + mAngle );
}
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
}

QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QDomElement graphicElem = element.firstChildElement( "Graphic" );
if( graphicElem.isNull() )
return NULL;

QString name = "square";
QColor color, borderColor;
double borderWidth, size;

if ( !QgsSymbolLayerV2Utils::wellKnownMarkerFromSld( graphicElem, name, color, borderColor, borderWidth, size ) )
return NULL;

double angle = 0.0;
QString angleFunc;
if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
{
bool ok;
double d = angleFunc.toDouble( &ok );
if ( ok )
angle = d;
}

QPointF offset;
QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );

QgsMarkerSymbolLayerV2 *m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size );
m->setAngle( angle );
m->setOffset( offset );
return m;
}

void QgsSimpleMarkerSymbolLayerV2::drawMarker( QPainter* p, QgsSymbolV2RenderContext& context )
{
Q_UNUSED( context );
Expand Down Expand Up @@ -627,6 +691,73 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
return m;
}

void QgsSvgMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
// <Graphic>
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QgsSymbolLayerV2Utils::externalGraphicToSld( doc, graphicElem, mPath, "image/svg+xml", mFillColor, mSize );

// <Rotation>
QString angleFunc;
bool ok;
double angle = props.value( "angle", "0" ).toDouble( &ok );
if ( !ok )
{
angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
}
else if ( angle + mAngle != 0 )
{
angleFunc = QString::number( angle + mAngle );
}

QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
}

QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QDomElement graphicElem = element.firstChildElement( "Graphic" );
if( graphicElem.isNull() )
return NULL;

QString path, mimeType;
QColor fillColor;
double size;

if ( !QgsSymbolLayerV2Utils::externalGraphicFromSld( graphicElem, path, mimeType, fillColor, size ) )
return NULL;

if ( mimeType != "image/svg+xml" )
return NULL;

double angle = 0.0;
QString angleFunc;
if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
{
bool ok;
double d = angleFunc.toDouble( &ok );
if ( ok )
angle = d;
}

QPointF offset;
QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );

QgsSvgMarkerSymbolLayerV2* m = new QgsSvgMarkerSymbolLayerV2( path, size );
m->setFillColor( fillColor );
//m->setOutlineColor( outlineColor );
//m->setOutlineWidth( outlineWidth );
m->setAngle( angle );
m->setOffset( offset );
return m;
}


QStringList QgsSvgMarkerSymbolLayerV2::listSvgFiles()
{
Expand Down Expand Up @@ -829,3 +960,71 @@ QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
m->setOffset( mOffset );
return m;
}

void QgsFontMarkerSymbolLayerV2::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const
{
// <Graphic>
QDomElement graphicElem = doc.createElement( "se:Graphic" );
element.appendChild( graphicElem );

QString fontPath = QString( "ttf://%1" ).arg( mFontFamily );
int markIndex = mChr.unicode();
QgsSymbolLayerV2Utils::externalMarkerToSld( doc, graphicElem, fontPath, "ttf", &markIndex, mColor, mSize );

// <Rotation>
QString angleFunc;
bool ok;
double angle = props.value( "angle", "0" ).toDouble( &ok );
if ( !ok )
{
angleFunc = QString( "%1 + %2" ).arg( props.value( "angle", "0" ) ).arg( mAngle );
}
else if ( angle + mAngle != 0 )
{
angleFunc = QString::number( angle + mAngle );
}
QgsSymbolLayerV2Utils::createRotationElement( doc, graphicElem, angleFunc );

// <Displacement>
QgsSymbolLayerV2Utils::createDisplacementElement( doc, graphicElem, mOffset );
}

QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::createFromSld( QDomElement &element )
{
QgsDebugMsg( "Entered." );

QDomElement graphicElem = element.firstChildElement( "Graphic" );
if( graphicElem.isNull() )
return NULL;

QString name, format;
QColor color;
double size;
int chr;

if ( !QgsSymbolLayerV2Utils::externalMarkerFromSld( graphicElem, name, format, chr, color, size ) )
return NULL;

if ( !name.startsWith( "ttf://" ) || format != "ttf" )
return NULL;

QString fontFamily = name.mid( 6 );

double angle = 0.0;
QString angleFunc;
if ( QgsSymbolLayerV2Utils::rotationFromSldElement( graphicElem, angleFunc ) )
{
bool ok;
double d = angleFunc.toDouble( &ok );
if ( ok )
angle = d;
}

QPointF offset;
QgsSymbolLayerV2Utils::displacementFromSldElement( graphicElem, offset );

QgsMarkerSymbolLayerV2 *m = new QgsFontMarkerSymbolLayerV2( fontFamily, chr, size, color );
m->setAngle( angle );
m->setOffset( offset );
return m;
}
9 changes: 9 additions & 0 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -43,6 +44,8 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

QString name() const { return mName; }
void setName( QString name ) { mName = name; }

Expand Down Expand Up @@ -87,6 +90,7 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

//! Return a list of all available svg files
static QStringList listSvgFiles();
Expand All @@ -111,6 +115,8 @@ class CORE_EXPORT QgsSvgMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

QString path() const { return mPath; }
void setPath( QString path );

Expand Down Expand Up @@ -161,6 +167,7 @@ class CORE_EXPORT QgsFontMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
// static stuff

static QgsSymbolLayerV2* create( const QgsStringMap& properties = QgsStringMap() );
static QgsSymbolLayerV2* createFromSld( QDomElement &element );

// implemented from base classes

Expand All @@ -176,6 +183,8 @@ class CORE_EXPORT QgsFontMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2

QgsSymbolLayerV2* clone() const;

void writeSldMarker( QDomDocument &doc, QDomElement &element, QgsStringMap props ) const;

// new methods

QString fontFamily() const { return mFontFamily; }
Expand Down
35 changes: 30 additions & 5 deletions src/core/symbology-ng/qgspointdisplacementrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
#include "qgssymbolv2.h"
#include "qgssymbollayerv2utils.h"
#include "qgsvectorlayer.h"

#include <QDomElement>
#include <QPainter>

#include <cmath>

QgsPointDisplacementRenderer::QgsPointDisplacementRenderer( const QString& labelAttributeName )
Expand Down Expand Up @@ -66,7 +68,13 @@ QgsFeatureRendererV2* QgsPointDisplacementRenderer::clone()
return r;
}

void QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
void QgsPointDisplacementRenderer::toSld( QDomDocument& doc, QDomElement &element ) const
{
mRenderer->toSld( doc, element );
}


bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
Q_UNUSED( drawVertexMarker );
//point position in screen coords
Expand All @@ -75,7 +83,7 @@ void QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRender
if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D )
{
//can only render point type
return;
return false;
}
QPointF pt;
_getPoint( pt, context, geom->asWkb() );
Expand Down Expand Up @@ -105,14 +113,14 @@ void QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRender
{
labelAttributeList << QString();
}
symbolList << dynamic_cast<QgsMarkerSymbolV2*>( mRenderer->symbolForFeature( attIt.value() ) );
symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, attIt.value() ) );
}
}
}
}
else //only one feature
{
symbolList << dynamic_cast<QgsMarkerSymbolV2*>( mRenderer->symbolForFeature( feature ) );
symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, feature ) );
if ( mDrawLabels )
{
labelAttributeList << getLabel( feature );
Expand All @@ -125,7 +133,7 @@ void QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRender

if ( symbolList.isEmpty() && labelAttributeList.isEmpty() )
{
return; //display all point symbols for one posi
return true; //display all point symbols for one posi
}


Expand Down Expand Up @@ -176,6 +184,7 @@ void QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRender
drawSymbols( feature, context, symbolList, symbolPositions, selected );
//and also the labels
drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
return true;
}

void QgsPointDisplacementRenderer::setEmbeddedRenderer( QgsFeatureRendererV2* r )
Expand Down Expand Up @@ -573,3 +582,19 @@ void QgsPointDisplacementRenderer::drawLabels( const QPointF& centerPoint, QgsSy
p->restore();
}
}

QgsSymbolV2* QgsPointDisplacementRenderer::firstSymbolForFeature( QgsFeatureRendererV2* r, QgsFeature& f )
{
if ( !r )
{
return 0;
}

QgsSymbolV2List symbolList = r->symbolsForFeature( f );
if ( symbolList.size() < 1 )
{
return 0;
}

return symbolList.at( 0 );
}
6 changes: 5 additions & 1 deletion src/core/symbology-ng/qgspointdisplacementrenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsFeatureRendererV2

QgsFeatureRendererV2* clone();

virtual void toSld( QDomDocument& doc, QDomElement &element ) const;

/**Reimplemented from QgsFeatureRendererV2*/
void renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );
bool renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );

QgsSymbolV2* symbolForFeature( QgsFeature& feature );

Expand Down Expand Up @@ -145,6 +147,8 @@ class CORE_EXPORT QgsPointDisplacementRenderer: public QgsFeatureRendererV2
void drawCircle( double radiusPainterUnits, QgsSymbolV2RenderContext& context, const QPointF& centerPoint, int nSymbols );
void drawSymbols( QgsFeature& f, QgsRenderContext& context, const QList<QgsMarkerSymbolV2*>& symbolList, const QList<QPointF>& symbolPositions, bool selected = false );
void drawLabels( const QPointF& centerPoint, QgsSymbolV2RenderContext& context, const QList<QPointF>& labelShifts, const QStringList& labelList );
/**Returns first symbol for feature or 0 if none*/
QgsSymbolV2* firstSymbolForFeature( QgsFeatureRendererV2* r, QgsFeature& f );
};

#endif // QGSPOINTDISPLACEMENTRENDERER_H
123 changes: 120 additions & 3 deletions src/core/symbology-ng/qgsrendererv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,18 @@ QgsFeatureRendererV2* QgsFeatureRendererV2::defaultRenderer( QGis::GeometryType
}


void QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
bool QgsFeatureRendererV2::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
QgsSymbolV2* symbol = symbolForFeature( feature );
if ( symbol == NULL )
return;
return false;

renderFeatureWithSymbol( feature, symbol, context, layer, selected, drawVertexMarker );
return true;
}

void QgsFeatureRendererV2::renderFeatureWithSymbol( QgsFeature& feature, QgsSymbolV2* symbol, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker )
{
QgsSymbolV2::SymbolType symbolType = symbol->type();

QgsGeometry* geom = feature.geometry();
Expand Down Expand Up @@ -356,7 +362,6 @@ QgsFeatureRendererV2* QgsFeatureRendererV2::load( QDomElement& element )
if ( r )
{
r->setUsingSymbolLevels( element.attribute( "symbollevels", "0" ).toInt() );
r->setUsingFirstRule( element.attribute( "firstrule", "0" ).toInt() );
}
return r;
}
Expand All @@ -367,6 +372,110 @@ QDomElement QgsFeatureRendererV2::save( QDomDocument& doc )
return doc.createElement( RENDERER_TAG_NAME );
}

QgsFeatureRendererV2* QgsFeatureRendererV2::loadSld( const QDomNode &node, QGis::GeometryType geomType, QString &errorMessage )
{
QDomElement element = node.toElement();
if ( element.isNull() )
return NULL;

// get the UserStyle element
QDomElement userStyleElem = element.firstChildElement( "UserStyle" );
if ( userStyleElem.isNull() )
{
// UserStyle element not found, nothing will be rendered
errorMessage = "Info: UserStyle element not found.";
return NULL;
}

// get the FeatureTypeStyle element
QDomElement featTypeStyleElem = userStyleElem.firstChildElement( "FeatureTypeStyle" );
if ( featTypeStyleElem.isNull() )
{
errorMessage = "Info: FeatureTypeStyle element not found.";
return NULL;
}

// use the RuleRenderer when more rules are present or the rule
// has filters or min/max scale denominators set,
// otherwise use the SingleSymbol renderer
bool needRuleRenderer = false;
int ruleCount = 0;

QDomElement ruleElem = featTypeStyleElem.firstChildElement( "Rule" );
while( !ruleElem.isNull() )
{
ruleCount++;

// more rules present, use the RuleRenderer
if ( ruleCount > 1 )
{
QgsDebugMsg( "more Rule elements found: need a RuleRenderer" );
needRuleRenderer = true;
break;
}

QDomElement ruleChildElem = ruleElem.firstChildElement();
while( !ruleChildElem.isNull() )
{
// rule has filter or min/max scale denominator, use the RuleRenderer
if ( ruleChildElem.localName() == "Filter" ||
ruleChildElem.localName() == "MinScaleDenominator" ||
ruleChildElem.localName() == "MaxScaleDenominator" )
{
QgsDebugMsg( "Filter or Min/MaxScaleDenominator element found: need a RuleRenderer" );
needRuleRenderer = true;
break;
}

ruleChildElem = ruleChildElem.nextSiblingElement();
}

if ( needRuleRenderer )
{
break;
}

ruleElem = ruleElem.nextSiblingElement( "Rule" );
}

QString rendererType;
if ( needRuleRenderer )
{
rendererType = "RuleRenderer";
}
else
{
rendererType = "singleSymbol";
}
QgsDebugMsg( QString( "Instantiating a '%1' renderer..." ).arg( rendererType ) );

// create the renderer and return it
QgsRendererV2AbstractMetadata* m = QgsRendererV2Registry::instance()->rendererMetadata( rendererType );
if ( m == NULL )
{
errorMessage = QString( "Error: Unable to get metadata for '%1' renderer." ).arg( rendererType );
return NULL;
}

QgsFeatureRendererV2* r = m->createRendererFromSld( featTypeStyleElem, geomType );
return r;
}

QDomElement QgsFeatureRendererV2::writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const
{
QDomElement userStyleElem = doc.createElement( "UserStyle" );

QDomElement nameElem = doc.createElement( "se:Name" );
nameElem.appendChild( doc.createTextNode( layer.name() ) );
userStyleElem.appendChild( nameElem );

QDomElement featureTypeStyleElem = doc.createElement( "se:FeatureTypeStyle" );
toSld( doc, featureTypeStyleElem );
userStyleElem.appendChild( featureTypeStyleElem );

return userStyleElem;
}

QgsLegendSymbologyList QgsFeatureRendererV2::legendSymbologyItems( QSize iconSize )
{
Q_UNUSED( iconSize );
Expand Down Expand Up @@ -412,3 +521,11 @@ void QgsFeatureRendererV2::renderVertexMarkerPolygon( QPolygonF& pts, QList<QPol
}
}
}

QgsSymbolV2List QgsFeatureRendererV2::symbolsForFeature( QgsFeature& feat )
{
QgsSymbolV2List lst;
QgsSymbolV2* s = symbolForFeature( feat );
if ( s ) lst.append( s );
return lst;
}
74 changes: 64 additions & 10 deletions src/core/symbology-ng/qgsrendererv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@
#include <QVariant>
#include <QPair>
#include <QPixmap>

class QDomDocument;
class QDomElement;
#include <QDomDocument>
#include <QDomElement>

class QgsSymbolV2;
class QgsRenderContext;
class QgsFeature;
class QgsVectorLayer;

typedef QMap<QString, QString> QgsStringMap;

typedef QList<QgsSymbolV2*> QgsSymbolV2List;
typedef QMap<QString, QgsSymbolV2* > QgsSymbolV2Map;

Expand Down Expand Up @@ -73,27 +74,55 @@ class CORE_EXPORT QgsFeatureRendererV2

virtual QgsFeatureRendererV2* clone() = 0;

virtual void renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );
virtual bool renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer = -1, bool selected = false, bool drawVertexMarker = false );

//! for debugging
virtual QString dump();

enum Capabilities {
SymbolLevels = 1, // rendering with symbol levels (i.e. implements symbols(), symbolForFeature())
RotationField = 1 << 1, // rotate symbols by attribute value
MoreSymbolsPerFeature = 1 << 2 // may use more than one symbol to render a feature: symbolsForFeature() will return them
};

//! returns bitwise OR-ed capabilities of the renderer
//! \note added in 2.0
virtual int capabilities() { return 0; }

//! for symbol levels
virtual QgsSymbolV2List symbols() = 0;

bool usingSymbolLevels() const { return mUsingSymbolLevels; }
void setUsingSymbolLevels( bool usingSymbolLevels ) { mUsingSymbolLevels = usingSymbolLevels; }

bool usingFirstRule() const { return mUsingFirstRule; }
void setUsingFirstRule( bool usingFirstRule ) { mUsingFirstRule = usingFirstRule; }


//! create a renderer from XML element
static QgsFeatureRendererV2* load( QDomElement& symbologyElem );

//! store renderer info to XML element
virtual QDomElement save( QDomDocument& doc );

//! create the SLD UserStyle element following the SLD v1.1 specs
//! @note added in 1.9
virtual QDomElement writeSld( QDomDocument& doc, const QgsVectorLayer &layer ) const;

/** create a new renderer according to the information contained in
* the UserStyle element of a SLD style document
* @param node the node in the SLD document whose the UserStyle element
* is a child
* @param geomType the geometry type of the features, used to convert
* Symbolizer elements
* @param errorMessage it will contain the error message if something
* went wrong
* @return the renderer
* @note added in 1.9
*/
static QgsFeatureRendererV2* loadSld( const QDomNode &node, QGis::GeometryType geomType, QString &errorMessage );

//! used from subclasses to create SLD Rule elements following SLD v1.1 specs
//! @note added in 1.9
virtual void toSld( QDomDocument& doc, QDomElement &element ) const
{ element.appendChild( doc.createComment( QString( "FeatureRendererV2 %1 not implemented yet" ).arg( type() ) ) ); }

//! return a list of symbology items for the legend
virtual QgsLegendSymbologyList legendSymbologyItems( QSize iconSize );

Expand All @@ -104,9 +133,35 @@ class CORE_EXPORT QgsFeatureRendererV2
//! set type and size of editing vertex markers for subsequent rendering
void setVertexMarkerAppearance( int type, int size );

//! return rotation field name (or empty string if not set or not supported by renderer)
//! @note added in 1.9
virtual QString rotationField() const { return ""; }
//! sets rotation field of renderer (if supported by the renderer)
//! @note added in 1.9
virtual void setRotationField( QString fieldName ) { Q_UNUSED( fieldName ); }

//! return whether the renderer will render a feature or not.
//! Must be called between startRender() and stopRender() calls.
//! Default implementation uses symbolForFeature().
//! @note added in 1.9
virtual bool willRenderFeature( QgsFeature& feat ) { return symbolForFeature( feat ) != NULL; }

//! return list of symbols used for rendering the feature.
//! For renderers that do not support MoreSymbolsPerFeature it is more efficient
//! to use symbolForFeature()
//! @note added in 1.9
virtual QgsSymbolV2List symbolsForFeature( QgsFeature& feat );

protected:
QgsFeatureRendererV2( QString type );

void renderFeatureWithSymbol( QgsFeature& feature,
QgsSymbolV2* symbol,
QgsRenderContext& context,
int layer,
bool selected,
bool drawVertexMarker );

//! render editing vertex marker at specified point
void renderVertexMarker( QPointF& pt, QgsRenderContext& context );
//! render editing vertex marker for a polyline
Expand All @@ -121,7 +176,6 @@ class CORE_EXPORT QgsFeatureRendererV2
QString mType;

bool mUsingSymbolLevels;
bool mUsingFirstRule;

/** The current type of editing marker */
int mCurrentVertexMarkerType;
Expand All @@ -130,4 +184,4 @@ class CORE_EXPORT QgsFeatureRendererV2
};


#endif
#endif // QGSRENDERERV2_H
8 changes: 6 additions & 2 deletions src/core/symbology-ng/qgsrendererv2registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ QgsRendererV2Registry::QgsRendererV2Registry()
// add default renderers
addRenderer( new QgsRendererV2Metadata( "singleSymbol",
QObject::tr( "Single Symbol" ),
QgsSingleSymbolRendererV2::create ) );
QgsSingleSymbolRendererV2::create,
QgsSingleSymbolRendererV2::createFromSld ) );

addRenderer( new QgsRendererV2Metadata( "categorizedSymbol",
QObject::tr( "Categorized" ),
QgsCategorizedSymbolRendererV2::create ) );
Expand All @@ -24,7 +26,9 @@ QgsRendererV2Registry::QgsRendererV2Registry()

addRenderer( new QgsRendererV2Metadata( "RuleRenderer",
QObject::tr( "Rule-based" ),
QgsRuleBasedRendererV2::create ) );
QgsRuleBasedRendererV2::create,
QgsRuleBasedRendererV2::createFromSld ) );

addRenderer( new QgsRendererV2Metadata( "pointDisplacement",
QObject::tr( "Point displacement" ),
QgsPointDisplacementRenderer::create ) );
Expand Down
24 changes: 23 additions & 1 deletion src/core/symbology-ng/qgsrendererv2registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <QStringList>
#include <QDomElement>

#include "qgis.h"

class QgsFeatureRendererV2;
class QgsVectorLayer;
class QgsStyleV2;
Expand Down Expand Up @@ -36,6 +38,9 @@ class CORE_EXPORT QgsRendererV2AbstractMetadata
virtual QgsRendererV2Widget* createRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
{ Q_UNUSED( layer ); Q_UNUSED( style ); Q_UNUSED( renderer ); return NULL; }

virtual QgsFeatureRendererV2* createRendererFromSld( QDomElement& elem, QGis::GeometryType geomType )
{ Q_UNUSED( elem ); Q_UNUSED( geomType ); return NULL; }

protected:
//! name used within QGIS for identification (the same what renderer's type() returns)
QString mName;
Expand All @@ -48,6 +53,7 @@ class CORE_EXPORT QgsRendererV2AbstractMetadata

typedef QgsFeatureRendererV2*( *QgsRendererV2CreateFunc )( QDomElement& );
typedef QgsRendererV2Widget*( *QgsRendererV2WidgetFunc )( QgsVectorLayer*, QgsStyleV2*, QgsFeatureRendererV2* );
typedef QgsFeatureRendererV2*( *QgsRendererV2CreateFromSldFunc )( QDomElement&, QGis::GeometryType geomType );

/**
Convenience metadata class that uses static functions to create renderer and its widget.
Expand All @@ -62,14 +68,28 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
QgsRendererV2CreateFunc pfCreate,
QIcon icon = QIcon(),
QgsRendererV2WidgetFunc pfWidget = NULL )
: QgsRendererV2AbstractMetadata( name, visibleName, icon ), mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ) {}
: QgsRendererV2AbstractMetadata( name, visibleName, icon ),
mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ), mCreateFromSldFunc( NULL ) {}

QgsRendererV2Metadata( QString name,
QString visibleName,
QgsRendererV2CreateFunc pfCreate,
QgsRendererV2CreateFromSldFunc pfCreateFromSld,
QIcon icon = QIcon(),
QgsRendererV2WidgetFunc pfWidget = NULL )
: QgsRendererV2AbstractMetadata( name, visibleName, icon ),
mCreateFunc( pfCreate ), mWidgetFunc( pfWidget ), mCreateFromSldFunc( pfCreateFromSld ) {}

virtual QgsFeatureRendererV2* createRenderer( QDomElement& elem ) { return mCreateFunc ? mCreateFunc( elem ) : NULL; }
virtual QgsRendererV2Widget* createRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
{ return mWidgetFunc ? mWidgetFunc( layer, style, renderer ) : NULL; }
virtual QgsFeatureRendererV2* createRendererFromSld( QDomElement& elem, QGis::GeometryType geomType )
{ return mCreateFromSldFunc ? mCreateFromSldFunc( elem, geomType ) : NULL; }


QgsRendererV2CreateFunc createFunction() const { return mCreateFunc; }
QgsRendererV2WidgetFunc widgetFunction() const { return mWidgetFunc; }
QgsRendererV2CreateFromSldFunc createFromSldFunction() const { return mCreateFromSldFunc; }

void setWidgetFunction( QgsRendererV2WidgetFunc f ) { mWidgetFunc = f; }

Expand All @@ -78,6 +98,8 @@ class CORE_EXPORT QgsRendererV2Metadata : public QgsRendererV2AbstractMetadata
QgsRendererV2CreateFunc mCreateFunc;
//! pointer to function that creates a widget for configuration of renderer's params
QgsRendererV2WidgetFunc mWidgetFunc;
//! pointer to function that creates an instance of the renderer from SLD
QgsRendererV2CreateFromSldFunc mCreateFromSldFunc;
};

/**
Expand Down
Loading