Skip to content

Commit

Permalink
Porting Raymond Nijssen FOSS4G 2016 labeling work onto latest version…
Browse files Browse the repository at this point in the history
… of master, with basic support for testing. fixes #8925
  • Loading branch information
aaime committed Jul 25, 2017
1 parent 1b9c5be commit 59d8b18
Show file tree
Hide file tree
Showing 5 changed files with 424 additions and 10 deletions.
30 changes: 22 additions & 8 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -2205,20 +2205,34 @@ bool QgsVectorLayer::writeSld( QDomNode &node, QDomDocument &doc, QString &error
{
Q_UNUSED( errorMessage );

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

QgsStringMap localProps = QgsStringMap( props );
if ( hasScaleBasedVisibility() )
{
QgsSymbolLayerUtils::mergeScaleDependencies( maximumScale(), minimumScale(), localProps );
}

if ( isSpatial() )
{
node.appendChild( mRenderer->writeSld( doc, name(), localProps ) );
if ( isSpatial() ) {
// store the Name element
QDomElement nameNode = doc.createElement( "se:Name" );
nameNode.appendChild( doc.createTextNode( name() ) );
node.appendChild( nameNode );

QDomElement userStyleElem = doc.createElement( "UserStyle" );
node.appendChild( userStyleElem );

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

userStyleElem.appendChild( nameElem );

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

mRenderer->toSld( doc, featureTypeStyleElem, localProps );
if ( mLabeling != nullptr )
{
mLabeling->toSld( featureTypeStyleElem, localProps );
}
}
return true;
}
Expand Down
49 changes: 49 additions & 0 deletions src/core/qgsvectorlayerlabeling.cpp
Expand Up @@ -17,6 +17,8 @@
#include "qgspallabeling.h"
#include "qgsrulebasedlabeling.h"
#include "qgsvectorlayer.h"
#include "qgssymbollayerutils.h"
#include "qgis.h"


QgsAbstractVectorLayerLabeling *QgsAbstractVectorLayerLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
Expand Down Expand Up @@ -88,3 +90,50 @@ QgsVectorLayerSimpleLabeling *QgsVectorLayerSimpleLabeling::create( const QDomEl

return new QgsVectorLayerSimpleLabeling( QgsPalLayerSettings() );
}

void QgsVectorLayerSimpleLabeling::toSld( QDomNode &parent, const QgsStringMap &props ) const
{

if ( mSettings->drawLabels )
{
QDomDocument doc = parent.ownerDocument();

QDomElement ruleElement = doc.createElement( QStringLiteral( "se:Rule" ) );
parent.appendChild( ruleElement );

QDomElement textSymbolizerElement = doc.createElement( QStringLiteral( "se:TextSymbolizer" ) );
ruleElement.appendChild( textSymbolizerElement );

// label
QDomElement labelElement = doc.createElement( QStringLiteral( "se:Label" ) );
textSymbolizerElement.appendChild( labelElement );

if ( mSettings->isExpression )
{
labelElement.appendChild( doc.createComment( QStringLiteral( "SE Export for %1 not implemented yet" ).arg( mSettings->getLabelExpression()->dump() ) ) );
labelElement.appendChild( doc.createTextNode( "Placeholder" ) );
}
else
{
QDomElement propertyNameElement = doc.createElement( QStringLiteral( "ogc:PropertyName" ) );
propertyNameElement.appendChild( doc.createTextNode( mSettings->fieldName ) );
labelElement.appendChild( propertyNameElement );
}

// font
QDomElement fontElement = doc.createElement( QStringLiteral( "se:Font" ) );
textSymbolizerElement.appendChild( fontElement );
QgsTextFormat format = mSettings->format();
fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-family" ), format.font().family() ) );
double fontSize = QgsSymbolLayerUtils::rescaleUom( format.size(), format.sizeUnit(), props );
fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-size" ), QString::number( fontSize ) ) );


// fill
QDomElement fillElement = doc.createElement( QStringLiteral( "se:Fill" ) );
textSymbolizerElement.appendChild( fillElement );
fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill" ), format.color().name() ) );
}


}
16 changes: 14 additions & 2 deletions src/core/qgsvectorlayerlabeling.h
Expand Up @@ -19,9 +19,9 @@

#include <QString>
#include <QStringList>
#include <QDomNode>

#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgis.h"

class QDomDocument;
class QDomElement;
Expand Down Expand Up @@ -76,6 +76,17 @@ class CORE_EXPORT QgsAbstractVectorLayerLabeling
//! Try to create instance of an implementation based on the XML data
static QgsAbstractVectorLayerLabeling *create( const QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;

/**
* Writes the SE 1.1 TextSymbolizer element based on the current layer labelling settings
*/
virtual void toSld( QDomNode& parent, const QgsStringMap& props ) const
{
Q_UNUSED( parent )
Q_UNUSED( props )
QDomDocument doc = parent.ownerDocument();
parent.appendChild( doc.createComment( QStringLiteral( "SE Export for %1 not implemented yet" ).arg( type() ) ) );
}

private:
Q_DISABLE_COPY( QgsAbstractVectorLayerLabeling )

Expand Down Expand Up @@ -105,6 +116,7 @@ class CORE_EXPORT QgsVectorLayerSimpleLabeling : public QgsAbstractVectorLayerLa
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const override;
virtual QgsPalLayerSettings settings( const QString &providerId = QString() ) const override;
bool requiresAdvancedEffects() const override;
virtual void toSld( QDomNode& parent, const QgsStringMap& props ) const override;

//! Create the instance from a DOM element with saved configuration
static QgsVectorLayerSimpleLabeling *create( const QDomElement &element, const QgsReadWriteContext &context );
Expand Down
54 changes: 54 additions & 0 deletions tests/src/python/test_qgssymbollayer_createsld.py
Expand Up @@ -546,6 +546,60 @@ def assertRuleRangeFilter(self, root, index, attributeName, min, includeMin, max
ltValue = lt.childNodes().item(1)
self.assertEquals(max, ltValue.toElement().text())

def testSimpleLabelling(self):
layer = QgsVectorLayer("Point", "addfeat", "memory")
self.loadStyleWithCustomProperties(layer, "simpleLabel")

dom, root = self.layerToSld(layer)
# print("Simple label text symbolizer" + dom.toString())

ts = self.getTextSymbolizer(root, 1, 0)
self.assertPropertyName(ts, 'se:Label', 'NAME')
font = self.assertElement(ts, 'se:Font', 0)
self.assertEquals('Liberation Mono', self.assertSvgParameter(font, 'font-family').text())
self.assertEquals('9', self.assertSvgParameter(font, 'font-size').text())

fill = self.assertElement(ts, 'se:Fill', 0)
self.assertEquals('#000000', self.assertSvgParameter(fill, "fill").text())

def loadStyleWithCustomProperties(self, layer, qmlFileName):
# load the style, only vector symbology
path = QDir.toNativeSeparators('%s/symbol_layer/%s.qml' % (unitTestDataPath(), qmlFileName))

# labelling is in custom properties, they need to be loaded separately
status = layer.loadNamedStyle(path)
doc = QDomDocument()
file = QFile(path)
file.open(QIODevice.ReadOnly)
doc.setContent(file, True)
file.close()
flag = layer.readCustomProperties(doc.documentElement())

def assertElement(self, container, elementName, index):
list = container.elementsByTagName(elementName)
self.assertTrue(list.size() > index, 'Expected to find at least ' + str(index + 1) + ' ' + elementName + ' in ' + container.nodeName() + ' but found ' + str(list.size()))
node = list.item(index)
self.assertTrue(node.isElement(), 'Found node but it''s not an element')
return node.toElement()

def getTextSymbolizer(self, root, ruleIndex, textSymbolizerIndex):
rule = self.assertElement(root, 'se:Rule', ruleIndex)
textSymbolizer = self.assertElement(rule, 'se:TextSymbolizer', textSymbolizerIndex)
return textSymbolizer

def assertPropertyName(self, root, containerProperty, expectedAttributeName):
container = root.elementsByTagName(containerProperty).item(0).toElement()
property = container.elementsByTagName("ogc:PropertyName").item(0).toElement()
self.assertEqual(expectedAttributeName, property.text())

def assertSvgParameter(self, container, expectedName):
list = container.elementsByTagName("se:SvgParameter")
for i in range(0, list.size()):
item = list.item(i)
if item.isElement and item.isElement() and item.toElement().attribute('name') == expectedName:
return item.toElement()
self.fail('Could not find a se:SvgParameter named ' + expectedName + ' in ' + container.nodeName())

def assertScaleDenominator(self, root, expectedMinScale, expectedMaxScale, index=0):
rule = root.elementsByTagName('se:Rule').item(index).toElement()

Expand Down

0 comments on commit 59d8b18

Please sign in to comment.