[FEATURE][AFS] Create labels when settings provied by server

This commit is contained in:
nirvn 2018-12-07 16:02:13 +07:00 committed by Mathieu Pellerin
parent cf0442dac6
commit 22a66ef390
9 changed files with 298 additions and 0 deletions

View File

@ -52,6 +52,7 @@ of feature and attribute information from a spatial datasource.
WriteLayerMetadata,
CancelSupport,
CreateRenderer,
CreateLabeling,
};
typedef QFlags<QgsVectorDataProvider::Capability> Capabilities;
@ -518,6 +519,23 @@ Only providers which report the CreateRenderer capability will return a feature
providers will return None.
.. versionadded:: 3.2
%End
virtual QgsAbstractVectorLayerLabeling *createLabeling( const QVariantMap &configuration = QVariantMap() ) const /Factory/;
%Docstring
Creates labeling settings, using provider backend specific information.
The ``configuration`` map can be used to pass provider-specific configuration maps to the provider to
allow customization of the returned labeling object. Support and format of ``configuration`` varies by provider.
When called with an empty ``configuration`` map the provider's default labeling settings will be returned.
This method returns a new labeling settings and the caller takes ownership of the returned object.
Only providers which report the CreateLabeling capability will return labeling settings. Other
providers will return None.
.. versionadded:: 3.6
%End
static QVariant convertValue( QVariant::Type type, const QString &value );

View File

@ -699,6 +699,11 @@ QgsFeatureRenderer *QgsVectorDataProvider::createRenderer( const QVariantMap & )
return nullptr;
}
QgsAbstractVectorLayerLabeling *QgsVectorDataProvider::createLabeling( const QVariantMap & ) const
{
return nullptr;
}
void QgsVectorDataProvider::pushError( const QString &msg ) const
{
QgsDebugMsg( msg );

View File

@ -41,6 +41,7 @@ class QgsFeatureIterator;
class QgsTransaction;
class QgsFeedback;
class QgsFeatureRenderer;
class QgsAbstractVectorLayerLabeling;
#include "qgsfeaturerequest.h"
@ -93,6 +94,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
WriteLayerMetadata = 1 << 22, //!< Provider can write layer metadata to the data store. Since QGIS 3.0. See QgsDataProvider::writeLayerMetadata()
CancelSupport = 1 << 23, //!< Supports interruption of pending queries from a separated thread. Since QGIS 3.2
CreateRenderer = 1 << 24, //!< Provider can create feature renderers using backend-specific formatting information. Since QGIS 3.2. See QgsVectorDataProvider::createRenderer().
CreateLabeling = 1 << 25, //!< Provider can set labeling settings using backend-specific formatting information. Since QGIS 3.6. See QgsVectorDataProvider::createLabeling().
};
Q_DECLARE_FLAGS( Capabilities, Capability )
@ -520,6 +522,23 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
*/
virtual QgsFeatureRenderer *createRenderer( const QVariantMap &configuration = QVariantMap() ) const SIP_FACTORY;
/**
* Creates labeling settings, using provider backend specific information.
*
* The \a configuration map can be used to pass provider-specific configuration maps to the provider to
* allow customization of the returned labeling object. Support and format of \a configuration varies by provider.
*
* When called with an empty \a configuration map the provider's default labeling settings will be returned.
*
* This method returns a new labeling settings and the caller takes ownership of the returned object.
*
* Only providers which report the CreateLabeling capability will return labeling settings. Other
* providers will return nullptr.
*
* \since QGIS 3.6
*/
virtual QgsAbstractVectorLayerLabeling *createLabeling( const QVariantMap &configuration = QVariantMap() ) const SIP_FACTORY;
static QVariant convertValue( QVariant::Type type, const QString &value );
/**

View File

@ -1531,6 +1531,16 @@ void QgsVectorLayer::setDataSource( const QString &dataSource, const QString &ba
}
setLegend( QgsMapLayerLegend::defaultVectorLegend( this ) );
if ( mDataProvider->capabilities() & QgsVectorDataProvider::CreateLabeling )
{
std::unique_ptr< QgsAbstractVectorLayerLabeling > defaultLabeling( mDataProvider->createLabeling() );
if ( defaultLabeling )
{
setLabeling( defaultLabeling.release() );
setLabelsEnabled( true );
}
}
}
emit dataSourceChanged();

View File

@ -222,6 +222,7 @@ QgsAfsProvider::QgsAfsProvider( const QString &uri, const ProviderOptions &optio
// renderer
mRendererDataMap = layerData.value( QStringLiteral( "drawingInfo" ) ).toMap().value( QStringLiteral( "renderer" ) ).toMap();
mLabelingDataList = layerData.value( QStringLiteral( "drawingInfo" ) ).toMap().value( QStringLiteral( "labelingInfo" ) ).toList();
mValid = true;
}
@ -263,6 +264,10 @@ QgsVectorDataProvider::Capabilities QgsAfsProvider::capabilities() const
{
c = c | QgsVectorDataProvider::CreateRenderer;
}
if ( !mLabelingDataList.empty() )
{
c = c | QgsVectorDataProvider::CreateLabeling;
}
return c;
}
@ -307,6 +312,10 @@ QgsFeatureRenderer *QgsAfsProvider::createRenderer( const QVariantMap & ) const
return QgsArcGisRestUtils::parseEsriRenderer( mRendererDataMap );
}
QgsAbstractVectorLayerLabeling *QgsAfsProvider::createLabeling( const QVariantMap & ) const
{
return QgsArcGisRestUtils::parseEsriLabeling( mLabelingDataList );
}
#ifdef HAVE_GUI

View File

@ -71,6 +71,7 @@ class QgsAfsProvider : public QgsVectorDataProvider
QString dataComment() const override;
void reloadData() override;
QgsFeatureRenderer *createRenderer( const QVariantMap &configuration = QVariantMap() ) const override;
QgsAbstractVectorLayerLabeling *createLabeling( const QVariantMap &configuration = QVariantMap() ) const override;
private:
bool mValid = false;
@ -80,6 +81,7 @@ class QgsAfsProvider : public QgsVectorDataProvider
QString mLayerDescription;
QgsLayerMetadata mLayerMetadata;
QVariantMap mRendererDataMap;
QVariantList mLabelingDataList;
};
#endif // QGSAFSPROVIDER_H

View File

@ -28,6 +28,7 @@
#include "geometry/qgspolygon.h"
#include "geometry/qgspoint.h"
#include "qgsfeedback.h"
#include "qgspallabeling.h"
#include "qgssymbol.h"
#include "qgssymbollayer.h"
#include "qgsauthmanager.h"
@ -36,8 +37,11 @@
#include "qgsfillsymbollayer.h"
#include "qgsmarkersymbollayer.h"
#include "qgsrenderer.h"
#include "qgsrulebasedlabeling.h"
#include "qgssinglesymbolrenderer.h"
#include "qgscategorizedsymbolrenderer.h"
#include "qgsvectorlayerlabeling.h"
#include <QEventLoop>
#include <QNetworkRequest>
#include <QNetworkReply>
@ -765,6 +769,132 @@ std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriPictureMarkerSymbo
return symbol;
}
QgsAbstractVectorLayerLabeling *QgsArcGisRestUtils::parseEsriLabeling( const QVariantList &labelingData )
{
if ( labelingData.empty() )
return nullptr;
QgsRuleBasedLabeling::Rule *root = new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings(), 0, 0, QString(), QString(), false );
root->setActive( true );
int i = 1;
for ( const QVariant &lbl : labelingData )
{
const QVariantMap labeling = lbl.toMap();
QgsPalLayerSettings *settings = new QgsPalLayerSettings();
QgsTextFormat format;
const QString placement = labeling.value( QStringLiteral( "labelPlacement" ) ).toString();
if ( placement == QLatin1String( "esriServerPointLabelPlacementAboveCenter" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantAbove;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementBelowCenter" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantBelow;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementCenterCenter" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantOver;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementAboveLeft" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantAboveLeft;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementBelowLeft" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantBelowLeft;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementCenterLeft" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantLeft;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementAboveRight" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantAboveRight;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementBelowRight" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantBelowRight;
}
else if ( placement == QLatin1String( "esriServerPointLabelPlacementCenterRight" ) )
{
settings->placement = QgsPalLayerSettings::OverPoint;
settings->quadOffset = QgsPalLayerSettings::QuadrantRight;
}
else if ( placement == QLatin1String( "esriServerLinePlacementAboveAfter" ) ||
placement == QLatin1String( "esriServerLinePlacementAboveStart" ) ||
placement == QLatin1String( "esriServerLinePlacementAboveAlong" ) )
{
settings->placement = QgsPalLayerSettings::Line;
settings->placementFlags = QgsPalLayerSettings::AboveLine | QgsPalLayerSettings::MapOrientation;
}
else if ( placement == QLatin1String( "esriServerLinePlacementBelowAfter" ) ||
placement == QLatin1String( "esriServerLinePlacementBelowStart" ) ||
placement == QLatin1String( "esriServerLinePlacementBelowAlong" ) )
{
settings->placement = QgsPalLayerSettings::Line;
settings->placementFlags = QgsPalLayerSettings::BelowLine | QgsPalLayerSettings::MapOrientation;
}
else if ( placement == QLatin1String( "esriServerLinePlacementCenterAfter" ) ||
placement == QLatin1String( "esriServerLinePlacementCenterStart" ) ||
placement == QLatin1String( "esriServerLinePlacementCenterAlong" ) )
{
settings->placement = QgsPalLayerSettings::Line;
settings->placementFlags = QgsPalLayerSettings::OnLine | QgsPalLayerSettings::MapOrientation;
}
else if ( placement == QLatin1String( "esriServerPolygonPlacementAlwaysHorizontal" ) )
{
settings->placement = QgsPalLayerSettings::Horizontal;
}
const double minScale = labeling.value( QStringLiteral( "minScale" ) ).toDouble();
const double maxScale = labeling.value( QStringLiteral( "maxScale" ) ).toDouble();
QVariantMap symbol = labeling.value( QStringLiteral( "symbol" ) ).toMap();
format.setColor( parseEsriColorJson( symbol.value( QStringLiteral( "color" ) ) ) );
const QString fontFamily = symbol.value( QStringLiteral( "font" ) ).toMap().value( QStringLiteral( "family" ) ).toString();
const QString fontStyle = symbol.value( QStringLiteral( "font" ) ).toMap().value( QStringLiteral( "style" ) ).toString();
const QString fontWeight = symbol.value( QStringLiteral( "font" ) ).toMap().value( QStringLiteral( "weight" ) ).toString();
const int fontSize = symbol.value( QStringLiteral( "font" ) ).toMap().value( QStringLiteral( "size" ) ).toInt();
QFont font( fontFamily, fontSize );
font.setStyleName( fontStyle );
font.setWeight( fontWeight == QLatin1String( "bold" ) ? QFont::Bold : QFont::Normal );
format.setFont( font );
format.setSize( fontSize );
format.setSizeUnit( QgsUnitTypes::RenderPoints );
settings->setFormat( format );
QString where = labeling.value( QStringLiteral( "where" ) ).toString();
QgsExpression exp( where );
// If the where clause isn't parsed as valid, don't use its
if ( !exp.isValid() )
where.clear();
QString expression = labeling.value( QStringLiteral( "labelExpression" ) ).toString();
settings->fieldName = expression.replace( '[', '"' ).replace( ']', '"' );
settings->isExpression = true;
QgsRuleBasedLabeling::Rule *child = new QgsRuleBasedLabeling::Rule( settings, maxScale, minScale, where, QObject::tr( "ASF label %1" ).arg( i++ ), false );
child->setActive( true );
root->appendChild( child );
}
return new QgsRuleBasedLabeling( root );
}
QgsFeatureRenderer *QgsArcGisRestUtils::parseEsriRenderer( const QVariantMap &rendererData )
{
const QString type = rendererData.value( QStringLiteral( "type" ) ).toString();

View File

@ -24,6 +24,7 @@ class QNetworkReply;
class QgsNetworkAccessManager;
class QgsFields;
class QgsAbstractGeometry;
class QgsAbstractVectorLayerLabeling;
class QgsCoordinateReferenceSystem;
class QgsFeedback;
class QgsSymbol;
@ -58,6 +59,7 @@ class QgsArcGisRestUtils
static std::unique_ptr< QgsMarkerSymbol > parseEsriMarkerSymbolJson( const QVariantMap &symbolData );
static std::unique_ptr< QgsMarkerSymbol > parseEsriPictureMarkerSymbolJson( const QVariantMap &symbolData );
static QgsFeatureRenderer *parseEsriRenderer( const QVariantMap &rendererData );
static QgsAbstractVectorLayerLabeling *parseEsriLabeling( const QVariantList &labelingData );
static QColor parseEsriColorJson( const QVariant &colorData );
static Qt::PenStyle parseEsriLineStyle( const QString &style );

View File

@ -23,6 +23,7 @@
#include "qgslinesymbollayer.h"
#include "qgsfillsymbollayer.h"
#include "qgsmarkersymbollayer.h"
#include "qgsrulebasedlabeling.h"
#include "qgssinglesymbolrenderer.h"
#include "qgscategorizedsymbolrenderer.h"
#include <QObject>
@ -49,6 +50,7 @@ class TestQgsArcGisRestUtils : public QObject
void testParsePictureFillSymbol();
void testParseRendererSimple();
void testParseRendererCategorized();
void testParseLabeling();
private:
@ -454,6 +456,107 @@ void TestQgsArcGisRestUtils::testParseRendererCategorized()
QVERIFY( catRenderer->categories().at( 1 ).symbol() );
}
void TestQgsArcGisRestUtils::testParseLabeling()
{
QVariantMap map = jsonStringToMap( "{"
"\"labelingInfo\": ["
"{"
"\"labelPlacement\": \"esriServerPointLabelPlacementAboveRight\","
"\"where\": \"1=1\","
"\"labelExpression\": \"[Name]\","
"\"useCodedValues\": true,"
"\"symbol\": {"
"\"type\": \"esriTS\","
"\"color\": ["
"255,"
"0,"
"0,"
"255"
"],"
"\"backgroundColor\": null,"
"\"borderLineColor\": null,"
"\"borderLineSize\": null,"
"\"verticalAlignment\": \"bottom\","
"\"horizontalAlignment\": \"center\","
"\"rightToLeft\": false,"
"\"angle\": 0,"
"\"xoffset\": 0,"
"\"yoffset\": 0,"
"\"haloColor\": null,"
"\"haloSize\": null,"
"\"font\": {"
"\"family\": \"Arial\","
"\"size\": 8,"
"\"style\": \"normal\","
"\"weight\": \"bold\","
"\"decoration\": \"none\""
"}"
"},"
"\"minScale\": 200000,"
"\"maxScale\": 0"
"},{"
"\"labelPlacement\": \"esriServerPointLabelPlacementAboveRight\","
"\"where\": \"1_testing broken where string\","
"\"labelExpression\": \"[Name]\","
"\"useCodedValues\": true,"
"\"symbol\": {"
"\"type\": \"esriTS\","
"\"color\": ["
"255,"
"0,"
"0,"
"255"
"],"
"\"backgroundColor\": null,"
"\"borderLineColor\": null,"
"\"borderLineSize\": null,"
"\"verticalAlignment\": \"bottom\","
"\"horizontalAlignment\": \"center\","
"\"rightToLeft\": false,"
"\"angle\": 0,"
"\"xoffset\": 0,"
"\"yoffset\": 0,"
"\"haloColor\": null,"
"\"haloSize\": null,"
"\"font\": {"
"\"family\": \"Arial\","
"\"size\": 8,"
"\"style\": \"normal\","
"\"weight\": \"bold\","
"\"decoration\": \"none\""
"}"
"},"
"\"minScale\": 200000,"
"\"maxScale\": 0"
"}"
"]"
"}" );
std::unique_ptr< QgsAbstractVectorLayerLabeling > labeling( QgsArcGisRestUtils::parseEsriLabeling( map.value( QStringLiteral( "labelingInfo" ) ).toList() ) );
QVERIFY( labeling );
QgsRuleBasedLabeling *rules = dynamic_cast< QgsRuleBasedLabeling *>( labeling.get() );
QVERIFY( rules );
QgsRuleBasedLabeling::Rule *root = rules->rootRule();
QVERIFY( root );
QgsRuleBasedLabeling::RuleList children = root->children();
QCOMPARE( children.count(), 2 );
//checking filter expression from valid where string
QCOMPARE( children.at( 0 )->filterExpression(), QStringLiteral( "1=1" ) );
//checking empty filter expression from invalid where string
QCOMPARE( children.at( 1 )->filterExpression(), QString( "" ) );
QCOMPARE( children.at( 0 )->minimumScale(), 200000.0 );
QCOMPARE( children.at( 0 )->maximumScale(), 0.0 );
QgsPalLayerSettings *settings = children.at( 0 )->settings();
QVERIFY( settings );
QCOMPARE( settings->placement, QgsPalLayerSettings::OverPoint );
QCOMPARE( settings->quadOffset, QgsPalLayerSettings::QuadrantAboveRight );
QgsTextFormat textFormat = settings->format();
QCOMPARE( textFormat.color(), QColor( 255, 0, 0 ) );
QCOMPARE( textFormat.size(), 8.0 );
}
QVariantMap TestQgsArcGisRestUtils::jsonStringToMap( const QString &string ) const
{
QJsonDocument doc = QJsonDocument::fromJson( string.toUtf8() );