text: /***************************************************************************
      qgsvectorlayerlabeling.cpp
      ---------------------
      begin                : September 2015
      copyright            : (C) 2015 by Martin Dobias
      email                : wonder dot sk at gmail dot com
   ***************************************************************************
   *                                                                         *
   *   This program is free software; you can redistribute it and/or modify  *
   *   it under the terms of the GNU General Public License as published by  *
   *   the Free Software Foundation; either version 2 of the License, or     *
   *   (at your option) any later version.                                   *
   *                                                                         *
   ***************************************************************************/
  #include "qgsvectorlayerlabeling.h"
  
  #include "qgspallabeling.h"
  #include "qgsrulebasedlabeling.h"
  #include "qgsvectorlayer.h"
  #include "qgssymbollayerutils.h"
  #include "qgssymbollayer.h"
  #include "qgsmarkersymbollayer.h"
  #include "qgis.h"
  
  
  QgsAbstractVectorLayerLabeling *QgsAbstractVectorLayerLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
  {
    QString type = element.attribute( QStringLiteral( "type" ) );
    if ( type == QLatin1String( "rule-based" ) )
    {
      return QgsRuleBasedLabeling::create( element, context );
    }
    else if ( type == QLatin1String( "simple" ) )
    {
      return QgsVectorLayerSimpleLabeling::create( element, context );
    }
    else
    {
      return nullptr;
    }
  }
  
  QgsVectorLayerLabelProvider *QgsVectorLayerSimpleLabeling::provider( QgsVectorLayer *layer ) const
  {
    return new QgsVectorLayerLabelProvider( layer, QString(), false, mSettings.get() );
  }
  
  QgsVectorLayerSimpleLabeling::QgsVectorLayerSimpleLabeling( const QgsPalLayerSettings &settings )
    : mSettings( new QgsPalLayerSettings( settings ) )
  {
  
  }
  
  QString QgsVectorLayerSimpleLabeling::type() const
  {
    return QStringLiteral( "simple" );
  }
  
  QgsAbstractVectorLayerLabeling *QgsVectorLayerSimpleLabeling::clone() const
  {
    return new QgsVectorLayerSimpleLabeling( *mSettings );
  }
  
  QDomElement QgsVectorLayerSimpleLabeling::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
  {
    QDomElement elem = doc.createElement( QStringLiteral( "labeling" ) );
    elem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "simple" ) );
    elem.appendChild( mSettings->writeXml( doc, context ) );
    return elem;
  }
  
  QgsPalLayerSettings QgsVectorLayerSimpleLabeling::settings( const QString &providerId ) const
  {
    Q_UNUSED( providerId );
    return *mSettings;
  }
  
  bool QgsVectorLayerSimpleLabeling::requiresAdvancedEffects() const
  {
    return mSettings->format().containsAdvancedEffects();
  }
  
  QgsVectorLayerSimpleLabeling *QgsVectorLayerSimpleLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
  {
    QDomElement settingsElem = element.firstChildElement( QStringLiteral( "settings" ) );
    if ( !settingsElem.isNull() )
    {
      QgsPalLayerSettings settings;
      settings.readXml( settingsElem, context );
      return new QgsVectorLayerSimpleLabeling( settings );
    }
  
    return new QgsVectorLayerSimpleLabeling( QgsPalLayerSettings() );
  }
  
  QPointF quadOffsetToSldAnchor( QgsPalLayerSettings::QuadrantPosition quadrantPosition )
  {
    double quadOffsetX = 0.5, quadOffsetY = 0.5;
  
    // adjust quadrant offset of labels
    switch ( quadrantPosition )
    {
      case QgsPalLayerSettings::QuadrantAboveLeft:
        quadOffsetX = 1;
        quadOffsetY = 0;
        break;
      case QgsPalLayerSettings::QuadrantAbove:
        quadOffsetX = 0.5;
        quadOffsetY = 0;
        break;
      case QgsPalLayerSettings::QuadrantAboveRight:
        quadOffsetX = 0;
        quadOffsetY = 0;
        break;
      case QgsPalLayerSettings::QuadrantLeft:
        quadOffsetX = 1;
        quadOffsetY = 0.5;
        break;
      case QgsPalLayerSettings::QuadrantRight:
        quadOffsetX = 0;
        quadOffsetY = 0.5;
        break;
      case QgsPalLayerSettings::QuadrantBelowLeft:
        quadOffsetX = 1;
        quadOffsetY = 1;
        break;
      case QgsPalLayerSettings::QuadrantBelow:
        quadOffsetX = 0.5;
        quadOffsetY = 1;
        break;
      case QgsPalLayerSettings::QuadrantBelowRight:
        quadOffsetX = 0;
        quadOffsetY = 1.0;
        break;
      case QgsPalLayerSettings::QuadrantOver:
        break;
    }
  
    return QPointF( quadOffsetX, quadOffsetY );
  }
  
  /*
   * This is not a generic function encoder, just enough to encode the label case control functions
   */
  void appendSimpleFunction( QDomDocument &doc, QDomElement &parent, const QString &name, const QString &attribute )
  {
    QDomElement function = doc.createElement( QStringLiteral( "ogc:Function" ) );
    function.setAttribute( QStringLiteral( "name" ), name );
    parent.appendChild( function );
    QDomElement property = doc.createElement( QStringLiteral( "ogc:PropertyName" ) );
    property.appendChild( doc.createTextNode( attribute ) );
    function.appendChild( property );
  }
  
  std::unique_ptr<QgsMarkerSymbolLayer> backgroundToMarkerLayer( const QgsTextBackgroundSettings &settings )
  {
    std::unique_ptr<QgsMarkerSymbolLayer> layer;
    switch ( settings.type() )
    {
      case QgsTextBackgroundSettings::ShapeSVG:
      {
        QgsSvgMarkerSymbolLayer *svg = new QgsSvgMarkerSymbolLayer( settings.svgFile() );
        svg->setStrokeWidth( settings.strokeWidth() );
        svg->setStrokeWidthUnit( settings.strokeWidthUnit() );
        layer.reset( svg );
        break;
      }
      case QgsTextBackgroundSettings::ShapeCircle:
      case QgsTextBackgroundSettings::ShapeEllipse:
      case QgsTextBackgroundSettings::ShapeRectangle:
      case QgsTextBackgroundSettings::ShapeSquare:
      {
        QgsSimpleMarkerSymbolLayer *marker = new QgsSimpleMarkerSymbolLayer();
        // default value
        QgsSimpleMarkerSymbolLayerBase::Shape shape = QgsSimpleMarkerSymbolLayerBase::Diamond;
        switch ( settings.type() )
        {
          case QgsTextBackgroundSettings::ShapeCircle:
          case QgsTextBackgroundSettings::ShapeEllipse:
            shape = QgsSimpleMarkerSymbolLayerBase::Circle;
            break;
          case QgsTextBackgroundSettings::ShapeRectangle:
          case QgsTextBackgroundSettings::ShapeSquare:
            shape = QgsSimpleMarkerSymbolLayerBase::Square;
            break;
          case QgsTextBackgroundSettings::ShapeSVG:
            break;
        }
  
        marker->setShape( shape );
        marker->setStrokeWidth( settings.strokeWidth() );
        marker->setStrokeWidthUnit( settings.strokeWidthUnit() );
        layer.reset( marker );
      }
    }
    layer->setEnabled( true );
    // a marker does not have a size x and y, just a size (and it should be at least one)
    QSizeF size = settings.size();
    layer->setSize( std::max( 1., std::max( size.width(), size.height() ) ) );
    layer->setSizeUnit( settings.sizeUnit() );
    // fill and stroke
    QColor fillColor = settings.fillColor();
    QColor strokeColor = settings.strokeColor();
    if ( settings.opacity() < 1 )
    {
      int alpha = std::round( settings.opacity() * 255 );
      fillColor.setAlpha( alpha );
      strokeColor.setAlpha( alpha );
    }
    layer->setFillColor( fillColor );
    layer->setStrokeColor( strokeColor );
    // rotation
    if ( settings.rotationType() == QgsTextBackgroundSettings::RotationFixed )
    {
      layer->setAngle( settings.rotation() );
    }
    // offset
    layer->setOffset( settings.offset() );
    layer->setOffsetUnit( settings.offsetUnit() );
  
    return layer;
  }
  
  void QgsAbstractVectorLayerLabeling::writeTextSymbolizer( QDomNode &parent, QgsPalLayerSettings &settings, const QgsStringMap &props ) const
  {
    QDomDocument doc = parent.ownerDocument();
  
    // text symbolizer
    QDomElement textSymbolizerElement = doc.createElement( QStringLiteral( "se:TextSymbolizer" ) );
    parent.appendChild( textSymbolizerElement );
  
    // label
    QgsTextFormat format = settings.format();
    QFont font = format.font();
    QDomElement labelElement = doc.createElement( QStringLiteral( "se:Label" ) );
    textSymbolizerElement.appendChild( labelElement );
    if ( settings.isExpression )
    {
      labelElement.appendChild( doc.createComment( QStringLiteral( "SE Export for %1 not implemented yet" ).arg( settings.getLabelExpression()->dump() ) ) );
      labelElement.appendChild( doc.createTextNode( "Placeholder" ) );
    }
    else
    {
      if ( font.capitalization() == QFont::AllUppercase )
      {
        appendSimpleFunction( doc, labelElement, QStringLiteral( "strToUpperCase" ), settings.fieldName );
      }
      else if ( font.capitalization() == QFont::AllLowercase )
      {
        appendSimpleFunction( doc, labelElement, QStringLiteral( "strToLowerCase" ), settings.fieldName );
      }
      else if ( font.capitalization() == QFont::Capitalize )
      {
        appendSimpleFunction( doc, labelElement, QStringLiteral( "strCapitalize" ), settings.fieldName );
      }
      else
      {
        QDomElement propertyNameElement = doc.createElement( QStringLiteral( "ogc:PropertyName" ) );
        propertyNameElement.appendChild( doc.createTextNode( settings.fieldName ) );
        labelElement.appendChild( propertyNameElement );
      }
    }
  
    // font
    QDomElement fontElement = doc.createElement( QStringLiteral( "se:Font" ) );
    textSymbolizerElement.appendChild( fontElement );
    fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-family" ), font.family() ) );
    double fontSize = QgsSymbolLayerUtils::rescaleUom( format.size(), format.sizeUnit(), props );
    fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-size" ), QString::number( fontSize ) ) );
    if ( format.font().italic() )
    {
      fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-style" ), QStringLiteral( "italic" ) ) );
    }
    if ( format.font().bold() )
    {
      fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-weight" ), QStringLiteral( "bold" ) ) );
    }
  
    // label placement
    QDomElement labelPlacement = doc.createElement( QStringLiteral( "se:LabelPlacement" ) );
    textSymbolizerElement.appendChild( labelPlacement );
    double maxDisplacement = 0;
    double repeatDistance = 0;
    switch ( settings.placement )
    {
      case QgsPalLayerSettings::OverPoint:
      {
        QDomElement pointPlacement = doc.createElement( "se:PointPlacement" );
        labelPlacement.appendChild( pointPlacement );
        // anchor point
        QPointF anchor = quadOffsetToSldAnchor( settings.quadOffset );
        QgsSymbolLayerUtils::createAnchorPointElement( doc, pointPlacement, anchor );
        // displacement
        if ( settings.xOffset > 0 || settings.yOffset > 0 )
        {
          QgsUnitTypes::RenderUnit offsetUnit =  settings.offsetUnits;
          double dx = QgsSymbolLayerUtils::rescaleUom( settings.xOffset, offsetUnit, props );
          double dy = QgsSymbolLayerUtils::rescaleUom( settings.yOffset, offsetUnit, props );
          QgsSymbolLayerUtils::createDisplacementElement( doc, pointPlacement, QPointF( dx, dy ) );
        }
        // rotation
        if ( settings.angleOffset != 0 )
        {
          QDomElement rotation = doc.createElement( "se:Rotation" );
          pointPlacement.appendChild( rotation );
          rotation.appendChild( doc.createTextNode( QString::number( settings.angleOffset ) ) );
        }
      }
      break;
      case QgsPalLayerSettings::AroundPoint:
      case QgsPalLayerSettings::OrderedPositionsAroundPoint:
      {
        QDomElement pointPlacement = doc.createElement( "se:PointPlacement" );
        labelPlacement.appendChild( pointPlacement );
  
        // SLD cannot do either, but let's do a best effort setting the distance using
        // anchor point and displacement
        QgsSymbolLayerUtils::createAnchorPointElement( doc, pointPlacement, QPointF( 0, 0.5 ) );
        QgsUnitTypes::RenderUnit distUnit = settings.distUnits;
        double radius = QgsSymbolLayerUtils::rescaleUom( settings.dist, distUnit, props );
        double offset = std::sqrt( radius * radius / 2 ); // make it start top/right
        maxDisplacement = radius + 1; // lock the distance
        QgsSymbolLayerUtils::createDisplacementElement( doc, pointPlacement, QPointF( offset, offset ) );
      }
      break;
      case QgsPalLayerSettings::Horizontal:
      case QgsPalLayerSettings::Free:
      {
        // still a point placement (for "free" it's a fallback, there is no SLD equivalent)
        QDomElement pointPlacement = doc.createElement( "se:PointPlacement" );
        labelPlacement.appendChild( pointPlacement );
        QgsSymbolLayerUtils::createAnchorPointElement( doc, pointPlacement, QPointF( 0.5, 0.5 ) );
        QgsUnitTypes::RenderUnit distUnit = settings.distUnits;
        double dist = QgsSymbolLayerUtils::rescaleUom( settings.dist, distUnit, props );
        QgsSymbolLayerUtils::createDisplacementElement( doc, pointPlacement, QPointF( 0, dist ) );
        break;
      }
      case QgsPalLayerSettings::Line:
      case QgsPalLayerSettings::Curved:
      case QgsPalLayerSettings::PerimeterCurved:
      {
        QDomElement linePlacement = doc.createElement( "se:LinePlacement" );
        labelPlacement.appendChild( linePlacement );
  
        // perpendicular distance if required
        if ( settings.dist > 0 )
        {
          QgsUnitTypes::RenderUnit distUnit = settings.distUnits;
          double dist = QgsSymbolLayerUtils::rescaleUom( settings.dist, distUnit, props );
          QDomElement perpendicular = doc.createElement( "se:PerpendicularOffset" );
          linePlacement.appendChild( perpendicular );
          perpendicular.appendChild( doc.createTextNode( qgsDoubleToString( dist, 2 ) ) );
        }
  
        // repeat distance if required
        if ( settings.repeatDistance > 0 )
        {
          QDomElement repeat = doc.createElement( "se:Repeat" );
          linePlacement.appendChild( repeat );
          repeat.appendChild( doc.createTextNode( QStringLiteral( "true" ) ) );
          QDomElement gap = doc.createElement( "se:Gap" );
          linePlacement.appendChild( gap );
          repeatDistance = QgsSymbolLayerUtils::rescaleUom( settings.repeatDistance, settings.repeatDistanceUnit, props );
          gap.appendChild( doc.createTextNode( qgsDoubleToString( repeatDistance, 2 ) ) );
        }
  
        // always generalized
        QDomElement generalize = doc.createElement( "se:GeneralizeLine" );
        linePlacement.appendChild( generalize );
        generalize.appendChild( doc.createTextNode( QStringLiteral( "true" ) ) );
      }
      break;
    }
  
    // halo
    QgsTextBufferSettings buffer = format.buffer();
    if ( buffer.enabled() )
    {
      QDomElement haloElement = doc.createElement( QStringLiteral( "se:Halo" ) );
      textSymbolizerElement.appendChild( haloElement );
  
      QDomElement radiusElement = doc.createElement( QStringLiteral( "se:Radius" ) );
      haloElement.appendChild( radiusElement );
      // the SLD uses a radius, which is actually half of the link thickness the buffer size specifies
      double radius = QgsSymbolLayerUtils::rescaleUom( buffer.size(), buffer.sizeUnit(), props ) / 2;
      radiusElement.appendChild( doc.createTextNode( qgsDoubleToString( radius ) ) );
  
      QDomElement fillElement = doc.createElement( QStringLiteral( "se:Fill" ) );
      haloElement.appendChild( fillElement );
      fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill" ), buffer.color().name() ) );
      if ( buffer.opacity() != 1 )
      {
        fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill-opacity" ), QString::number( buffer.opacity() ) ) );
      }
    }
  
    // fill
    QDomElement fillElement = doc.createElement( QStringLiteral( "se:Fill" ) );
    textSymbolizerElement.appendChild( fillElement );
    fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill" ), format.color().name() ) );
    if ( format.opacity() != 1 )
    {
      fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill-opacity" ), QString::number( format.opacity() ) ) );
    }
  
    // background graphic (not supported by SE 1.1, but supported by the GeoTools ecosystem as an extension)
    QgsTextBackgroundSettings background = format.background();
    if ( background.enabled() )
    {
      std::unique_ptr<QgsMarkerSymbolLayer> layer = backgroundToMarkerLayer( background );
      layer->writeSldMarker( doc, textSymbolizerElement, props );
    }
  
    // priority and zIndex, the default values are 0 and 5 in qgis (and between 0 and 10),
    // in the GeoTools ecosystem there is a single priority value set at 1000 by default
    if ( settings.priority != 5 || settings.zIndex > 0 )
    {
      QDomElement priorityElement = doc.createElement( QStringLiteral( "se:Priority" ) );
      textSymbolizerElement.appendChild( priorityElement );
      int priority = 500 + 1000 * settings.zIndex + ( settings.priority - 5 ) * 100;
      if ( settings.priority == 0 && settings.zIndex > 0 )
      {
        // small adjustment to make sure labels in z index n+1 are all above level n despite the priority value
        priority += 1;
      }
      priorityElement.appendChild( doc.createTextNode( QString::number( priority ) ) );
    }
  
    // vendor options for text appearance
    if ( font.underline() )
    {
      QDomElement vo = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "underlineText" ), QStringLiteral( "true" ) );
      textSymbolizerElement.appendChild( vo );
    }
    if ( font.strikeOut() )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "strikethroughText" ), QStringLiteral( "true" ) );
      textSymbolizerElement.appendChild( vo );
    }
    // vendor options for text positioning
    if ( maxDisplacement > 0 )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "maxDisplacement" ), qgsDoubleToString( maxDisplacement, 2 ) );
      textSymbolizerElement.appendChild( vo );
    }
    if ( settings.placement == QgsPalLayerSettings::Curved || settings.placement == QgsPalLayerSettings::PerimeterCurved )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "followLine" ), QStringLiteral( "true" ) );
      textSymbolizerElement.appendChild( vo );
      if ( settings.maxCurvedCharAngleIn > 0 || settings.maxCurvedCharAngleOut > 0 )
      {
        // SLD has no notion for this, the GeoTools ecosystem can only do a single angle
        double angle = std::min( std::fabs( settings.maxCurvedCharAngleIn ), std::fabs( settings.maxCurvedCharAngleOut ) );
        QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "maxAngleDelta" ), qgsDoubleToString( angle ) );
        textSymbolizerElement.appendChild( vo );
      }
    }
    if ( repeatDistance > 0 )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "repeat" ), qgsDoubleToString( repeatDistance, 2 ) );
      textSymbolizerElement.appendChild( vo );
    }
    // miscellaneous options
    if ( settings.displayAll )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "conflictResolution" ), QStringLiteral( "false" ) );
      textSymbolizerElement.appendChild( vo );
    }
    if ( settings.upsidedownLabels == QgsPalLayerSettings::ShowAll )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "forceLeftToRight" ), QStringLiteral( "false" ) );
      textSymbolizerElement.appendChild( vo );
    }
    if ( settings.mergeLines )
    {
      QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "group" ), QStringLiteral( "yes" ) );
      textSymbolizerElement.appendChild( vo );
      if ( settings.labelPerPart )
      {
        QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "labelAllGroup" ), QStringLiteral( "true" ) );
        textSymbolizerElement.appendChild( vo );
      }
    }
    // background symbol resize handling
    if ( background.enabled() )
    {
      // enable resizing if needed
      switch ( background.sizeType() )
      {
        case QgsTextBackgroundSettings::SizeBuffer:
        {
          QString resizeType;
          if ( background.type() == QgsTextBackgroundSettings::ShapeRectangle || background.type() == QgsTextBackgroundSettings::ShapeEllipse )
          {
            resizeType = QStringLiteral( "stretch" );
          }
          else
          {
            resizeType = QStringLiteral( "proportional" );
          }
          QDomElement voResize =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "graphic-resize" ), resizeType );
          textSymbolizerElement.appendChild( voResize );
  
          // now hadle margin
          QSizeF size = background.size();
          if ( size.width() > 0 || size.height() > 0 )
          {
            double x = QgsSymbolLayerUtils::rescaleUom( size.width(), background.sizeUnit(), props );
            double y = QgsSymbolLayerUtils::rescaleUom( size.height(), background.sizeUnit(), props );
            // in case of ellipse qgis pads the size generously to make sure the text is inside the ellipse
            // the following seems to do the trick and keep visual output similar
            if ( background.type() == QgsTextBackgroundSettings::ShapeEllipse )
            {
              x += fontSize / 2;
              y += fontSize;
            }
            QString resizeSpec = QString( "%1 %2" ).arg( qgsDoubleToString( x, 2 ), qgsDoubleToString( y, 2 ) );
            QDomElement voMargin =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "graphic-margin" ), resizeSpec );
            textSymbolizerElement.appendChild( voMargin );
          }
          break;
        }
        case QgsTextBackgroundSettings::SizeFixed:
        case QgsTextBackgroundSettings::SizePercent:
          // nothing to do here
          break;
      }
    }
  }
  
  
  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 );
  
      // scale dependencies
      if ( mSettings->scaleVisibility )
      {
        QgsStringMap scaleProps = QgsStringMap();
        // tricky here, the max scale is expressed as its denominator, but it's still the max scale
        // in other words, the smallest scale denominator....
        scaleProps.insert( "scaleMinDenom", qgsDoubleToString( mSettings->maximumScale ) );
        scaleProps.insert( "scaleMaxDenom", qgsDoubleToString( mSettings->minimumScale ) );
        QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElement, scaleProps );
      }
  
      writeTextSymbolizer( ruleElement, *mSettings, props );
    }
  
  
  }
  
  void QgsVectorLayerSimpleLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId )
  {
    Q_UNUSED( providerId );
  
    if ( mSettings.get() == settings )
      return;
  
    mSettings.reset( settings );
  }
  