Merge pull request #4313 from pblottiere/cleansingleton
[Server] WMS getmap refactoring
@ -460,6 +460,7 @@ Convenience function to query topological editing status
|
||||
:rtype: QgsAnnotationManager
|
||||
%End
|
||||
|
||||
|
||||
void setNonIdentifiableLayers( const QList<QgsMapLayer *> &layers );
|
||||
%Docstring
|
||||
Set a list of layers which should not be taken into account on map identification
|
||||
|
@ -84,11 +84,18 @@ class QgsServerProjectParser
|
||||
|
||||
/** Returns the text of the <layername> element for a layer element
|
||||
@return name or a null string in case of error*/
|
||||
QString layerName( const QDomElement &layerElem ) const;
|
||||
// QString layerName( const QDomElement &layerElem ) const;
|
||||
|
||||
QStringList wfsLayers() const;
|
||||
QStringList wcsLayers() const;
|
||||
|
||||
/** Gets a list containing names of layers. If a layer has a short name,
|
||||
* then it's used instead of it's name.
|
||||
* \returns A list of layers' names or short name if defined
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QStringList layersNames() const;
|
||||
|
||||
//! Add layers for vector joins
|
||||
void addJoinLayersForElement( const QDomElement &layerElem ) const;
|
||||
|
||||
@ -101,10 +108,6 @@ class QgsServerProjectParser
|
||||
@return id or a null string in case of error*/
|
||||
QString layerId( const QDomElement &layerElem ) const;
|
||||
|
||||
/** Returns the text of the <id> element for a layer element
|
||||
@return id or a null string in case of error*/
|
||||
QString layerShortName( const QDomElement &layerElem ) const;
|
||||
|
||||
QgsRectangle projectExtent() const;
|
||||
|
||||
int numberOfLayers() const;
|
||||
|
@ -1980,6 +1980,11 @@ QgsAnnotationManager *QgsProject::annotationManager()
|
||||
return mAnnotationManager.get();
|
||||
}
|
||||
|
||||
const QgsAnnotationManager *QgsProject::annotationManager() const
|
||||
{
|
||||
return mAnnotationManager.get();
|
||||
}
|
||||
|
||||
void QgsProject::setNonIdentifiableLayers( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
QStringList currentLayers = nonIdentifiableLayers();
|
||||
|
@ -419,6 +419,12 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
|
||||
*/
|
||||
QgsAnnotationManager *annotationManager();
|
||||
|
||||
/**
|
||||
* Returns a const pointer to the project's annotation manager.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
const QgsAnnotationManager *annotationManager() const SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Set a list of layers which should not be taken into account on map identification
|
||||
*/
|
||||
|
@ -40,6 +40,20 @@ QgsConfigCache::QgsConfigCache()
|
||||
QObject::connect( &mFileSystemWatcher, &QFileSystemWatcher::fileChanged, this, &QgsConfigCache::removeChangedEntry );
|
||||
}
|
||||
|
||||
const QgsProject *QgsConfigCache::project( const QString &path )
|
||||
{
|
||||
if ( ! mProjectCache[ path ] )
|
||||
{
|
||||
std::unique_ptr<QgsProject> prj( new QgsProject() );
|
||||
if ( prj->read( path ) )
|
||||
{
|
||||
mProjectCache.insert( path, prj.release() );
|
||||
}
|
||||
}
|
||||
|
||||
return mProjectCache[ path ];
|
||||
}
|
||||
|
||||
QgsServerProjectParser *QgsConfigCache::serverConfiguration( const QString &filePath )
|
||||
{
|
||||
QgsMessageLog::logMessage(
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
class QgsServerProjectParser;
|
||||
class QgsAccessControl;
|
||||
class QgsProject;
|
||||
|
||||
class SERVER_EXPORT QgsConfigCache : public QObject
|
||||
{
|
||||
@ -47,6 +48,14 @@ class SERVER_EXPORT QgsConfigCache : public QObject
|
||||
|
||||
void removeEntry( const QString &path );
|
||||
|
||||
/** If the project is not cached yet, then the project is read thank to the
|
||||
* path. If the project is not available, then a nullptr is returned.
|
||||
* \param path the filename of the QGIS project
|
||||
* \returns the project or nullptr if an error happened
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
const QgsProject *project( const QString &path );
|
||||
|
||||
private:
|
||||
QgsConfigCache();
|
||||
|
||||
@ -58,6 +67,7 @@ class SERVER_EXPORT QgsConfigCache : public QObject
|
||||
|
||||
QCache<QString, QDomDocument> mXmlDocumentCache;
|
||||
QCache<QString, QgsWmsConfigParser> mWMSConfigCache;
|
||||
QCache<QString, QgsProject> mProjectCache;
|
||||
|
||||
private slots:
|
||||
//! Removes changed entry from this cache
|
||||
|
@ -40,8 +40,32 @@ void QgsOWSServerFilterRestorer::applyAccessControlLayerFilters( const QgsAccess
|
||||
}
|
||||
if ( !layer->subsetString().isEmpty() )
|
||||
{
|
||||
sql.prepend( " AND " );
|
||||
sql.prepend( ") AND (" );
|
||||
sql.append( ")" );
|
||||
sql.prepend( layer->subsetString() );
|
||||
sql.prepend( "(" );
|
||||
}
|
||||
if ( !layer->setSubsetString( sql ) )
|
||||
{
|
||||
QgsMessageLog::logMessage( QStringLiteral( "Layer does not support Subset String" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsOWSServerFilterRestorer::applyAccessControlLayerFilters( const QgsAccessControl *accessControl, QgsMapLayer *mapLayer )
|
||||
{
|
||||
if ( QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mapLayer ) )
|
||||
{
|
||||
QString sql = accessControl->extraSubsetString( layer );
|
||||
if ( !sql.isEmpty() )
|
||||
{
|
||||
if ( !layer->subsetString().isEmpty() )
|
||||
{
|
||||
sql.prepend( ") AND (" );
|
||||
sql.append( ")" );
|
||||
sql.prepend( layer->subsetString() );
|
||||
sql.prepend( "(" );
|
||||
}
|
||||
if ( !layer->setSubsetString( sql ) )
|
||||
{
|
||||
|
@ -53,6 +53,13 @@ class SERVER_EXPORT QgsOWSServerFilterRestorer
|
||||
static void applyAccessControlLayerFilters( const QgsAccessControl *accessControl, QgsMapLayer *mapLayer,
|
||||
QHash<QgsMapLayer *, QString> &originalLayerFilters );
|
||||
|
||||
/** Applies filters from access control on layer.
|
||||
* \param accessControl The access control instance
|
||||
* \param mapLayer The layer on which the filter has to be applied
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
static void applyAccessControlLayerFilters( const QgsAccessControl *accessControl, QgsMapLayer *mapLayer );
|
||||
|
||||
private:
|
||||
const QgsAccessControl *mAccessControl = nullptr;
|
||||
QHash<QgsMapLayer *, QString> mOriginalLayerFilters;
|
||||
|
@ -76,6 +76,7 @@ QgsServer::QgsServer( )
|
||||
abort();
|
||||
}
|
||||
init();
|
||||
mConfigCache = QgsConfigCache::instance();
|
||||
}
|
||||
|
||||
QString &QgsServer::serverName()
|
||||
@ -353,20 +354,10 @@ void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &res
|
||||
QString configFilePath = configPath( *sConfigFilePath, parameterMap );
|
||||
|
||||
// load the project if needed and not empty
|
||||
auto projectIt = mProjectRegistry.find( configFilePath );
|
||||
if ( projectIt == mProjectRegistry.constEnd() )
|
||||
const QgsProject *project = mConfigCache->project( configFilePath );
|
||||
if ( ! project )
|
||||
{
|
||||
// load the project
|
||||
QgsProject *project = new QgsProject();
|
||||
project->setFileName( configFilePath );
|
||||
if ( project->read() )
|
||||
{
|
||||
projectIt = mProjectRegistry.insert( configFilePath, project );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw QgsServerException( QStringLiteral( "Project file error" ) );
|
||||
}
|
||||
throw QgsServerException( QStringLiteral( "Project file error" ) );
|
||||
}
|
||||
|
||||
sServerInterface->setConfigFilePath( configFilePath );
|
||||
@ -397,7 +388,7 @@ void QgsServer::handleRequest( QgsServerRequest &request, QgsServerResponse &res
|
||||
QgsService *service = sServiceRegistry.getService( serviceString, versionString );
|
||||
if ( service )
|
||||
{
|
||||
service->executeRequest( request, responseDecorator, projectIt.value() );
|
||||
service->executeRequest( request, responseDecorator, project );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -124,8 +124,8 @@ class SERVER_EXPORT QgsServer
|
||||
|
||||
static QgsServerSettings sSettings;
|
||||
|
||||
// map of QgsProject
|
||||
QMap<QString, const QgsProject *> mProjectRegistry;
|
||||
//! cache
|
||||
QgsConfigCache *mConfigCache;
|
||||
};
|
||||
#endif // QGSSERVER_H
|
||||
|
||||
|
@ -29,10 +29,13 @@
|
||||
#include "qgsvectorlayerjoinbuffer.h"
|
||||
#include "qgseditorwidgetregistry.h"
|
||||
#include "qgslayertreegroup.h"
|
||||
#include "qgslayertreelayer.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgseditorwidgetsetup.h"
|
||||
#include "qgsgui.h"
|
||||
#include "qgsexpressionnodeimpl.h"
|
||||
#include "qgsserverprojectutils.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
#include <QFileInfo>
|
||||
@ -42,32 +45,35 @@
|
||||
|
||||
QgsServerProjectParser::QgsServerProjectParser( QDomDocument *xmlDoc, const QString &filePath )
|
||||
: mXMLDoc( xmlDoc )
|
||||
, mProject( QgsConfigCache::instance()->project( filePath ) )
|
||||
, mProjectPath( filePath )
|
||||
, mUseLayerIDs( false )
|
||||
{
|
||||
QMap<QString, QgsMapLayer *> layers = mProject->mapLayers();
|
||||
mProjectLayerElements.reserve( layers.size() );
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
QDomDocument doc;
|
||||
QDomElement el = doc.createElement( "maplayer" );
|
||||
layer->writeLayerXml( el, doc, QgsReadWriteContext() );
|
||||
mProjectLayerElements.push_back( el );
|
||||
|
||||
QString name = layer->shortName();
|
||||
if ( name.isEmpty() )
|
||||
{
|
||||
name = layer->name();
|
||||
}
|
||||
|
||||
mProjectLayerElementsByName.insert( name, el );
|
||||
mProjectLayerElementsById.insert( layer->id(), el );
|
||||
}
|
||||
|
||||
mRestrictedLayers = findRestrictedLayers();
|
||||
|
||||
//accelerate the search for layers, groups and the creation of annotation items
|
||||
if ( mXMLDoc )
|
||||
{
|
||||
QDomNodeList layerNodeList = mXMLDoc->elementsByTagName( QStringLiteral( "maplayer" ) );
|
||||
QDomElement currentElement;
|
||||
int nNodes = layerNodeList.size();
|
||||
mProjectLayerElements.reserve( nNodes );
|
||||
for ( int i = 0; i < nNodes; ++i )
|
||||
{
|
||||
currentElement = layerNodeList.at( i ).toElement();
|
||||
mProjectLayerElements.push_back( currentElement );
|
||||
QString lName = layerShortName( currentElement );
|
||||
if ( lName.isEmpty() )
|
||||
lName = layerName( currentElement );
|
||||
mProjectLayerElementsByName.insert( lName, currentElement );
|
||||
mProjectLayerElementsById.insert( layerId( currentElement ), currentElement );
|
||||
}
|
||||
|
||||
mLegendGroupElements = findLegendGroupElements();
|
||||
|
||||
mUseLayerIDs = findUseLayerIds();
|
||||
mRestrictedLayers = findRestrictedLayers();
|
||||
|
||||
mCustomLayerOrder.clear();
|
||||
|
||||
QDomElement customOrder = mXMLDoc->documentElement().firstChildElement( QStringLiteral( "layer-tree-canvas" ) ).firstChildElement( QStringLiteral( "custom-order" ) );
|
||||
@ -88,9 +94,31 @@ QgsServerProjectParser::QgsServerProjectParser( QDomDocument *xmlDoc, const QStr
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsServerProjectParser::useLayerIds() const
|
||||
{
|
||||
return QgsServerProjectUtils::wmsUseLayerIds( *mProject );
|
||||
}
|
||||
|
||||
QStringList QgsServerProjectParser::layersNames() const
|
||||
{
|
||||
QStringList names;
|
||||
Q_FOREACH ( QgsMapLayer *layer, mProject->mapLayers() )
|
||||
{
|
||||
if ( ! layer->shortName().isEmpty() )
|
||||
{
|
||||
names.append( layer->shortName() );
|
||||
}
|
||||
else
|
||||
{
|
||||
names.append( layer->name() );
|
||||
}
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
QgsServerProjectParser::QgsServerProjectParser()
|
||||
: mXMLDoc( nullptr )
|
||||
, mUseLayerIDs( false )
|
||||
{
|
||||
}
|
||||
|
||||
@ -349,21 +377,6 @@ QString QgsServerProjectParser::layerId( const QDomElement &layerElem ) const
|
||||
return idElem.text();
|
||||
}
|
||||
|
||||
QString QgsServerProjectParser::layerShortName( const QDomElement &layerElem ) const
|
||||
{
|
||||
if ( layerElem.isNull() )
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QDomElement nameElem = layerElem.firstChildElement( QStringLiteral( "shortname" ) );
|
||||
if ( nameElem.isNull() )
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
return nameElem.text().replace( QLatin1String( "," ), QLatin1String( "%60" ) );
|
||||
}
|
||||
|
||||
QgsRectangle QgsServerProjectParser::projectExtent() const
|
||||
{
|
||||
QgsRectangle extent;
|
||||
@ -637,21 +650,6 @@ void QgsServerProjectParser::serviceCapabilities( QDomElement &parentElement, QD
|
||||
parentElement.appendChild( serviceElem );
|
||||
}
|
||||
|
||||
QString QgsServerProjectParser::layerName( const QDomElement &layerElem ) const
|
||||
{
|
||||
if ( layerElem.isNull() )
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QDomElement nameElem = layerElem.firstChildElement( QStringLiteral( "layername" ) );
|
||||
if ( nameElem.isNull() )
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
return nameElem.text().replace( QLatin1String( "," ), QLatin1String( "%60" ) ); //commas are not allowed in layer names
|
||||
}
|
||||
|
||||
void QgsServerProjectParser::combineExtentAndCrsOfGroupChildren( QDomElement &groupElem, QDomDocument &doc, bool considerMapExtent ) const
|
||||
{
|
||||
QgsRectangle combinedBBox;
|
||||
@ -1048,130 +1046,54 @@ QDomElement QgsServerProjectParser::propertiesElem() const
|
||||
|
||||
QSet<QString> QgsServerProjectParser::findRestrictedLayers() const
|
||||
{
|
||||
QSet<QString> restrictedLayerSet;
|
||||
// get name of restricted layers/groups in project
|
||||
QStringList restricted = QgsServerProjectUtils::wmsRestrictedLayers( *mProject );
|
||||
|
||||
if ( !mXMLDoc )
|
||||
// extract restricted layers from excluded groups
|
||||
QStringList restrictedLayersNames;
|
||||
QgsLayerTree *root = mProject->layerTreeRoot();
|
||||
|
||||
Q_FOREACH ( QString l, restricted )
|
||||
{
|
||||
return restrictedLayerSet;
|
||||
QgsLayerTreeGroup *group = root->findGroup( l );
|
||||
if ( group )
|
||||
{
|
||||
QList<QgsLayerTreeLayer *> groupLayers = group->findLayers();
|
||||
Q_FOREACH ( QgsLayerTreeLayer *treeLayer, groupLayers )
|
||||
{
|
||||
restrictedLayersNames.append( treeLayer->name() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
restrictedLayersNames.append( l );
|
||||
}
|
||||
}
|
||||
|
||||
//names of unpublished layers / groups
|
||||
QDomElement propertiesElem = mXMLDoc->documentElement().firstChildElement( QStringLiteral( "properties" ) );
|
||||
if ( !propertiesElem.isNull() )
|
||||
// build output with names, ids or short name according to the configuration
|
||||
QSet<QString> restrictedLayers;
|
||||
QList<QgsLayerTreeLayer *> layers = root->findLayers();
|
||||
Q_FOREACH ( QgsLayerTreeLayer *layer, layers )
|
||||
{
|
||||
QDomElement wmsLayerRestrictionElem = propertiesElem.firstChildElement( QStringLiteral( "WMSRestrictedLayers" ) );
|
||||
if ( !wmsLayerRestrictionElem.isNull() )
|
||||
if ( restrictedLayersNames.contains( layer->name() ) )
|
||||
{
|
||||
QStringList restrictedLayersAndGroups;
|
||||
QDomNodeList wmsLayerRestrictionValues = wmsLayerRestrictionElem.elementsByTagName( QStringLiteral( "value" ) );
|
||||
for ( int i = 0; i < wmsLayerRestrictionValues.size(); ++i )
|
||||
QString shortName = layer->layer()->shortName();
|
||||
if ( QgsServerProjectUtils::wmsUseLayerIds( *mProject ) )
|
||||
{
|
||||
restrictedLayerSet.insert( wmsLayerRestrictionValues.at( i ).toElement().text() );
|
||||
restrictedLayers.insert( layer->layerId() );
|
||||
}
|
||||
else if ( ! shortName.isEmpty() )
|
||||
{
|
||||
restrictedLayers.insert( shortName );
|
||||
}
|
||||
else
|
||||
{
|
||||
restrictedLayers.insert( layer->name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//get legend dom element
|
||||
if ( restrictedLayerSet.size() < 1 || !mXMLDoc )
|
||||
{
|
||||
return restrictedLayerSet;
|
||||
}
|
||||
|
||||
QDomElement legendElem = mXMLDoc->documentElement().firstChildElement( QStringLiteral( "legend" ) );
|
||||
if ( legendElem.isNull() )
|
||||
{
|
||||
return restrictedLayerSet;
|
||||
}
|
||||
|
||||
//go through all legend groups and insert names of subgroups / sublayers if there is a match
|
||||
QDomNodeList legendGroupList = legendElem.elementsByTagName( QStringLiteral( "legendgroup" ) );
|
||||
for ( int i = 0; i < legendGroupList.size(); ++i )
|
||||
{
|
||||
//get name
|
||||
QDomElement groupElem = legendGroupList.at( i ).toElement();
|
||||
QString groupName = groupElem.attribute( QStringLiteral( "name" ) );
|
||||
if ( restrictedLayerSet.contains( groupName ) ) //match: add names of subgroups and sublayers to set
|
||||
{
|
||||
//embedded group? -> also get names of subgroups and sublayers from embedded projects
|
||||
if ( groupElem.attribute( QStringLiteral( "embedded" ) ) == QLatin1String( "1" ) )
|
||||
{
|
||||
sublayersOfEmbeddedGroup( convertToAbsolutePath( groupElem.attribute( QStringLiteral( "project" ) ) ), groupName, restrictedLayerSet );
|
||||
}
|
||||
else //local group
|
||||
{
|
||||
QDomNodeList subgroupList = groupElem.elementsByTagName( QStringLiteral( "legendgroup" ) );
|
||||
for ( int j = 0; j < subgroupList.size(); ++j )
|
||||
{
|
||||
restrictedLayerSet.insert( subgroupList.at( j ).toElement().attribute( QStringLiteral( "name" ) ) );
|
||||
}
|
||||
QDomNodeList sublayerList = groupElem.elementsByTagName( QStringLiteral( "legendlayer" ) );
|
||||
for ( int k = 0; k < sublayerList.size(); ++k )
|
||||
{
|
||||
restrictedLayerSet.insert( sublayerList.at( k ).toElement().attribute( QStringLiteral( "name" ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// wmsLayerRestrictionValues contains LayerIDs
|
||||
if ( mUseLayerIDs )
|
||||
{
|
||||
QDomNodeList legendLayerList = legendElem.elementsByTagName( QStringLiteral( "legendlayer" ) );
|
||||
for ( int i = 0; i < legendLayerList.size(); ++i )
|
||||
{
|
||||
//get name
|
||||
QDomElement layerElem = legendLayerList.at( i ).toElement();
|
||||
QString layerName = layerElem.attribute( QStringLiteral( "name" ) );
|
||||
if ( restrictedLayerSet.contains( layerName ) ) //match: add layer id
|
||||
{
|
||||
// get legend layer file element
|
||||
QDomNodeList layerfileList = layerElem.elementsByTagName( QStringLiteral( "legendlayerfile" ) );
|
||||
if ( !layerfileList.isEmpty() )
|
||||
{
|
||||
// add layer id
|
||||
restrictedLayerSet.insert( layerfileList.at( 0 ).toElement().attribute( QStringLiteral( "layerid" ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add short name in restricted layers
|
||||
else
|
||||
{
|
||||
QDomNodeList layerNodeList = mXMLDoc->elementsByTagName( "maplayer" );
|
||||
for ( int i = 0; i < layerNodeList.size(); ++i )
|
||||
{
|
||||
QDomElement layerElem = layerNodeList.at( i ).toElement();
|
||||
// get name
|
||||
QString lName = layerName( layerElem );
|
||||
if ( restrictedLayerSet.contains( lName ) )
|
||||
{
|
||||
// get short name
|
||||
lName = layerShortName( layerElem );
|
||||
if ( !lName.isEmpty() )
|
||||
{
|
||||
// add short name
|
||||
restrictedLayerSet.insert( lName );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return restrictedLayerSet;
|
||||
}
|
||||
|
||||
bool QgsServerProjectParser::findUseLayerIds() const
|
||||
{
|
||||
if ( !mXMLDoc )
|
||||
return false;
|
||||
|
||||
QDomElement propertiesElem = mXMLDoc->documentElement().firstChildElement( QStringLiteral( "properties" ) );
|
||||
if ( propertiesElem.isNull() )
|
||||
return false;
|
||||
|
||||
QDomElement wktElem = propertiesElem.firstChildElement( QStringLiteral( "WMSUseLayerIDs" ) );
|
||||
if ( wktElem.isNull() )
|
||||
return false;
|
||||
|
||||
return wktElem.text().compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0;
|
||||
return restrictedLayers;
|
||||
}
|
||||
|
||||
void QgsServerProjectParser::layerFromLegendLayer( const QDomElement &legendLayerElem, QMap< int, QgsMapLayer *> &layers, bool useCache ) const
|
||||
@ -1304,6 +1226,11 @@ void QgsServerProjectParser::sublayersOfEmbeddedGroup( const QString &projectFil
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QgsServerProjectParser::wfsLayers() const
|
||||
{
|
||||
return QgsServerProjectUtils::wfsLayerIds( *mProject );
|
||||
}
|
||||
|
||||
QStringList QgsServerProjectParser::wfsLayerNames() const
|
||||
{
|
||||
QStringList layerNameList;
|
||||
@ -1312,7 +1239,7 @@ QStringList QgsServerProjectParser::wfsLayerNames() const
|
||||
projectLayerMap( layerMap );
|
||||
|
||||
QgsMapLayer *currentLayer = nullptr;
|
||||
QStringList wfsIdList = wfsLayers();
|
||||
QStringList wfsIdList = QgsServerProjectUtils::wfsLayerIds( *mProject );
|
||||
QStringList::const_iterator wfsIdIt = wfsIdList.constBegin();
|
||||
for ( ; wfsIdIt != wfsIdList.constEnd(); ++wfsIdIt )
|
||||
{
|
||||
@ -1322,7 +1249,8 @@ QStringList QgsServerProjectParser::wfsLayerNames() const
|
||||
currentLayer = layerMapIt.value();
|
||||
if ( currentLayer )
|
||||
{
|
||||
layerNameList.append( mUseLayerIDs ? currentLayer->id() : currentLayer->name() );
|
||||
bool useLayerIds = QgsServerProjectUtils::wmsUseLayerIds( *mProject );
|
||||
layerNameList.append( useLayerIds ? currentLayer->id() : currentLayer->name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1348,7 +1276,8 @@ QStringList QgsServerProjectParser::wcsLayerNames() const
|
||||
currentLayer = layerMapIt.value();
|
||||
if ( currentLayer )
|
||||
{
|
||||
layerNameList.append( mUseLayerIDs ? currentLayer->id() : currentLayer->name() );
|
||||
bool useLayerIds = QgsServerProjectUtils::wmsUseLayerIds( *mProject );
|
||||
layerNameList.append( useLayerIds ? currentLayer->id() : currentLayer->name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1454,66 +1383,9 @@ QList< QPair< QString, QgsDatumTransformStore::Entry > > QgsServerProjectParser:
|
||||
return layerTransformList;
|
||||
}
|
||||
|
||||
QStringList QgsServerProjectParser::wfsLayers() const
|
||||
{
|
||||
QStringList wfsList;
|
||||
if ( !mXMLDoc )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
|
||||
QDomElement qgisElem = mXMLDoc->documentElement();
|
||||
if ( qgisElem.isNull() )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
QDomElement propertiesElem = qgisElem.firstChildElement( QStringLiteral( "properties" ) );
|
||||
if ( propertiesElem.isNull() )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
QDomElement wfsLayersElem = propertiesElem.firstChildElement( QStringLiteral( "WFSLayers" ) );
|
||||
if ( wfsLayersElem.isNull() )
|
||||
{
|
||||
return wfsList;
|
||||
}
|
||||
QDomNodeList valueList = wfsLayersElem.elementsByTagName( QStringLiteral( "value" ) );
|
||||
for ( int i = 0; i < valueList.size(); ++i )
|
||||
{
|
||||
wfsList << valueList.at( i ).toElement().text();
|
||||
}
|
||||
return wfsList;
|
||||
}
|
||||
|
||||
QStringList QgsServerProjectParser::wcsLayers() const
|
||||
{
|
||||
QStringList wcsList;
|
||||
if ( !mXMLDoc )
|
||||
{
|
||||
return wcsList;
|
||||
}
|
||||
|
||||
QDomElement qgisElem = mXMLDoc->documentElement();
|
||||
if ( qgisElem.isNull() )
|
||||
{
|
||||
return wcsList;
|
||||
}
|
||||
QDomElement propertiesElem = qgisElem.firstChildElement( QStringLiteral( "properties" ) );
|
||||
if ( propertiesElem.isNull() )
|
||||
{
|
||||
return wcsList;
|
||||
}
|
||||
QDomElement wcsLayersElem = propertiesElem.firstChildElement( QStringLiteral( "WCSLayers" ) );
|
||||
if ( wcsLayersElem.isNull() )
|
||||
{
|
||||
return wcsList;
|
||||
}
|
||||
QDomNodeList valueList = wcsLayersElem.elementsByTagName( QStringLiteral( "value" ) );
|
||||
for ( int i = 0; i < valueList.size(); ++i )
|
||||
{
|
||||
wcsList << valueList.at( i ).toElement().text();
|
||||
}
|
||||
return wcsList;
|
||||
return QgsServerProjectUtils::wcsLayerIds( *mProject );
|
||||
}
|
||||
|
||||
void QgsServerProjectParser::addJoinLayersForElement( const QDomElement &layerElem ) const
|
||||
|
@ -85,7 +85,7 @@ class SERVER_EXPORT QgsServerProjectParser
|
||||
QDomElement propertiesElem() const;
|
||||
|
||||
QSet<QString> restrictedLayers() const { return mRestrictedLayers; }
|
||||
bool useLayerIds() const { return mUseLayerIDs; }
|
||||
bool useLayerIds() const;
|
||||
|
||||
QHash< QString, QDomElement > projectLayerElementsByName() const { return mProjectLayerElementsByName; }
|
||||
QHash< QString, QDomElement > projectLayerElementsById() const { return mProjectLayerElementsById; }
|
||||
@ -95,16 +95,19 @@ class SERVER_EXPORT QgsServerProjectParser
|
||||
QStringList wfsLayerNames() const;
|
||||
QStringList wcsLayerNames() const;
|
||||
|
||||
/** Gets a list containing names of layers. If a layer has a short name,
|
||||
* then it's used instead of it's name.
|
||||
* \returns A list of layers' names or short name if defined
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QStringList layersNames() const;
|
||||
|
||||
QDomElement firstComposerLegendElement() const;
|
||||
|
||||
QList<QDomElement> publishedComposerElements() const;
|
||||
|
||||
QList< QPair< QString, QgsDatumTransformStore::Entry > > layerCoordinateTransforms() const;
|
||||
|
||||
/** Returns the text of the <layername> element for a layer element
|
||||
\returns name or a null string in case of error*/
|
||||
QString layerName( const QDomElement &layerElem ) const;
|
||||
|
||||
QStringList wfsLayers() const;
|
||||
QStringList wcsLayers() const;
|
||||
|
||||
@ -119,10 +122,6 @@ class SERVER_EXPORT QgsServerProjectParser
|
||||
\returns id or a null string in case of error*/
|
||||
QString layerId( const QDomElement &layerElem ) const;
|
||||
|
||||
/** Returns the text of the <id> element for a layer element
|
||||
\returns id or a null string in case of error*/
|
||||
QString layerShortName( const QDomElement &layerElem ) const;
|
||||
|
||||
QgsRectangle projectExtent() const;
|
||||
|
||||
int numberOfLayers() const;
|
||||
@ -138,6 +137,9 @@ class SERVER_EXPORT QgsServerProjectParser
|
||||
//! Content of project file
|
||||
QDomDocument *mXMLDoc = nullptr;
|
||||
|
||||
//! Project
|
||||
const QgsProject *mProject = nullptr;
|
||||
|
||||
//! Absolute project file path (including file name)
|
||||
QString mProjectPath;
|
||||
|
||||
@ -156,8 +158,6 @@ class SERVER_EXPORT QgsServerProjectParser
|
||||
//! Names of layers and groups which should not be published
|
||||
QSet<QString> mRestrictedLayers;
|
||||
|
||||
bool mUseLayerIDs;
|
||||
|
||||
QgsServerProjectParser(); //forbidden
|
||||
|
||||
//! Returns a complete string set with all the restricted layer names (layers/groups that are not to be published)
|
||||
@ -165,8 +165,6 @@ class SERVER_EXPORT QgsServerProjectParser
|
||||
|
||||
QStringList mCustomLayerOrder;
|
||||
|
||||
bool findUseLayerIds() const;
|
||||
|
||||
QList<QDomElement> findLegendGroupElements() const;
|
||||
QList<QDomElement> setLegendGroupElementsWithLayerTree( QgsLayerTreeGroup *layerTreeGroup, const QDomElement &legendElement ) const;
|
||||
|
||||
|
@ -102,7 +102,7 @@ int QgsServerProjectUtils::wmsMaxHeight( const QgsProject &project )
|
||||
|
||||
bool QgsServerProjectUtils::wmsUseLayerIds( const QgsProject &project )
|
||||
{
|
||||
return project.readBoolEntry( QStringLiteral( "WMSUseLayerIDs" ), QStringLiteral( "/" ) );
|
||||
return project.readBoolEntry( QStringLiteral( "WMSUseLayerIDs" ), QStringLiteral( "/" ), false );
|
||||
}
|
||||
|
||||
bool QgsServerProjectUtils::wmsInfoFormatSia2045( const QgsProject &project )
|
||||
|
@ -1746,25 +1746,9 @@ void QgsWmsProjectParser::addOWSLayers( QDomDocument &doc,
|
||||
|
||||
int QgsWmsProjectParser::layersAndStyles( QStringList &layers, QStringList &styles ) const
|
||||
{
|
||||
layers.clear();
|
||||
layers = mProjectParser->layersNames();
|
||||
styles.clear();
|
||||
|
||||
const QList<QDomElement> &projectLayerElements = mProjectParser->projectLayerElements();
|
||||
QList<QDomElement>::const_iterator elemIt = projectLayerElements.constBegin();
|
||||
|
||||
QString currentLayerName;
|
||||
|
||||
for ( ; elemIt != projectLayerElements.constEnd(); ++elemIt )
|
||||
{
|
||||
currentLayerName = mProjectParser->layerShortName( *elemIt );
|
||||
if ( currentLayerName.isEmpty() )
|
||||
currentLayerName = mProjectParser->layerName( *elemIt );
|
||||
if ( !currentLayerName.isEmpty() )
|
||||
{
|
||||
layers << currentLayerName;
|
||||
styles << QString();
|
||||
}
|
||||
}
|
||||
styles.reserve( layers.size() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -18,12 +18,20 @@ SET (wms_SRCS
|
||||
qgsmaprendererjobproxy.cpp
|
||||
qgsmediancut.cpp
|
||||
qgswmsrenderer.cpp
|
||||
qgswmsparameters.cpp
|
||||
qgslayerrestorer.cpp
|
||||
)
|
||||
|
||||
SET (wms_MOC_HDRS
|
||||
qgswmsparameters.h
|
||||
)
|
||||
|
||||
########################################################
|
||||
# Build
|
||||
|
||||
ADD_LIBRARY (wms MODULE ${wms_SRCS})
|
||||
QT5_WRAP_CPP(wms_MOC_SRCS ${wms_MOC_HDRS})
|
||||
|
||||
ADD_LIBRARY (wms MODULE ${wms_SRCS} ${wms_MOC_SRCS} ${wms_MOC_HDRS})
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM
|
||||
@ -35,6 +43,7 @@ INCLUDE_DIRECTORIES(SYSTEM
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/src/core
|
||||
${CMAKE_SOURCE_DIR}/src/core/annotations
|
||||
${CMAKE_SOURCE_DIR}/src/core/expression
|
||||
${CMAKE_SOURCE_DIR}/src/core/dxf
|
||||
${CMAKE_SOURCE_DIR}/src/core/expression
|
||||
|
115
src/server/services/wms/qgslayerrestorer.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
/***************************************************************************
|
||||
qgslayerrestorer.cpp
|
||||
--------------------
|
||||
begin : April 24, 2017
|
||||
copyright : (C) 2017 by Paul Blottiere
|
||||
email : paul.blottiere@oslandia.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 "qgslayerrestorer.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgsrasterrenderer.h"
|
||||
#include "qgsmaplayerstylemanager.h"
|
||||
|
||||
const QString DEFAULT_NAMED_STYLE = "server_default_style";
|
||||
|
||||
QgsLayerRestorer::QgsLayerRestorer( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
QgsLayerSettings settings;
|
||||
|
||||
QString style = layer->styleManager()->currentStyle();
|
||||
if ( style.isEmpty() )
|
||||
{
|
||||
layer->styleManager()->addStyleFromLayer( DEFAULT_NAMED_STYLE );
|
||||
settings.mNamedStyle = DEFAULT_NAMED_STYLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.mNamedStyle = style;
|
||||
}
|
||||
|
||||
// set a custom property allowing to keep in memory if a SLD file has
|
||||
// been loaded for rendering
|
||||
layer->setCustomProperty( "readSLD", false );
|
||||
|
||||
QString errMsg;
|
||||
QDomDocument sldDoc;
|
||||
layer->exportSldStyle( sldDoc, errMsg );
|
||||
settings.mSldStyle.setContent( sldDoc.toString(), true ); // for namespace processing
|
||||
|
||||
if ( layer->type() == QgsMapLayer::LayerType::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
|
||||
if ( vLayer )
|
||||
{
|
||||
settings.mOpacity = vLayer->opacity();
|
||||
settings.mSelectedFeatureIds = vLayer->selectedFeatureIds();
|
||||
settings.mFilter = vLayer->subsetString();
|
||||
}
|
||||
}
|
||||
else if ( layer->type() == QgsMapLayer::LayerType::RasterLayer )
|
||||
{
|
||||
QgsRasterLayer *rLayer = qobject_cast<QgsRasterLayer *>( layer );
|
||||
|
||||
if ( rLayer )
|
||||
{
|
||||
settings.mOpacity = rLayer->renderer()->opacity();
|
||||
}
|
||||
}
|
||||
|
||||
mLayerSettings[layer] = settings;
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayerRestorer::~QgsLayerRestorer()
|
||||
{
|
||||
for ( QgsMapLayer *layer : mLayerSettings.keys() )
|
||||
{
|
||||
QgsLayerSettings settings = mLayerSettings[layer];
|
||||
layer->styleManager()->setCurrentStyle( settings.mNamedStyle );
|
||||
|
||||
// if a SLD file has been loaded for rendering, we restore the previous one
|
||||
QString errMsg;
|
||||
QDomElement root = settings.mSldStyle.firstChildElement( "StyledLayerDescriptor" );
|
||||
QDomElement el = root.firstChildElement( "NamedLayer" );
|
||||
if ( layer->customProperty( "readSLD", false ).toBool() )
|
||||
{
|
||||
layer->readSld( el, errMsg );
|
||||
}
|
||||
layer->removeCustomProperty( "readSLD" );
|
||||
|
||||
if ( layer->type() == QgsMapLayer::LayerType::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
|
||||
if ( vLayer )
|
||||
{
|
||||
vLayer->setOpacity( settings.mOpacity );
|
||||
vLayer->selectByIds( settings.mSelectedFeatureIds );
|
||||
vLayer->setSubsetString( settings.mFilter );
|
||||
}
|
||||
}
|
||||
else if ( layer->type() == QgsMapLayer::LayerType::RasterLayer )
|
||||
{
|
||||
QgsRasterLayer *rLayer = qobject_cast<QgsRasterLayer *>( layer );
|
||||
|
||||
if ( rLayer )
|
||||
{
|
||||
rLayer->renderer()->setOpacity( settings.mOpacity );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
48
src/server/services/wms/qgslayerrestorer.h
Normal file
@ -0,0 +1,48 @@
|
||||
/***************************************************************************
|
||||
qgslayerrestorer.h
|
||||
-------------------
|
||||
begin : April 24, 2017
|
||||
copyright : (C) 2017 by Paul Blottiere
|
||||
email : paul.blottiere@oslandia.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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSLAYERRESTORER_H
|
||||
#define QGSLAYERRESTORER_H
|
||||
|
||||
#include <QList>
|
||||
|
||||
#include "qgsmaplayer.h"
|
||||
|
||||
/** RAII class to restore layer configuration on destruction (opacity,
|
||||
* filters, ...)
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class QgsLayerRestorer
|
||||
{
|
||||
struct QgsLayerSettings
|
||||
{
|
||||
double mOpacity;
|
||||
QString mNamedStyle;
|
||||
QDomDocument mSldStyle;
|
||||
QString mFilter;
|
||||
QgsFeatureIds mSelectedFeatureIds;
|
||||
};
|
||||
|
||||
public:
|
||||
QgsLayerRestorer( const QList<QgsMapLayer *> &layers );
|
||||
~QgsLayerRestorer();
|
||||
|
||||
private:
|
||||
QMap<QgsMapLayer *, QgsLayerSettings> mLayerSettings;
|
||||
};
|
||||
|
||||
#endif
|
660
src/server/services/wms/qgswmsparameters.cpp
Normal file
@ -0,0 +1,660 @@
|
||||
/***************************************************************************
|
||||
qgswmsparameters.cpp
|
||||
--------------------
|
||||
begin : March 17, 2017
|
||||
copyright : (C) 2017 by Paul Blottiere
|
||||
email : paul dot blottiere at oslandia 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 "qgswmsparameters.h"
|
||||
#include "qgsmessagelog.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace QgsWms
|
||||
{
|
||||
QgsWmsParameters::QgsWmsParameters()
|
||||
{
|
||||
const Parameter pHighlightGeom = { ParameterName::HIGHLIGHT_GEOM,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightGeom );
|
||||
|
||||
const Parameter pHighlightSymbol = { ParameterName::HIGHLIGHT_SYMBOL,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightSymbol );
|
||||
|
||||
const Parameter pHighlightLabel = { ParameterName::HIGHLIGHT_LABELSTRING,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightLabel );
|
||||
|
||||
const Parameter pHighlightColor = { ParameterName::HIGHLIGHT_LABELCOLOR,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightColor );
|
||||
|
||||
const Parameter pHighlightFontSize = { ParameterName::HIGHLIGHT_LABELSIZE,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightFontSize );
|
||||
|
||||
const Parameter pHighlightFontWeight = { ParameterName::HIGHLIGHT_LABELWEIGHT,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightFontWeight );
|
||||
|
||||
const Parameter pHighlightFont = { ParameterName::HIGHLIGHT_LABELFONT,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightFont );
|
||||
|
||||
const Parameter pHighlightBufferColor = { ParameterName::HIGHLIGHT_LABELBUFFERCOLOR,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightBufferColor );
|
||||
|
||||
const Parameter pHighlightBufferSize = { ParameterName::HIGHLIGHT_LABELBUFFERSIZE,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHighlightBufferSize );
|
||||
|
||||
const Parameter pCRS = { ParameterName::CRS,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pCRS );
|
||||
|
||||
const Parameter pHeight = { ParameterName::HEIGHT,
|
||||
QVariant::Int,
|
||||
QVariant( 0 ),
|
||||
QVariant()
|
||||
};
|
||||
save( pHeight );
|
||||
|
||||
const Parameter pWidth = { ParameterName::WIDTH,
|
||||
QVariant::Int,
|
||||
QVariant( 0 ),
|
||||
QVariant()
|
||||
};
|
||||
save( pWidth );
|
||||
|
||||
const Parameter pBbox = { ParameterName::BBOX,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pBbox );
|
||||
|
||||
const Parameter pSld = { ParameterName::SLD,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pSld );
|
||||
|
||||
const Parameter pLayer = { ParameterName::LAYER,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pLayer );
|
||||
|
||||
const Parameter pLayers = { ParameterName::LAYERS,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pLayers );
|
||||
|
||||
const Parameter pStyle = { ParameterName::STYLE,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pLayers );
|
||||
|
||||
const Parameter pStyles = { ParameterName::STYLES,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pStyles );
|
||||
|
||||
const Parameter pOpacities = { ParameterName::OPACITIES,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pOpacities );
|
||||
|
||||
const Parameter pFilter = { ParameterName::FILTER,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pFilter );
|
||||
|
||||
const Parameter pSelection = { ParameterName::SELECTION,
|
||||
QVariant::String,
|
||||
QVariant( "" ),
|
||||
QVariant()
|
||||
};
|
||||
save( pSelection );
|
||||
}
|
||||
|
||||
QgsWmsParameters::QgsWmsParameters( const QgsServerRequest::Parameters ¶meters )
|
||||
{
|
||||
load( parameters );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::load( const QgsServerRequest::Parameters ¶meters )
|
||||
{
|
||||
mRequestParameters = parameters;
|
||||
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<ParameterName>() );
|
||||
foreach ( QString key, parameters.keys() )
|
||||
{
|
||||
const ParameterName name = ( ParameterName ) metaEnum.keyToValue( key.toStdString().c_str() );
|
||||
if ( name >= 0 )
|
||||
{
|
||||
QVariant value( parameters[key] );
|
||||
if ( value.canConvert( mParameters[name].mType ) )
|
||||
{
|
||||
mParameters[name].mValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
raiseError( name );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsWmsParameters::dump() const
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<ParameterName>() );
|
||||
|
||||
log( "WMS Request parameters:" );
|
||||
for ( auto parameter : mParameters.toStdMap() )
|
||||
{
|
||||
const QString value = parameter.second.mValue.toString();
|
||||
|
||||
if ( ! value.isEmpty() )
|
||||
{
|
||||
const QString name = metaEnum.valueToKey( parameter.first );
|
||||
log( " - " + name + " : " + value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsWmsParameters::save( const Parameter ¶meter )
|
||||
{
|
||||
mParameters[ parameter.mName ] = parameter;
|
||||
}
|
||||
|
||||
QVariant QgsWmsParameters::value( ParameterName name ) const
|
||||
{
|
||||
return mParameters[name].mValue;
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightGeom() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_GEOM, ';' );
|
||||
}
|
||||
|
||||
QList<QgsGeometry> QgsWmsParameters::highlightGeomAsGeom() const
|
||||
{
|
||||
QList<QgsGeometry> geometries;
|
||||
|
||||
Q_FOREACH ( QString wkt, highlightGeom() )
|
||||
{
|
||||
QgsGeometry g( QgsGeometry::fromWkt( wkt ) );
|
||||
|
||||
if ( g.isGeosValid() )
|
||||
{
|
||||
geometries.append( g );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString val = value( ParameterName::HIGHLIGHT_GEOM ).toString();
|
||||
QString msg = "HIGHLIGHT_GEOM ('" + val + "') cannot be converted into a list of geometries";
|
||||
raiseError( msg );
|
||||
}
|
||||
}
|
||||
|
||||
return geometries;
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightSymbol() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_SYMBOL, ';' );
|
||||
}
|
||||
|
||||
QString QgsWmsParameters::crs() const
|
||||
{
|
||||
return value( ParameterName::CRS ).toString();
|
||||
}
|
||||
|
||||
QString QgsWmsParameters::bbox() const
|
||||
{
|
||||
return value( ParameterName::BBOX ).toString();
|
||||
}
|
||||
|
||||
QgsRectangle QgsWmsParameters::bboxAsRectangle() const
|
||||
{
|
||||
QgsRectangle extent;
|
||||
|
||||
if ( !bbox().isEmpty() )
|
||||
{
|
||||
QStringList corners = bbox().split( "," );
|
||||
|
||||
if ( corners.size() == 4 )
|
||||
{
|
||||
double d[4];
|
||||
bool ok;
|
||||
|
||||
for ( int i = 0; i < 4; i++ )
|
||||
{
|
||||
corners[i].replace( QLatin1String( " " ), QLatin1String( "+" ) );
|
||||
d[i] = corners[i].toDouble( &ok );
|
||||
if ( !ok )
|
||||
{
|
||||
raiseError( "BBOX ('" + bbox() + "') cannot be converted into a rectangle" );
|
||||
}
|
||||
}
|
||||
|
||||
extent = QgsRectangle( d[0], d[1], d[2], d[3] );
|
||||
}
|
||||
else
|
||||
{
|
||||
raiseError( "BBOX ('" + bbox() + "') cannot be converted into a rectangle" );
|
||||
}
|
||||
}
|
||||
|
||||
return extent;
|
||||
}
|
||||
|
||||
int QgsWmsParameters::height() const
|
||||
{
|
||||
bool ok = false;
|
||||
int height = value( ParameterName::HEIGHT ).toInt( &ok );
|
||||
|
||||
if ( ! ok )
|
||||
raiseError( ParameterName::HEIGHT );
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
int QgsWmsParameters::width() const
|
||||
{
|
||||
bool ok = false;
|
||||
int width = value( ParameterName::WIDTH ).toInt( &ok );
|
||||
|
||||
if ( ! ok )
|
||||
raiseError( ParameterName::WIDTH );
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::toStringList( ParameterName name, char delimiter ) const
|
||||
{
|
||||
return value( name ).toString().split( delimiter, QString::SkipEmptyParts );
|
||||
}
|
||||
|
||||
QList<int> QgsWmsParameters::toIntList( QStringList l, ParameterName p ) const
|
||||
{
|
||||
QList<int> elements;
|
||||
|
||||
Q_FOREACH ( QString element, l )
|
||||
{
|
||||
bool ok;
|
||||
int e = element.toInt( &ok );
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
elements.append( e );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString val = value( p ).toString();
|
||||
QString n = name( p );
|
||||
QString msg = n + " ('" + val + "') cannot be converted into a list of int";
|
||||
raiseError( msg );
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
QList<float> QgsWmsParameters::toFloatList( QStringList l, ParameterName p ) const
|
||||
{
|
||||
QList<float> elements;
|
||||
|
||||
Q_FOREACH ( QString element, l )
|
||||
{
|
||||
bool ok;
|
||||
float e = element.toFloat( &ok );
|
||||
|
||||
if ( ok )
|
||||
{
|
||||
elements.append( e );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString val = value( p ).toString();
|
||||
QString n = name( p );
|
||||
QString msg = n + " ('" + val + "') cannot be converted into a list of float";
|
||||
raiseError( msg );
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
QList<QColor> QgsWmsParameters::toColorList( QStringList l, ParameterName p ) const
|
||||
{
|
||||
QList<QColor> elements;
|
||||
|
||||
Q_FOREACH ( QString element, l )
|
||||
{
|
||||
QColor c = QColor( element );
|
||||
|
||||
if ( c.isValid() )
|
||||
{
|
||||
elements.append( c );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString val = value( p ).toString();
|
||||
QString n = name( p );
|
||||
QString msg = n + " ('" + val + "') cannot be converted into a list of colors";
|
||||
raiseError( msg );
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelString() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELSTRING, ';' );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelSize() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELSIZE, ';' );
|
||||
}
|
||||
|
||||
QList<int> QgsWmsParameters::highlightLabelSizeAsInt() const
|
||||
{
|
||||
return toIntList( highlightLabelSize(), ParameterName::HIGHLIGHT_LABELSIZE );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelColor() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELCOLOR, ';' );
|
||||
}
|
||||
|
||||
QList<QColor> QgsWmsParameters::highlightLabelColorAsColor() const
|
||||
{
|
||||
return toColorList( highlightLabelColor(), ParameterName::HIGHLIGHT_LABELCOLOR );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelWeight() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELWEIGHT, ';' );
|
||||
}
|
||||
|
||||
QList<int> QgsWmsParameters::highlightLabelWeightAsInt() const
|
||||
{
|
||||
return toIntList( highlightLabelWeight(), ParameterName::HIGHLIGHT_LABELWEIGHT );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelFont() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELFONT, ';' );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelBufferColor() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELBUFFERCOLOR, ';' );
|
||||
}
|
||||
|
||||
QList<QColor> QgsWmsParameters::highlightLabelBufferColorAsColor() const
|
||||
{
|
||||
return toColorList( highlightLabelBufferColor(), ParameterName::HIGHLIGHT_LABELBUFFERCOLOR );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::highlightLabelBufferSize() const
|
||||
{
|
||||
return toStringList( ParameterName::HIGHLIGHT_LABELBUFFERSIZE, ';' );
|
||||
}
|
||||
|
||||
QList<float> QgsWmsParameters::highlightLabelBufferSizeAsFloat() const
|
||||
{
|
||||
return toFloatList( highlightLabelBufferSize(), ParameterName::HIGHLIGHT_LABELBUFFERSIZE );
|
||||
}
|
||||
|
||||
QString QgsWmsParameters::sld() const
|
||||
{
|
||||
return value( ParameterName::SLD ).toString();
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::filters() const
|
||||
{
|
||||
return toStringList( ParameterName::FILTER, ';' );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::selections() const
|
||||
{
|
||||
return toStringList( ParameterName::SELECTION );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::opacities() const
|
||||
{
|
||||
return toStringList( ParameterName::OPACITIES );
|
||||
}
|
||||
|
||||
QList<int> QgsWmsParameters::opacitiesAsInt() const
|
||||
{
|
||||
return toIntList( opacities(), ParameterName::OPACITIES );
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::allLayersNickname() const
|
||||
{
|
||||
QStringList layer = toStringList( ParameterName::LAYER );
|
||||
QStringList layers = toStringList( ParameterName::LAYERS );
|
||||
return layer << layers;
|
||||
}
|
||||
|
||||
QStringList QgsWmsParameters::allStyles() const
|
||||
{
|
||||
QStringList style = value( ParameterName::STYLE ).toString().split( ",", QString::SkipEmptyParts );
|
||||
QStringList styles = value( ParameterName::STYLES ).toString().split( "," );
|
||||
return style << styles;
|
||||
}
|
||||
|
||||
QList<QgsWmsParametersLayer> QgsWmsParameters::layersParameters() const
|
||||
{
|
||||
QList<QgsWmsParametersLayer> parameters;
|
||||
QStringList layers = allLayersNickname();
|
||||
QStringList styles = allStyles();
|
||||
QStringList filter = filters();
|
||||
QStringList selection = selections();
|
||||
QList<int> opacities = opacitiesAsInt();
|
||||
|
||||
// filter format: "LayerName:filterString;LayerName2:filterString2;..."
|
||||
// several filters can be defined for one layer
|
||||
QMultiMap<QString, QString> layerFilters;
|
||||
Q_FOREACH ( QString f, filter )
|
||||
{
|
||||
QStringList splits = f.split( ":" );
|
||||
if ( splits.size() == 2 )
|
||||
{
|
||||
layerFilters.insert( splits[0], splits[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString filterStr = value( ParameterName::FILTER ).toString();
|
||||
raiseError( "FILTER ('" + filterStr + "') is not properly formatted" );
|
||||
}
|
||||
}
|
||||
|
||||
// selection format: "LayerName:id0,id1;LayerName2:id0,id1;..."
|
||||
// several filters can be defined for one layer
|
||||
QMultiMap<QString, QString> layerSelections;
|
||||
Q_FOREACH ( QString s, selection )
|
||||
{
|
||||
QStringList splits = s.split( ":" );
|
||||
if ( splits.size() == 2 )
|
||||
{
|
||||
layerSelections.insert( splits[0], splits[1] );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString selStr = value( ParameterName::SELECTION ).toString();
|
||||
raiseError( "SELECTION ('" + selStr + "') is not properly formatted" );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < layers.size(); i++ )
|
||||
{
|
||||
QString layer = layers[i];
|
||||
QgsWmsParametersLayer param;
|
||||
param.mNickname = layer;
|
||||
|
||||
if ( i < styles.count() )
|
||||
param.mStyle = styles[i];
|
||||
|
||||
if ( i < opacities.count() )
|
||||
param.mOpacity = opacities[i];
|
||||
|
||||
if ( layerFilters.contains( layer ) )
|
||||
{
|
||||
QMultiMap<QString, QString>::const_iterator it;
|
||||
it = layerFilters.find( layer );
|
||||
while ( it != layerFilters.end() && it.key() == layer )
|
||||
{
|
||||
param.mFilter.append( it.value() );
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if ( layerSelections.contains( layer ) )
|
||||
{
|
||||
QMultiMap<QString, QString>::const_iterator it;
|
||||
it = layerSelections.find( layer );
|
||||
while ( it != layerSelections.end() && it.key() == layer )
|
||||
{
|
||||
param.mSelection << it.value().split( "," );
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
parameters.append( param );
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
QList<QgsWmsParametersHighlightLayer> QgsWmsParameters::highlightLayersParameters() const
|
||||
{
|
||||
QList<QgsWmsParametersHighlightLayer> params;
|
||||
QList<QgsGeometry> geoms = highlightGeomAsGeom();
|
||||
QStringList slds = highlightSymbol();
|
||||
QStringList labels = highlightLabelString();
|
||||
QList<QColor> colors = highlightLabelColorAsColor();
|
||||
QList<int> sizes = highlightLabelSizeAsInt();
|
||||
QList<int> weights = highlightLabelWeightAsInt();
|
||||
QStringList fonts = highlightLabelFont();
|
||||
QList<QColor> bufferColors = highlightLabelBufferColorAsColor();
|
||||
QList<float> bufferSizes = highlightLabelBufferSizeAsFloat();
|
||||
|
||||
int nLayers = qMin( geoms.size(), slds.size() );
|
||||
for ( int i = 0; i < nLayers; i++ )
|
||||
{
|
||||
QgsWmsParametersHighlightLayer param;
|
||||
param.mName = "highlight_" + QString::number( i );
|
||||
param.mGeom = geoms[i];
|
||||
param.mSld = slds[i];
|
||||
|
||||
if ( i < labels.count() )
|
||||
param.mLabel = labels[i];
|
||||
|
||||
if ( i < colors.count() )
|
||||
param.mColor = colors[i];
|
||||
|
||||
if ( i < sizes.count() )
|
||||
param.mSize = sizes[i];
|
||||
|
||||
if ( i < weights.count() )
|
||||
param.mWeight = weights[i];
|
||||
|
||||
if ( i < fonts.count() )
|
||||
param.mFont = fonts[ i ];
|
||||
|
||||
if ( i < bufferColors.count() )
|
||||
param.mBufferColor = bufferColors[i];
|
||||
|
||||
if ( i < bufferSizes.count() )
|
||||
param.mBufferSize = bufferSizes[i];
|
||||
|
||||
params.append( param );
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
QString QgsWmsParameters::name( ParameterName name ) const
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<ParameterName>() );
|
||||
return metaEnum.valueToKey( name );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::log( const QString &msg ) const
|
||||
{
|
||||
QgsMessageLog::logMessage( msg, "Server", QgsMessageLog::INFO );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::raiseError( ParameterName paramName ) const
|
||||
{
|
||||
const QString value = mParameters[paramName].mValue.toString();
|
||||
const QString param = name( paramName );
|
||||
const QString type = QVariant::typeToName( mParameters[paramName].mType );
|
||||
raiseError( param + " ('" + value + "') cannot be converted into " + type );
|
||||
}
|
||||
|
||||
void QgsWmsParameters::raiseError( const QString &msg ) const
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "Invalid WMS Parameter" ), msg );
|
||||
}
|
||||
}
|
301
src/server/services/wms/qgswmsparameters.h
Normal file
@ -0,0 +1,301 @@
|
||||
/***************************************************************************
|
||||
qgswmsparameters.h
|
||||
------------------
|
||||
begin : March 17, 2017
|
||||
copyright : (C) 2017 by Paul Blottiere
|
||||
email : paul dot blottiere at oslandia 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSWMSPARAMETERS_H
|
||||
#define QGSWMSPARAMETERS_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QMetaEnum>
|
||||
#include <QColor>
|
||||
#include "qgsrectangle.h"
|
||||
#include "qgswmsserviceexception.h"
|
||||
#include "qgsserverrequest.h"
|
||||
#include "qgsgeometry.h"
|
||||
|
||||
/** QgsWmsParameters provides an interface to retrieve and manipulate WMS
|
||||
* parameters received from the client.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
namespace QgsWms
|
||||
{
|
||||
struct QgsWmsParametersLayer
|
||||
{
|
||||
QString mNickname; // name, id or short name
|
||||
int mOpacity = -1;
|
||||
QStringList mFilter; // list of filter
|
||||
QStringList mSelection; // list of string fid
|
||||
QString mStyle;
|
||||
};
|
||||
|
||||
struct QgsWmsParametersHighlightLayer
|
||||
{
|
||||
QString mName;
|
||||
QgsGeometry mGeom;
|
||||
QString mSld;
|
||||
QString mLabel;
|
||||
QColor mColor;
|
||||
int mSize = 0;
|
||||
int mWeight = 0;
|
||||
QString mFont;
|
||||
float mBufferSize = 0;
|
||||
QColor mBufferColor;
|
||||
};
|
||||
|
||||
class QgsWmsParameters
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
enum ParameterName
|
||||
{
|
||||
CRS, // instead of SRS for WMS 1.3.0
|
||||
// SRS, // for WMS 1.1.1
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
BBOX,
|
||||
LAYER,
|
||||
LAYERS,
|
||||
STYLE,
|
||||
STYLES,
|
||||
OPACITIES,
|
||||
SLD,
|
||||
FILTER,
|
||||
SELECTION,
|
||||
HIGHLIGHT_GEOM,
|
||||
HIGHLIGHT_SYMBOL,
|
||||
HIGHLIGHT_LABELSTRING,
|
||||
HIGHLIGHT_LABELFONT,
|
||||
HIGHLIGHT_LABELSIZE,
|
||||
HIGHLIGHT_LABELWEIGHT,
|
||||
HIGHLIGHT_LABELCOLOR,
|
||||
HIGHLIGHT_LABELBUFFERCOLOR,
|
||||
HIGHLIGHT_LABELBUFFERSIZE
|
||||
};
|
||||
Q_ENUM( ParameterName )
|
||||
|
||||
struct Parameter
|
||||
{
|
||||
ParameterName mName;
|
||||
QVariant::Type mType;
|
||||
QVariant mDefaultValue;
|
||||
QVariant mValue;
|
||||
};
|
||||
|
||||
/** Constructor.
|
||||
* \param map of parameters where keys are parameters' names.
|
||||
*/
|
||||
QgsWmsParameters( const QgsServerRequest::Parameters ¶meters );
|
||||
|
||||
/** Constructor.
|
||||
*/
|
||||
QgsWmsParameters();
|
||||
|
||||
/** Loads new parameters.
|
||||
* \param map of parameters
|
||||
*/
|
||||
void load( const QgsServerRequest::Parameters ¶meters );
|
||||
|
||||
/** Dumps parameters.
|
||||
*/
|
||||
void dump() const;
|
||||
|
||||
/** Returns CRS or an empty string if none is defined.
|
||||
* \returns crs parameter as string
|
||||
*/
|
||||
QString crs() const;
|
||||
|
||||
/** Returns WIDTH parameter as an int (0 if not defined). An exception is
|
||||
* raised if it cannot be converted.
|
||||
* \returns width parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int width() const;
|
||||
|
||||
/** Returns HEIGHT parameter as an int (0 if not defined). An exception
|
||||
* is raised if it cannot be converted.
|
||||
* \returns height parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int height() const;
|
||||
|
||||
/** Returns BBOX if defined or an empty string.
|
||||
* \returns bbox parameter
|
||||
*/
|
||||
QString bbox() const;
|
||||
|
||||
/** Returns BBOX as a rectangle if defined and valid. An exception is
|
||||
* raised if the BBOX string cannot be converted into a rectangle.
|
||||
* \returns bbox as rectangle
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QgsRectangle bboxAsRectangle() const;
|
||||
|
||||
/** Returns SLD if defined or an empty string.
|
||||
* \returns sld
|
||||
*/
|
||||
QString sld() const;
|
||||
|
||||
/** Returns the list of feature selection found in SELECTION parameter.
|
||||
* \returns the list of selection
|
||||
*/
|
||||
QStringList selections() const;
|
||||
|
||||
/** Returns the list of filters found in FILTER parameter.
|
||||
* \returns the list of filter
|
||||
*/
|
||||
QStringList filters() const;
|
||||
|
||||
/** Returns the list of opacities found in OPACITIES parameter.
|
||||
* \returns the list of opacities in string
|
||||
*/
|
||||
QStringList opacities() const;
|
||||
|
||||
/** Returns the list of opacities found in OPACITIES parameter as
|
||||
* integers. If an opacity cannot be converted into an integer, then an
|
||||
* exception is raised
|
||||
* \returns a list of opacities as integers
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<int> opacitiesAsInt() const;
|
||||
|
||||
/** Returns nickname of layers found in LAYER and LAYERS parameters.
|
||||
* \returns nickname of layers
|
||||
*/
|
||||
QStringList allLayersNickname() const;
|
||||
|
||||
/** Returns styles found in STYLE and STYLES parameters.
|
||||
* \returns name of styles
|
||||
*/
|
||||
QStringList allStyles() const;
|
||||
|
||||
/** Returns parameters for each layer found in LAYER/LAYERS.
|
||||
* \returns layer parameters
|
||||
*/
|
||||
QList<QgsWmsParametersLayer> layersParameters() const;
|
||||
|
||||
/** Returns parameters for each highlight layer.
|
||||
* \returns parameters for each highlight layer
|
||||
*/
|
||||
QList<QgsWmsParametersHighlightLayer> highlightLayersParameters() const;
|
||||
|
||||
/** Returns HIGHLIGHT_GEOM as a list of string in WKT.
|
||||
* \returns highlight geometries
|
||||
*/
|
||||
QStringList highlightGeom() const;
|
||||
|
||||
/** Returns HIGHLIGHT_GEOM as a list of geometries. An exception is
|
||||
* raised if an invalid geometry is found.
|
||||
* \returns highlight geometries
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<QgsGeometry> highlightGeomAsGeom() const;
|
||||
|
||||
/** Returns HIGHLIGHT_SYMBOL as a list of string.
|
||||
* \returns highlight sld symbols
|
||||
*/
|
||||
QStringList highlightSymbol() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELSTRING as a list of string.
|
||||
* \returns highlight label string
|
||||
*/
|
||||
QStringList highlightLabelString() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELCOLOR as a list of string.
|
||||
* \returns highlight label color
|
||||
*/
|
||||
QStringList highlightLabelColor() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELCOLOR as a list of color. An exception is
|
||||
* raised if an invalid color is found.
|
||||
* \returns highlight label color
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<QColor> highlightLabelColorAsColor() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELSIZE as a list of string.
|
||||
* \returns highlight label size
|
||||
*/
|
||||
QStringList highlightLabelSize() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELSIZE as a list of int An exception is raised
|
||||
* if an invalid size is found.
|
||||
* \returns highlight label size
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<int> highlightLabelSizeAsInt() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELWEIGHT as a list of string.
|
||||
* \returns highlight label weight
|
||||
*/
|
||||
QStringList highlightLabelWeight() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELWEIGHT as a list of int. An exception is
|
||||
* raised if an invalid weight is found.
|
||||
* \returns highlight label weight
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<int> highlightLabelWeightAsInt() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELFONT
|
||||
* \returns highlight label font
|
||||
*/
|
||||
QStringList highlightLabelFont() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELBUFFERSIZE
|
||||
* \returns highlight label buffer size
|
||||
*/
|
||||
QStringList highlightLabelBufferSize() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELBUFFERSIZE as a list of float. An exception is
|
||||
* raised if an invalid size is found.
|
||||
* \returns highlight label buffer size
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<float> highlightLabelBufferSizeAsFloat() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELBUFFERCOLOR as a list of string.
|
||||
* \returns highlight label buffer color
|
||||
*/
|
||||
QStringList highlightLabelBufferColor() const;
|
||||
|
||||
/** Returns HIGHLIGHT_LABELBUFFERCOLOR as a list of colors. An axception
|
||||
* is raised if an invalid color is found.
|
||||
* \returns highlight label buffer color
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
QList<QColor> highlightLabelBufferColorAsColor() const;
|
||||
|
||||
private:
|
||||
QString name( ParameterName name ) const;
|
||||
void raiseError( ParameterName name ) const;
|
||||
void raiseError( const QString &msg ) const;
|
||||
void initParameters();
|
||||
QVariant value( ParameterName name ) const;
|
||||
void log( const QString &msg ) const;
|
||||
void save( const Parameter ¶meter );
|
||||
QStringList toStringList( ParameterName name, char delimiter = ',' ) const;
|
||||
QList<int> toIntList( QStringList l, ParameterName name ) const;
|
||||
QList<float> toFloatList( QStringList l, ParameterName name ) const;
|
||||
QList<QColor> toColorList( QStringList l, ParameterName name ) const;
|
||||
|
||||
QgsServerRequest::Parameters mRequestParameters;
|
||||
QMap<ParameterName, Parameter> mParameters;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -28,6 +28,7 @@
|
||||
#include "qgsfieldformatterregistry.h"
|
||||
#include "qgsfeatureiterator.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgsmapserviceexception.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
@ -58,6 +59,13 @@
|
||||
#include "qgswmsserviceexception.h"
|
||||
#include "qgsserverprojectutils.h"
|
||||
#include "qgsgui.h"
|
||||
#include "qgsmaplayerstylemanager.h"
|
||||
#include "qgswkbtypes.h"
|
||||
#include "qgsannotationmanager.h"
|
||||
#include "qgsannotation.h"
|
||||
#include "qgsvectorlayerlabeling.h"
|
||||
#include "qgspallabeling.h"
|
||||
#include "qgslayerrestorer.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QPainter>
|
||||
@ -109,6 +117,11 @@ namespace QgsWms
|
||||
, mSettings( *serverIface->serverSettings() )
|
||||
, mProject( project )
|
||||
{
|
||||
mWmsParameters.load( parameters );
|
||||
mWmsParameters.dump();
|
||||
|
||||
initRestrictedLayers();
|
||||
initNicknameLayers();
|
||||
}
|
||||
|
||||
|
||||
@ -256,7 +269,7 @@ namespace QgsWms
|
||||
if ( contentBasedLegend )
|
||||
{
|
||||
HitTest hitTest;
|
||||
getMap( contentBasedMapSettings, &hitTest );
|
||||
getMapOld( contentBasedMapSettings, &hitTest );
|
||||
|
||||
Q_FOREACH ( QgsLayerTreeNode *node, rootGroup.children() )
|
||||
{
|
||||
@ -401,7 +414,7 @@ namespace QgsWms
|
||||
}
|
||||
|
||||
|
||||
void QgsRenderer::runHitTest( const QgsMapSettings &mapSettings, HitTest &hitTest )
|
||||
void QgsRenderer::runHitTest( const QgsMapSettings &mapSettings, HitTest &hitTest ) const
|
||||
{
|
||||
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
|
||||
|
||||
@ -426,7 +439,7 @@ namespace QgsWms
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols, QgsRenderContext &context )
|
||||
void QgsRenderer::runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols, QgsRenderContext &context ) const
|
||||
{
|
||||
QgsFeatureRenderer *r = vl->renderer();
|
||||
bool moreSymbolsPerFeature = r->capabilities() & QgsFeatureRenderer::MoreSymbolsPerFeature;
|
||||
@ -693,13 +706,13 @@ namespace QgsWms
|
||||
}
|
||||
#endif
|
||||
|
||||
QImage *QgsRenderer::getMap( HitTest *hitTest )
|
||||
QImage *QgsRenderer::getMapOld( HitTest *hitTest )
|
||||
{
|
||||
QgsMapSettings mapSettings;
|
||||
return getMap( mapSettings, hitTest );
|
||||
return getMapOld( mapSettings, hitTest );
|
||||
}
|
||||
|
||||
QImage *QgsRenderer::getMap( QgsMapSettings &mapSettings, HitTest *hitTest )
|
||||
QImage *QgsRenderer::getMapOld( QgsMapSettings &mapSettings, HitTest *hitTest )
|
||||
{
|
||||
if ( !checkMaximumWidthHeight() )
|
||||
{
|
||||
@ -792,6 +805,101 @@ namespace QgsWms
|
||||
return image;
|
||||
}
|
||||
|
||||
QImage *QgsRenderer::getMap( HitTest *hitTest )
|
||||
{
|
||||
QgsMapSettings mapSettings;
|
||||
return getMap( mapSettings, hitTest );
|
||||
}
|
||||
|
||||
QImage *QgsRenderer::getMap( QgsMapSettings &mapSettings, HitTest *hitTest )
|
||||
{
|
||||
// check size
|
||||
if ( !checkMaximumWidthHeight() )
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "Size error" ),
|
||||
QStringLiteral( "The requested map size is too large" ) );
|
||||
}
|
||||
|
||||
// get layers parameters
|
||||
QList<QgsMapLayer *> layers;
|
||||
QList<QgsWmsParametersLayer> params = mWmsParameters.layersParameters();
|
||||
|
||||
// init layer restorer before doing anything
|
||||
std::unique_ptr<QgsLayerRestorer> restorer;
|
||||
restorer.reset( new QgsLayerRestorer( mNicknameLayers.values() ) );
|
||||
|
||||
// init stylized layers according to LAYERS/STYLES or SLD
|
||||
QString sld = mWmsParameters.sld();
|
||||
if ( !sld.isEmpty() )
|
||||
{
|
||||
layers = sldStylizedLayers( sld );
|
||||
}
|
||||
else
|
||||
{
|
||||
layers = stylizedLayers( params );
|
||||
}
|
||||
|
||||
// remove unwanted layers (restricted layers, ...)
|
||||
removeUnwantedLayers( layers );
|
||||
|
||||
// configure each layer with opacity, selection filter, ...
|
||||
bool updateMapExtent = mWmsParameters.bbox().isEmpty() ? true : false;
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
{
|
||||
if ( param.mNickname == layerNickname( *layer ) )
|
||||
{
|
||||
checkLayerReadPermissions( layer );
|
||||
|
||||
setLayerOpacity( layer, param.mOpacity );
|
||||
|
||||
setLayerFilter( layer, param.mFilter );
|
||||
|
||||
setLayerAccessControlFilter( layer );
|
||||
|
||||
setLayerSelection( layer, param.mSelection );
|
||||
|
||||
if ( updateMapExtent )
|
||||
updateExtent( layer, mapSettings );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add highlight layers above others
|
||||
layers = layers << highlightLayers();
|
||||
|
||||
// create the output image and the painter
|
||||
std::unique_ptr<QPainter> painter;
|
||||
std::unique_ptr<QImage> image( createImage() );
|
||||
|
||||
// configure map settings (background, DPI, ...)
|
||||
configureMapSettings( image.get(), mapSettings );
|
||||
|
||||
// add layers to map settings (revert order for the rendering)
|
||||
std::reverse( layers.begin(), layers.end() );
|
||||
mapSettings.setLayers( layers );
|
||||
|
||||
// rendering step for layers
|
||||
painter.reset( layersRendering( mapSettings, *image.get(), hitTest ) );
|
||||
|
||||
// rendering step for annotations
|
||||
annotationsRendering( painter.get() );
|
||||
|
||||
// painting is terminated
|
||||
painter->end();
|
||||
|
||||
// scale output image if necessary (required by WMS spec)
|
||||
QImage *scaledImage = scaleImage( image.get() );
|
||||
if ( scaledImage )
|
||||
image.reset( scaledImage );
|
||||
|
||||
// return
|
||||
return image.release();
|
||||
}
|
||||
|
||||
static void infoPointToMapCoordinates( int i, int j, QgsPoint *infoPoint, const QgsMapSettings &mapSettings )
|
||||
{
|
||||
//check if i, j are in the pixel range of the image
|
||||
@ -1201,9 +1309,8 @@ namespace QgsWms
|
||||
QString version = mParameters.value( QStringLiteral( "VERSION" ), QStringLiteral( "1.3.0" ) );
|
||||
if ( useBbox && version != QLatin1String( "1.1.1" ) )
|
||||
{
|
||||
QString bboxStr = mParameters.value( "BBOX" );
|
||||
QgsRectangle mapExtent = parseBbox( bboxStr );
|
||||
if ( !bboxStr.isEmpty() && mapExtent.isEmpty() )
|
||||
QgsRectangle mapExtent = mWmsParameters.bboxAsRectangle();
|
||||
if ( !mWmsParameters.bbox().isEmpty() && mapExtent.isEmpty() )
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ),
|
||||
QStringLiteral( "Invalid BBOX parameter" ) );
|
||||
@ -1305,13 +1412,10 @@ namespace QgsWms
|
||||
mapSettings.setOutputDpi( paintDevice->logicalDpiX() );
|
||||
|
||||
//map extent
|
||||
QgsRectangle mapExtent;
|
||||
QString bboxStr = mParameters.value( "BBOX" );
|
||||
if ( !bboxStr.isEmpty() )
|
||||
QgsRectangle mapExtent = mWmsParameters.bboxAsRectangle();
|
||||
if ( !mWmsParameters.bbox().isEmpty() && mapExtent.isEmpty() )
|
||||
{
|
||||
mapExtent = parseBbox( bboxStr );
|
||||
if ( mapExtent.isEmpty() )
|
||||
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ), QStringLiteral( "Invalid BBOX parameter" ) );
|
||||
throw QgsBadRequestException( QStringLiteral( "InvalidParameterValue" ), QStringLiteral( "Invalid BBOX parameter" ) );
|
||||
}
|
||||
|
||||
QString crs = mParameters.value( QStringLiteral( "CRS" ), mParameters.value( QStringLiteral( "SRS" ) ) );
|
||||
@ -1807,7 +1911,6 @@ namespace QgsWms
|
||||
return layerKeys;
|
||||
}
|
||||
|
||||
|
||||
void QgsRenderer::applyRequestedLayerFilters( const QStringList &layerList, QgsMapSettings &mapSettings, QHash<QgsMapLayer *, QString> &originalFilters ) const
|
||||
{
|
||||
if ( layerList.isEmpty() )
|
||||
@ -2246,30 +2349,19 @@ namespace QgsWms
|
||||
{
|
||||
//test if maxWidth / maxHeight set and WIDTH / HEIGHT parameter is in the range
|
||||
int wmsMaxWidth = QgsServerProjectUtils::wmsMaxWidth( *mProject );
|
||||
if ( wmsMaxWidth != -1 )
|
||||
int width = mWmsParameters.width();
|
||||
if ( wmsMaxWidth != -1 && width != -1 && width > wmsMaxWidth )
|
||||
{
|
||||
QMap<QString, QString>::const_iterator widthIt = mParameters.find( QStringLiteral( "WIDTH" ) );
|
||||
if ( widthIt != mParameters.constEnd() )
|
||||
{
|
||||
if ( widthIt->toInt() > wmsMaxWidth )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int wmsMaxHeight = QgsServerProjectUtils::wmsMaxHeight( *mProject );
|
||||
if ( wmsMaxHeight != -1 )
|
||||
int height = mWmsParameters.height();
|
||||
if ( wmsMaxHeight != -1 && height != -1 && height > wmsMaxHeight )
|
||||
{
|
||||
QMap<QString, QString>::const_iterator heightIt = mParameters.find( QStringLiteral( "HEIGHT" ) );
|
||||
if ( heightIt != mParameters.constEnd() )
|
||||
{
|
||||
if ( heightIt->toInt() > wmsMaxHeight )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2639,5 +2731,460 @@ namespace QgsWms
|
||||
}
|
||||
|
||||
|
||||
} // namespace QgsWms
|
||||
void QgsRenderer::initRestrictedLayers()
|
||||
{
|
||||
mRestrictedLayers.clear();
|
||||
|
||||
// get name of restricted layers/groups in project
|
||||
QStringList restricted = QgsServerProjectUtils::wmsRestrictedLayers( *mProject );
|
||||
|
||||
// extract restricted layers from excluded groups
|
||||
QStringList restrictedLayersNames;
|
||||
QgsLayerTreeGroup *root = mProject->layerTreeRoot();
|
||||
|
||||
Q_FOREACH ( QString l, restricted )
|
||||
{
|
||||
QgsLayerTreeGroup *group = root->findGroup( l );
|
||||
if ( group )
|
||||
{
|
||||
QList<QgsLayerTreeLayer *> groupLayers = group->findLayers();
|
||||
Q_FOREACH ( QgsLayerTreeLayer *treeLayer, groupLayers )
|
||||
{
|
||||
restrictedLayersNames.append( treeLayer->name() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
restrictedLayersNames.append( l );
|
||||
}
|
||||
}
|
||||
|
||||
// build output with names, ids or short name according to the configuration
|
||||
QList<QgsLayerTreeLayer *> layers = root->findLayers();
|
||||
Q_FOREACH ( QgsLayerTreeLayer *layer, layers )
|
||||
{
|
||||
if ( restrictedLayersNames.contains( layer->name() ) )
|
||||
{
|
||||
mRestrictedLayers.append( layerNickname( *layer->layer() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::initNicknameLayers()
|
||||
{
|
||||
Q_FOREACH ( QgsMapLayer *ml, mProject->mapLayers() )
|
||||
{
|
||||
mNicknameLayers[ layerNickname( *ml ) ] = ml;
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsRenderer::layerNickname( const QgsMapLayer &layer ) const
|
||||
{
|
||||
QString name = layer.shortName();
|
||||
if ( QgsServerProjectUtils::wmsUseLayerIds( *mProject ) )
|
||||
{
|
||||
name = layer.id();
|
||||
}
|
||||
else if ( name.isEmpty() )
|
||||
{
|
||||
name = layer.name();
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool QgsRenderer::layerScaleVisibility( const QgsMapLayer &layer, double scaleDenominator ) const
|
||||
{
|
||||
bool visible = false;
|
||||
bool scaleBasedVisibility = layer.hasScaleBasedVisibility();
|
||||
bool useScaleConstraint = ( scaleDenominator > 0 && scaleBasedVisibility );
|
||||
|
||||
if ( !useScaleConstraint || layer.isInScaleRange( scaleDenominator ) )
|
||||
{
|
||||
visible = true;
|
||||
}
|
||||
|
||||
return visible;
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsRenderer::highlightLayers()
|
||||
{
|
||||
QList<QgsMapLayer *> highlightLayers;
|
||||
|
||||
// try to create highlight layer for each geometry
|
||||
QList<QgsWmsParametersHighlightLayer> params = mWmsParameters.highlightLayersParameters();
|
||||
QString crs = mWmsParameters.crs();
|
||||
Q_FOREACH ( QgsWmsParametersHighlightLayer param, params )
|
||||
{
|
||||
// create sld document from symbology
|
||||
QDomDocument sldDoc;
|
||||
if ( !sldDoc.setContent( param.mSld, true ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// create renderer from sld document
|
||||
QString errorMsg;
|
||||
std::unique_ptr<QgsFeatureRenderer> renderer;
|
||||
QDomElement el = sldDoc.documentElement();
|
||||
renderer.reset( QgsFeatureRenderer::loadSld( el, param.mGeom.type(), errorMsg ) );
|
||||
if ( !renderer )
|
||||
{
|
||||
QgsMessageLog::logMessage( errorMsg, "Server", QgsMessageLog::INFO );
|
||||
continue;
|
||||
}
|
||||
|
||||
// build url for vector layer
|
||||
QString typeName = QgsWkbTypes::geometryDisplayString( param.mGeom.type() );
|
||||
QString url = typeName + "?crs=" + crs;
|
||||
if ( ! param.mLabel.isEmpty() )
|
||||
{
|
||||
url += "&field=label:string";
|
||||
}
|
||||
|
||||
// create vector layer
|
||||
std::unique_ptr<QgsVectorLayer> layer;
|
||||
layer.reset( new QgsVectorLayer( url, param.mName, "memory" ) );
|
||||
if ( !layer->isValid() )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// create feature with label if necessary
|
||||
QgsFeature fet( layer->pendingFields() );
|
||||
if ( ! param.mLabel.isEmpty() )
|
||||
{
|
||||
fet.setAttribute( 0, param.mLabel );
|
||||
|
||||
// init labeling engine
|
||||
QgsPalLayerSettings palSettings;
|
||||
palSettings.fieldName = "label"; // defined in url
|
||||
palSettings.priority = 10; // always drawn
|
||||
palSettings.displayAll = true;
|
||||
|
||||
QgsPalLayerSettings::Placement placement = QgsPalLayerSettings::AroundPoint;
|
||||
switch ( param.mGeom.type() )
|
||||
{
|
||||
case QgsWkbTypes::PointGeometry:
|
||||
{
|
||||
placement = QgsPalLayerSettings::AroundPoint;
|
||||
palSettings.dist = 2; // in mm
|
||||
palSettings.placementFlags = 0;
|
||||
break;
|
||||
}
|
||||
case QgsWkbTypes::PolygonGeometry:
|
||||
{
|
||||
QgsGeometry point = param.mGeom.pointOnSurface();
|
||||
QgsPoint pt = point.asPoint();
|
||||
placement = QgsPalLayerSettings::AroundPoint;
|
||||
|
||||
QgsPalLayerSettings::Property pX = QgsPalLayerSettings::PositionX;
|
||||
QVariant x( pt.x() );
|
||||
palSettings.dataDefinedProperties().setProperty( pX, x );
|
||||
|
||||
QgsPalLayerSettings::Property pY = QgsPalLayerSettings::PositionY;
|
||||
QVariant y( pt.y() );
|
||||
palSettings.dataDefinedProperties().setProperty( pY, y );
|
||||
|
||||
QgsPalLayerSettings::Property pHali = QgsPalLayerSettings::Hali;
|
||||
QVariant hali( "Center" );
|
||||
palSettings.dataDefinedProperties().setProperty( pHali, hali );
|
||||
|
||||
QgsPalLayerSettings::Property pVali = QgsPalLayerSettings::Vali;
|
||||
QVariant vali( "Half" );
|
||||
palSettings.dataDefinedProperties().setProperty( pVali, vali );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
placement = QgsPalLayerSettings::Line;
|
||||
palSettings.dist = 2;
|
||||
palSettings.placementFlags = 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
palSettings.placement = placement;
|
||||
QgsTextFormat textFormat;
|
||||
QgsTextBufferSettings bufferSettings;
|
||||
|
||||
if ( param.mColor.isValid() )
|
||||
{
|
||||
textFormat.setColor( param.mColor );
|
||||
}
|
||||
|
||||
if ( param.mSize > 0 )
|
||||
{
|
||||
textFormat.setSize( param.mSize );
|
||||
}
|
||||
|
||||
// no weight property in PAL settings or QgsTextFormat
|
||||
/* if ( param.fontWeight > 0 )
|
||||
{
|
||||
} */
|
||||
|
||||
if ( ! param.mFont.isEmpty() )
|
||||
{
|
||||
textFormat.setFont( param.mFont );
|
||||
}
|
||||
|
||||
if ( param.mBufferColor.isValid() )
|
||||
{
|
||||
bufferSettings.setColor( param.mBufferColor );
|
||||
}
|
||||
|
||||
if ( param.mBufferSize > 0 )
|
||||
{
|
||||
bufferSettings.setEnabled( true );
|
||||
bufferSettings.setSize( param.mBufferSize );
|
||||
}
|
||||
|
||||
textFormat.setBuffer( bufferSettings );
|
||||
palSettings.setFormat( textFormat );
|
||||
|
||||
QgsVectorLayerSimpleLabeling *simpleLabeling = new QgsVectorLayerSimpleLabeling( palSettings );
|
||||
layer->setLabeling( simpleLabeling );
|
||||
}
|
||||
fet.setGeometry( param.mGeom );
|
||||
|
||||
// add feature to layer and set the SLD renderer
|
||||
layer->dataProvider()->addFeatures( QgsFeatureList() << fet );
|
||||
layer->setRenderer( renderer.release() );
|
||||
|
||||
// keep the vector as an highlight layer
|
||||
if ( layer->isValid() )
|
||||
{
|
||||
highlightLayers.append( layer.release() );
|
||||
}
|
||||
}
|
||||
|
||||
return highlightLayers;
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsRenderer::sldStylizedLayers( const QString &sld ) const
|
||||
{
|
||||
QList<QgsMapLayer *> layers;
|
||||
|
||||
if ( !sld.isEmpty() )
|
||||
{
|
||||
QDomDocument doc;
|
||||
doc.setContent( sld, true );
|
||||
QDomElement docEl = doc.documentElement();
|
||||
|
||||
QDomElement root = doc.firstChildElement( "StyledLayerDescriptor" );
|
||||
QDomElement namedElem = root.firstChildElement( "NamedLayer" );
|
||||
|
||||
if ( !docEl.isNull() )
|
||||
{
|
||||
QDomNodeList named = docEl.elementsByTagName( "NamedLayer" );
|
||||
for ( int i = 0; i < named.size(); ++i )
|
||||
{
|
||||
QDomNodeList names = named.item( i ).toElement().elementsByTagName( "Name" );
|
||||
if ( !names.isEmpty() )
|
||||
{
|
||||
QString lname = names.item( 0 ).toElement().text();
|
||||
QString err;
|
||||
if ( mNicknameLayers.contains( lname ) && !mRestrictedLayers.contains( lname ) )
|
||||
{
|
||||
mNicknameLayers[lname]->readSld( namedElem, err );
|
||||
mNicknameLayers[lname]->setCustomProperty( "readSLD", true );
|
||||
layers.append( mNicknameLayers[lname] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
QList<QgsMapLayer *> QgsRenderer::stylizedLayers( const QList<QgsWmsParametersLayer> ¶ms ) const
|
||||
{
|
||||
QList<QgsMapLayer *> layers;
|
||||
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
{
|
||||
QString nickname = param.mNickname;
|
||||
QString style = param.mStyle;
|
||||
if ( mNicknameLayers.contains( nickname ) )
|
||||
{
|
||||
if ( !style.isEmpty() )
|
||||
{
|
||||
bool rc = mNicknameLayers[nickname]->styleManager()->setCurrentStyle( style );
|
||||
if ( ! rc )
|
||||
{
|
||||
throw QgsMapServiceException( QStringLiteral( "StyleNotDefined" ), QStringLiteral( "Style \"%1\" does not exist for layer \"%2\"" ).arg( style, nickname ) );
|
||||
}
|
||||
}
|
||||
|
||||
layers.append( mNicknameLayers[nickname] );
|
||||
}
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
QPainter *QgsRenderer::layersRendering( const QgsMapSettings &mapSettings, QImage &image, HitTest *hitTest ) const
|
||||
{
|
||||
QPainter *painter;
|
||||
if ( hitTest )
|
||||
{
|
||||
runHitTest( mapSettings, *hitTest );
|
||||
painter = new QPainter();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
mAccessControl->resolveFilterFeatures( mapSettings.layers() );
|
||||
#endif
|
||||
QgsMapRendererJobProxy renderJob( mSettings.parallelRendering(), mSettings.maxThreads(), mAccessControl );
|
||||
renderJob.render( mapSettings, &image );
|
||||
painter = renderJob.takePainter();
|
||||
}
|
||||
|
||||
return painter;
|
||||
}
|
||||
|
||||
void QgsRenderer::setLayerOpacity( QgsMapLayer *layer, int opacity ) const
|
||||
{
|
||||
if ( opacity >= 0 && opacity <= 255 )
|
||||
{
|
||||
if ( layer->type() == QgsMapLayer::LayerType::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
|
||||
vl->setOpacity( opacity / 255. );
|
||||
}
|
||||
else if ( layer->type() == QgsMapLayer::LayerType::RasterLayer )
|
||||
{
|
||||
QgsRasterLayer *rl = qobject_cast<QgsRasterLayer *>( layer );
|
||||
QgsRasterRenderer *rasterRenderer = rl->renderer();
|
||||
rasterRenderer->setOpacity( opacity / 255. );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::setLayerFilter( QgsMapLayer *layer, const QStringList &filters ) const
|
||||
{
|
||||
if ( layer->type() == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer *filteredLayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
Q_FOREACH ( QString filter, filters )
|
||||
{
|
||||
if ( !testFilterStringSafety( filter ) )
|
||||
{
|
||||
throw QgsBadRequestException( QStringLiteral( "Filter string rejected" ),
|
||||
QStringLiteral( "The filter string %1"
|
||||
" has been rejected because of security reasons."
|
||||
" Note: Text strings have to be enclosed in single or double quotes."
|
||||
" A space between each word / special character is mandatory."
|
||||
" Allowed Keywords and special characters are "
|
||||
" AND,OR,IN,<,>=,>,>=,!=,',',(,),DMETAPHONE,SOUNDEX."
|
||||
" Not allowed are semicolons in the filter expression." ).arg( filter ) );
|
||||
}
|
||||
|
||||
QString newSubsetString = filter;
|
||||
if ( !filteredLayer->subsetString().isEmpty() )
|
||||
{
|
||||
newSubsetString.prepend( ") AND (" );
|
||||
newSubsetString.append( ")" );
|
||||
newSubsetString.prepend( filteredLayer->subsetString() );
|
||||
newSubsetString.prepend( "(" );
|
||||
}
|
||||
filteredLayer->setSubsetString( newSubsetString );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::setLayerSelection( QgsMapLayer *layer, const QStringList &fids ) const
|
||||
{
|
||||
if ( layer->type() == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsFeatureIds selectedIds;
|
||||
|
||||
Q_FOREACH ( const QString &id, fids )
|
||||
{
|
||||
selectedIds.insert( STRING_TO_FID( id ) );
|
||||
}
|
||||
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
|
||||
vl->selectByIds( selectedIds );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::setLayerAccessControlFilter( QgsMapLayer *layer ) const
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsOWSServerFilterRestorer::applyAccessControlLayerFilters( mAccessControl, layer );
|
||||
#else
|
||||
Q_UNUSED( layer );
|
||||
#endif
|
||||
}
|
||||
|
||||
void QgsRenderer::updateExtent( const QgsMapLayer *layer, QgsMapSettings &mapSettings ) const
|
||||
{
|
||||
QgsRectangle layerExtent = mapSettings.layerToMapCoordinates( layer, layer->extent() );
|
||||
QgsRectangle mapExtent = mapSettings.extent();
|
||||
if ( !layerExtent.isEmpty() )
|
||||
{
|
||||
mapExtent.combineExtentWith( layerExtent );
|
||||
mapSettings.setExtent( mapExtent );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRenderer::annotationsRendering( QPainter *painter ) const
|
||||
{
|
||||
const QgsAnnotationManager *annotationManager = mProject->annotationManager();
|
||||
QList< QgsAnnotation * > annotations = annotationManager->annotations();
|
||||
|
||||
QgsRenderContext renderContext = QgsRenderContext::fromQPainter( painter );
|
||||
Q_FOREACH ( QgsAnnotation *annotation, annotations )
|
||||
{
|
||||
annotation->render( renderContext );
|
||||
}
|
||||
}
|
||||
|
||||
QImage *QgsRenderer::scaleImage( const QImage *image ) const
|
||||
{
|
||||
//test if width / height ratio of image is the same as the ratio of
|
||||
// WIDTH / HEIGHT parameters. If not, the image has to be scaled (required
|
||||
// by WMS spec)
|
||||
QImage *scaledImage = nullptr;
|
||||
int width = mWmsParameters.width();
|
||||
int height = mWmsParameters.height();
|
||||
if ( width != image->width() || height != image->height() )
|
||||
{
|
||||
scaledImage = new QImage( image->scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
|
||||
}
|
||||
|
||||
return scaledImage;
|
||||
}
|
||||
|
||||
void QgsRenderer::checkLayerReadPermissions( QgsMapLayer *layer ) const
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
if ( !mAccessControl->layerReadPermission( layer ) )
|
||||
{
|
||||
throw QgsSecurityException( QStringLiteral( "You are not allowed to access to the layer: %1" ).arg( layer->name() ) );
|
||||
}
|
||||
#else
|
||||
Q_UNUSED( layer );
|
||||
#endif
|
||||
}
|
||||
|
||||
void QgsRenderer::removeUnwantedLayers( QList<QgsMapLayer *> &layers, double scaleDenominator ) const
|
||||
{
|
||||
QList<QgsMapLayer *> wantedLayers;
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
{
|
||||
if ( !layerScaleVisibility( *layer, scaleDenominator ) )
|
||||
continue;
|
||||
|
||||
if ( mRestrictedLayers.contains( layerNickname( *layer ) ) )
|
||||
continue;
|
||||
|
||||
wantedLayers.append( layer );
|
||||
}
|
||||
|
||||
layers = wantedLayers;
|
||||
}
|
||||
} // namespace QgsWms
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "qgswmsconfigparser.h"
|
||||
#include "qgsserversettings.h"
|
||||
#include "qgswmsparameters.h"
|
||||
#include <QDomDocument>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
@ -93,10 +94,12 @@ namespace QgsWms
|
||||
of the image object). If an instance to existing hit test structure is passed, instead of rendering
|
||||
it will fill the structure with symbols that would be used for rendering */
|
||||
QImage *getMap( HitTest *hitTest = nullptr );
|
||||
QImage *getMapOld( HitTest *hitTest = nullptr );
|
||||
|
||||
/** Identical to getMap( HitTest* hitTest ) and updates the map settings actually used.
|
||||
\since QGIS 3.0 */
|
||||
QImage *getMap( QgsMapSettings &mapSettings, HitTest *hitTest = nullptr );
|
||||
QImage *getMapOld( QgsMapSettings &mapSettings, HitTest *hitTest = nullptr );
|
||||
|
||||
|
||||
/** Returns printed page as binary
|
||||
@ -111,6 +114,59 @@ namespace QgsWms
|
||||
|
||||
private:
|
||||
|
||||
// Init the restricted layers with nicknames
|
||||
void initRestrictedLayers();
|
||||
|
||||
// Build and returns highlight layers
|
||||
QList<QgsMapLayer *> highlightLayers();
|
||||
|
||||
// Init a map with nickname for layers' project
|
||||
void initNicknameLayers();
|
||||
|
||||
// Return the nickname of the layer (short name, id or name according to
|
||||
// the project configuration)
|
||||
QString layerNickname( const QgsMapLayer &layer ) const;
|
||||
|
||||
// Return true if the layer has to be displayed according to he current
|
||||
// scale
|
||||
bool layerScaleVisibility( const QgsMapLayer &layer, double scaleDenominator ) const;
|
||||
|
||||
// Remove unwanted layers (restricted, not visible, etc)
|
||||
void removeUnwantedLayers( QList<QgsMapLayer *> &layers, double scaleDenominator = -1 ) const;
|
||||
|
||||
// Rendering step for layers
|
||||
QPainter *layersRendering( const QgsMapSettings &mapSettings, QImage &image, HitTest *hitTest = nullptr ) const;
|
||||
|
||||
// Rendering step for annotations
|
||||
void annotationsRendering( QPainter *painter ) const;
|
||||
|
||||
// Return a list of layers stylized with LAYERS/STYLES parameters
|
||||
QList<QgsMapLayer *> stylizedLayers( const QList<QgsWmsParametersLayer> ¶ms ) const;
|
||||
|
||||
// Return a list of layers stylized with SLD parameter
|
||||
QList<QgsMapLayer *> sldStylizedLayers( const QString &sld ) const;
|
||||
|
||||
// Set layer opacity
|
||||
void setLayerOpacity( QgsMapLayer *layer, int opacity ) const;
|
||||
|
||||
// Set layer filter
|
||||
void setLayerFilter( QgsMapLayer *layer, const QStringList &filter ) const;
|
||||
|
||||
// Set layer python filter
|
||||
void setLayerAccessControlFilter( QgsMapLayer *layer ) const;
|
||||
|
||||
// Set layer selection
|
||||
void setLayerSelection( QgsMapLayer *layer, const QStringList &fids ) const;
|
||||
|
||||
// Combine map extent with layer extent
|
||||
void updateExtent( const QgsMapLayer *layer, QgsMapSettings &mapSettings ) const;
|
||||
|
||||
// Scale image with WIDTH/HEIGHT if necessary
|
||||
QImage *scaleImage( const QImage *image ) const;
|
||||
|
||||
// Check layer read permissions
|
||||
void checkLayerReadPermissions( QgsMapLayer *layer ) const;
|
||||
|
||||
/** Initializes WMS layers and configures rendering.
|
||||
* \param layersList out: list with WMS layer names
|
||||
* \param stylesList out: list with WMS style names
|
||||
@ -170,9 +226,9 @@ namespace QgsWms
|
||||
QStringList layerSet( const QStringList &layersList, const QStringList &stylesList, const QgsCoordinateReferenceSystem &destCRS, double scaleDenominator = -1 ) const;
|
||||
|
||||
//! Record which symbols would be used if the map was in the current configuration of renderer. This is useful for content-based legend
|
||||
void runHitTest( const QgsMapSettings &mapSettings, HitTest &hitTest );
|
||||
void runHitTest( const QgsMapSettings &mapSettings, HitTest &hitTest ) const;
|
||||
//! Record which symbols within one layer would be rendered with the given renderer context
|
||||
void runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols, QgsRenderContext &context );
|
||||
void runHitTestLayer( QgsVectorLayer *vl, SymbolSet &usedSymbols, QgsRenderContext &context ) const;
|
||||
|
||||
//! Read legend parameter from the request or from the first print composer in the project
|
||||
void legendParameters( double &boxSpace, double &layerSpace, double &layerTitleSpace,
|
||||
@ -263,6 +319,9 @@ namespace QgsWms
|
||||
|
||||
const QgsServerSettings &mSettings;
|
||||
const QgsProject *mProject = nullptr;
|
||||
QgsWmsParameters mWmsParameters;
|
||||
QStringList mRestrictedLayers;
|
||||
QMap<QString, QgsMapLayer *> mNicknameLayers;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -55,6 +55,7 @@ RE_ATTRIBUTES = b'[^>\s]+=[^>\s]+'
|
||||
|
||||
|
||||
class QgsServerTestBase(unittest.TestCase):
|
||||
|
||||
"""Base class for QGIS server tests"""
|
||||
|
||||
# Set to True in child classes to re-generate reference files for this class
|
||||
@ -97,6 +98,9 @@ class QgsServerTestBase(unittest.TestCase):
|
||||
|
||||
d = unitTestDataPath('qgis_server_accesscontrol') + '/'
|
||||
self.projectPath = os.path.join(d, "project.qgs")
|
||||
self.projectAnnotationPath = os.path.join(d, "project_with_annotations.qgs")
|
||||
self.projectStatePath = os.path.join(d, "project_state.qgs")
|
||||
self.projectUseLayerIdsPath = os.path.join(d, "project_use_layerids.qgs")
|
||||
|
||||
# Clean env just to be sure
|
||||
env_vars = ['QUERY_STRING', 'QGIS_PROJECT_FILE']
|
||||
@ -187,14 +191,14 @@ class QgsServerTestBase(unittest.TestCase):
|
||||
self.server.handleRequest(request, response)
|
||||
headers = []
|
||||
rh = response.headers()
|
||||
rk = list(rh.keys())
|
||||
rk.sort()
|
||||
rk = sorted(rh.keys())
|
||||
for k in rk:
|
||||
headers.append(("%s: %s" % (k, rh[k])).encode('utf-8'))
|
||||
return b"\n".join(headers) + b"\n\n", bytes(response.body())
|
||||
|
||||
|
||||
class TestQgsServer(QgsServerTestBase):
|
||||
|
||||
"""Tests container"""
|
||||
|
||||
# Set to True to re-generate reference files for this class
|
||||
|
@ -142,8 +142,8 @@ class RestrictedAccessControl(QgsAccessControlFilter):
|
||||
if not self._active:
|
||||
return super(RestrictedAccessControl, self).authorizedLayerAttributes(layer, attributes)
|
||||
|
||||
if "colour" in attributes: # spellok
|
||||
attributes.remove("colour") # spellok
|
||||
if "color" in attributes: # spellok
|
||||
attributes.remove("color") # spellok
|
||||
return attributes
|
||||
|
||||
def allowToEdit(self, layer, feature):
|
||||
@ -169,8 +169,7 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
cls._server.handleRequest(request, response)
|
||||
headers = []
|
||||
rh = response.headers()
|
||||
rk = list(rh.keys())
|
||||
rk.sort()
|
||||
rk = sorted(rh.keys())
|
||||
for k in rk:
|
||||
headers.append(("%s: %s" % (k, rh[k])).encode('utf-8'))
|
||||
return b"\n".join(headers) + b"\n\n", bytes(response.body())
|
||||
@ -250,7 +249,7 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
str(response).find("<TreeName>Country</TreeName>") != -1,
|
||||
"No Country layer in GetProjectSettings\n%s" % response)
|
||||
self.assertTrue(
|
||||
str(response).find("<LayerDrawingOrder>Country_Labels,Country,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello,db_point</LayerDrawingOrder>") != -1,
|
||||
str(response).find("<LayerDrawingOrder>Country_Diagrams,Country_Labels,Country,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello,db_point</LayerDrawingOrder>") != -1,
|
||||
"LayerDrawingOrder in GetProjectSettings\n%s" % response)
|
||||
|
||||
response, headers = self._get_restricted(query_string)
|
||||
@ -261,7 +260,7 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
str(response).find("<TreeName>Country</TreeName>") != -1,
|
||||
"Country layer in GetProjectSettings\n%s" % response)
|
||||
self.assertTrue(
|
||||
str(response).find("<LayerDrawingOrder>Country_Labels,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello,db_point</LayerDrawingOrder>") != -1,
|
||||
str(response).find("<LayerDrawingOrder>Country_Diagrams,Country_Labels,dem,Hello_Filter_SubsetString,Hello_Project_SubsetString,Hello_SubsetString,Hello,db_point</LayerDrawingOrder>") != -1,
|
||||
"LayerDrawingOrder in GetProjectSettings\n%s" % response)
|
||||
|
||||
def test_wms_getprojectsettings(self):
|
||||
@ -451,7 +450,7 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
str(response).find("<qgs:pk>1</qgs:pk>") != -1,
|
||||
"No result in GetFeatureInfo\n%s" % response)
|
||||
self.assertTrue(
|
||||
str(response).find("<qgs:colour>red</qgs:colour>") != -1, # spellok
|
||||
str(response).find("<qgs:color>red</qgs:color>") != -1, # spellok
|
||||
"No color in result of GetFeatureInfo\n%s" % response)
|
||||
|
||||
response, headers = self._get_restricted(query_string)
|
||||
@ -459,10 +458,10 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
str(response).find("<qgs:pk>1</qgs:pk>") != -1,
|
||||
"No result in GetFeatureInfo\n%s" % response)
|
||||
self.assertFalse(
|
||||
str(response).find("<qgs:colour>red</qgs:colour>") != -1, # spellok
|
||||
str(response).find("<qgs:color>red</qgs:color>") != -1, # spellok
|
||||
"Unexpected color in result of GetFeatureInfo\n%s" % response)
|
||||
self.assertFalse(
|
||||
str(response).find("<qgs:colour>NULL</qgs:colour>") != -1, # spellok
|
||||
str(response).find("<qgs:color>NULL</qgs:color>") != -1, # spellok
|
||||
"Unexpected color NULL in result of GetFeatureInfo\n%s" % response)
|
||||
|
||||
def test_wms_getfeatureinfo_hello2(self):
|
||||
@ -603,7 +602,7 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
str(response).find("<qgs:pk>1</qgs:pk>") != -1,
|
||||
"No result in GetFeature\n%s" % response)
|
||||
self.assertTrue(
|
||||
str(response).find("<qgs:colour>red</qgs:colour>") != -1, # spellok
|
||||
str(response).find("<qgs:color>red</qgs:color>") != -1, # spellok
|
||||
"No color in result of GetFeature\n%s" % response)
|
||||
|
||||
response, headers = self._post_restricted(data)
|
||||
@ -611,10 +610,10 @@ class TestQgsServerAccessControl(unittest.TestCase):
|
||||
str(response).find("<qgs:pk>1</qgs:pk>") != -1,
|
||||
"No result in GetFeature\n%s" % response)
|
||||
self.assertFalse(
|
||||
str(response).find("<qgs:colour>red</qgs:colour>") != -1, # spellok
|
||||
str(response).find("<qgs:color>red</qgs:color>") != -1, # spellok
|
||||
"Unexpected color in result of GetFeature\n%s" % response)
|
||||
self.assertFalse(
|
||||
str(response).find("<qgs:colour>NULL</qgs:colour>") != -1, # spellok
|
||||
str(response).find("<qgs:color>NULL</qgs:color>") != -1, # spellok
|
||||
"Unexpected color NULL in result of GetFeature\n%s" % response)
|
||||
|
||||
def test_wfs_getfeature_hello2(self):
|
||||
|
@ -27,9 +27,12 @@ class TestQgsServerProjectUtils(unittest.TestCase):
|
||||
self.testdata_path = unitTestDataPath('qgis_server_project') + '/'
|
||||
|
||||
self.prj = QgsProject()
|
||||
prjPath = os.path.join(self.testdata_path, "project.qgs")
|
||||
self.prj.setFileName(prjPath)
|
||||
self.prj.read()
|
||||
self.prjPath = os.path.join(self.testdata_path, "project.qgs")
|
||||
self.prj.read(self.prjPath)
|
||||
|
||||
self.prj2 = QgsProject()
|
||||
self.prj2Path = os.path.join(self.testdata_path, "project2.qgs")
|
||||
self.prj2.read(self.prj2Path)
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
@ -43,6 +46,40 @@ class TestQgsServerProjectUtils(unittest.TestCase):
|
||||
self.assertEqual(QgsServerProjectUtils.wcsServiceUrl(self.prj), "my_wcs_advertised_url")
|
||||
self.assertEqual(QgsServerProjectUtils.wfsServiceUrl(self.prj), "my_wfs_advertised_url")
|
||||
|
||||
def test_wmsuselayerids(self):
|
||||
self.assertEqual(QgsServerProjectUtils.wmsUseLayerIds(self.prj), False)
|
||||
self.assertEqual(QgsServerProjectUtils.wmsUseLayerIds(self.prj2), True)
|
||||
|
||||
def test_wmsrestrictedlayers(self):
|
||||
# retrieve entry from project
|
||||
result = QgsServerProjectUtils.wmsRestrictedLayers(self.prj)
|
||||
expected = []
|
||||
expected.append('points') # layer
|
||||
expected.append('group1') # local group
|
||||
expected.append('groupEmbedded') # embedded group
|
||||
|
||||
self.assertListEqual(sorted(expected), sorted(result))
|
||||
|
||||
def test_wfslayersids(self):
|
||||
# retrieve entry from project
|
||||
result = QgsServerProjectUtils.wfsLayerIds(self.prj)
|
||||
|
||||
expected = []
|
||||
expected.append('multipoint20170309173637804') # from embedded group
|
||||
expected.append('points20170309173738552') # local layer
|
||||
expected.append('polys20170309173913723') # from local group
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_wcslayersids(self):
|
||||
# retrieve entry from project
|
||||
result = QgsServerProjectUtils.wcsLayerIds(self.prj)
|
||||
|
||||
expected = []
|
||||
expected.append('landsat20170313142548073')
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -39,6 +39,7 @@ RE_ATTRIBUTES = b'[^>\s]+=[^>\s]+'
|
||||
|
||||
|
||||
class TestQgsServerWMS(QgsServerTestBase):
|
||||
|
||||
"""QGIS Server WMS Tests"""
|
||||
|
||||
# Set to True to re-generate reference files for this class
|
||||
@ -175,6 +176,293 @@ class TestQgsServerWMS(QgsServerTestBase):
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Basic")
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,dem",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Basic2")
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectUseLayerIdsPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "country20131022151106556",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Basic3")
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,db_point",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Basic4")
|
||||
|
||||
def test_wms_getmap_invalid_parameters(self):
|
||||
# height should be an int
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "FOO",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"HEIGHT (\'FOO\') cannot be converted into int" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# width should be an int
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "FOO",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"WIDTH (\'FOO\') cannot be converted into int" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# bbox should be formatted like "double,double,double,double"
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"BBOX (\'-16817707,-4710778,5696513\') cannot be converted into a rectangle" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,FOO",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"BBOX (\'-16817707,-4710778,5696513,FOO\') cannot be converted into a rectangle" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# opacities should be a list of int
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"OPACITIES": "253,FOO",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"OPACITIES (\'253,FOO\') cannot be converted into a list of int" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# filters should be formatted like "layer0:filter0;layer1:filter1"
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857",
|
||||
"FILTER": "Country \"name\" = 'eurasia'"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"FILTER (\'Country \"name\" = \'eurasia\'\') is not properly formatted" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# selections should be formatted like "layer0:id0,id1;layer1:id0"
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"SRS": "EPSG:3857",
|
||||
"SELECTION": "Country=4"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"SELECTION (\'Country=4\') is not properly formatted" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# invalid highlight geometries
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Labels",
|
||||
"HIGHLIGHT_GEOM": "POLYGONN((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"HIGHLIGHT_GEOM (\'POLYGONN((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))\') cannot be converted into a list of geometries" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# invalid highlight label colors
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Labels",
|
||||
"HIGHLIGHT_LABELCOLOR": "%2300230000;%230023000",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"HIGHLIGHT_LABELCOLOR (\'#00230000;#0023000\') cannot be converted into a list of colors" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# invalid list of label sizes
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Labels",
|
||||
"HIGHLIGHT_LABELSIZE": "16;17;FOO",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"HIGHLIGHT_LABELSIZE (\'16;17;FOO\') cannot be converted into a list of int" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# invalid list of label buffer size
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Labels",
|
||||
"HIGHLIGHT_LABELBUFFERSIZE": "1.5;2;FF",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"HIGHLIGHT_LABELBUFFERSIZE (\'1.5;2;FF\') cannot be converted into a list of float" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
# invalid buffer color
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Labels",
|
||||
"HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00;%232300FF0",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"HIGHLIGHT_LABELBUFFERCOLOR (\'#2300FF00;#2300FF0\') cannot be converted into a list of colors" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
def test_wms_getmap_transparent(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
@ -400,6 +688,43 @@ class TestQgsServerWMS(QgsServerTestBase):
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Filter")
|
||||
|
||||
# try to display a feature yet filtered by the project
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectStatePath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857",
|
||||
"FILTER": "Country:\"name\" = 'africa'"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Filter2")
|
||||
|
||||
# display all features to check that initial filter is restored
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectStatePath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857",
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Filter3")
|
||||
|
||||
def test_wms_getmap_selection(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
@ -419,6 +744,24 @@ class TestQgsServerWMS(QgsServerTestBase):
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Selection")
|
||||
|
||||
def test_wms_getmap_diagrams(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Diagrams,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Diagrams")
|
||||
|
||||
def test_wms_getmap_opacities(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
@ -438,6 +781,121 @@ class TestQgsServerWMS(QgsServerTestBase):
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Opacities")
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello,dem",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857",
|
||||
"OPACITIES": "125,50,150"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Opacities2")
|
||||
|
||||
def test_wms_getmap_highlight(self):
|
||||
# highlight layer with color separated from sld
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country_Labels",
|
||||
"HIGHLIGHT_GEOM": "POLYGON((-15000000 10000000, -15000000 6110620, 2500000 6110620, 2500000 10000000, -15000000 10000000))",
|
||||
"HIGHLIGHT_SYMBOL": "<StyledLayerDescriptor><UserStyle><Name>Highlight</Name><FeatureTypeStyle><Rule><Name>Symbol</Name><LineSymbolizer><Stroke><SvgParameter name=\"stroke\">%23ea1173</SvgParameter><SvgParameter name=\"stroke-opacity\">1</SvgParameter><SvgParameter name=\"stroke-width\">1.6</SvgParameter></Stroke></LineSymbolizer></Rule></FeatureTypeStyle></UserStyle></StyledLayerDescriptor>",
|
||||
"HIGHLIGHT_LABELSTRING": "Highlight Layer!",
|
||||
"HIGHLIGHT_LABELSIZE": "16",
|
||||
"HIGHLIGHT_LABELCOLOR": "%2300FF0000",
|
||||
"HIGHLIGHT_LABELBUFFERCOLOR": "%232300FF00",
|
||||
"HIGHLIGHT_LABELBUFFERSIZE": "1.5",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Highlight")
|
||||
|
||||
def test_wms_getmap_annotations(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectAnnotationPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,Hello",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_Annotations")
|
||||
|
||||
def test_wms_getmap_sld(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,db_point",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_SLDRestored")
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"REQUEST": "GetMap",
|
||||
"VERSION": "1.1.1",
|
||||
"SERVICE": "WMS",
|
||||
"SLD": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><StyledLayerDescriptor xmlns=\"http://www.opengis.net/sld\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:ogc=\"http://www.opengis.net/ogc\" xsi:schemaLocation=\"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/StyledLayerDescriptor.xsd\" version=\"1.1.0\" xmlns:se=\"http://www.opengis.net/se\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"> <NamedLayer> <se:Name>db_point</se:Name> <UserStyle> <se:Name>db_point_style</se:Name> <se:FeatureTypeStyle> <se:Rule> <se:Name>Single symbol</se:Name> <ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\"> <ogc:PropertyIsEqualTo> <ogc:PropertyName>gid</ogc:PropertyName> <ogc:Literal>1</ogc:Literal> </ogc:PropertyIsEqualTo> </ogc:Filter> <se:PointSymbolizer uom=\"http://www.opengeospatial.org/se/units/metre\"> <se:Graphic> <se:Mark> <se:WellKnownName>square</se:WellKnownName> <se:Fill> <se:SvgParameter name=\"fill\">5e86a1</se:SvgParameter> </se:Fill> <se:Stroke> <se:SvgParameter name=\"stroke\">000000</se:SvgParameter> </se:Stroke> </se:Mark> <se:Size>0.007</se:Size> </se:Graphic> </se:PointSymbolizer> </se:Rule> </se:FeatureTypeStyle> </UserStyle> </NamedLayer> </StyledLayerDescriptor>",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"WIDTH": "500",
|
||||
"HEIGHT": "500",
|
||||
"LAYERS": "db_point",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_SLD")
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
"SERVICE": "WMS",
|
||||
"VERSION": "1.1.1",
|
||||
"REQUEST": "GetMap",
|
||||
"LAYERS": "Country,db_point",
|
||||
"STYLES": "",
|
||||
"FORMAT": "image/png",
|
||||
"BBOX": "-16817707,-4710778,5696513,14587125",
|
||||
"HEIGHT": "500",
|
||||
"WIDTH": "500",
|
||||
"CRS": "EPSG:3857"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMS_GetMap_SLDRestored")
|
||||
|
||||
def test_wms_getprint_basic(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectPath),
|
||||
|
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Annotations/WMS_GetMap_Annotations.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Annotations/WMS_GetMap_Annotations_mask.png
vendored
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Basic2/WMS_GetMap_Basic2.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Basic2/WMS_GetMap_Basic2_mask.png
vendored
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Basic3/WMS_GetMap_Basic3.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Basic3/WMS_GetMap_Basic3_mask.png
vendored
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Basic4/WMS_GetMap_Basic4.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Basic4/WMS_GetMap_Basic4_mask.png
vendored
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Diagrams/WMS_GetMap_Diagrams.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Diagrams/WMS_GetMap_Diagrams_mask.png
vendored
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter2/WMS_GetMap_Filter2.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter2/WMS_GetMap_Filter2_mask.png
vendored
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter3/WMS_GetMap_Filter3.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Filter3/WMS_GetMap_Filter3_mask.png
vendored
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Highlight/WMS_GetMap_Highlight.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Highlight/WMS_GetMap_Highlight_mask.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_Opacities2/WMS_GetMap_Opacities2.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_SLD/WMS_GetMap_SLD.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_SLDRestored/WMS_GetMap_SLDRestored.png
vendored
Normal file
After Width: | Height: | Size: 979 KiB |
BIN
tests/testdata/control_images/qgis_server/WMS_GetMap_SLDRestored/WMS_GetMap_SLDRestored_mask.png
vendored
Normal file
After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 3.8 KiB |
1894
tests/testdata/qgis_server_accesscontrol/project.qgs
vendored
3850
tests/testdata/qgis_server_accesscontrol/project_state.qgs
vendored
Normal file
4199
tests/testdata/qgis_server_accesscontrol/project_use_layerids.qgs
vendored
Normal file
3935
tests/testdata/qgis_server_accesscontrol/project_with_annotations.qgs
vendored
Normal file
1206
tests/testdata/qgis_server_project/project.qgs
vendored
269
tests/testdata/qgis_server_project/project2.qgs
vendored
Normal file
@ -0,0 +1,269 @@
|
||||
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||
<qgis version="2.99.0-Master" projectname="">
|
||||
<title></title>
|
||||
<autotransaction active="0"/>
|
||||
<evaluateDefaultValues active="0"/>
|
||||
<layer-tree-group checked="Qt::Checked" expanded="1" name="">
|
||||
<customproperties/>
|
||||
<layer-tree-group checked="Qt::Checked" expanded="1" name="groupEmbedded">
|
||||
<customproperties/>
|
||||
<layer-tree-layer checked="Qt::Checked" expanded="1" id="multipoint20170309173637804" name="multipoint">
|
||||
<customproperties/>
|
||||
</layer-tree-layer>
|
||||
</layer-tree-group>
|
||||
</layer-tree-group>
|
||||
<snapping-settings enabled="0" type="1" unit="2" tolerance="0" mode="2" intersection-snapping="0">
|
||||
<individual-layer-settings>
|
||||
<layer-setting enabled="0" type="1" units="2" tolerance="0" id="multipoint20170309173637804"/>
|
||||
</individual-layer-settings>
|
||||
</snapping-settings>
|
||||
<relations/>
|
||||
<mapcanvas>
|
||||
<units>degrees</units>
|
||||
<extent>
|
||||
<xmin>-118.30669239248942404</xmin>
|
||||
<ymin>22.77273630404421567</ymin>
|
||||
<xmax>-81.58695972535105057</xmax>
|
||||
<ymax>46.72277089440163422</ymax>
|
||||
</extent>
|
||||
<rotation>0</rotation>
|
||||
<destinationsrs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</destinationsrs>
|
||||
<rendermaptile>0</rendermaptile>
|
||||
<layer_coordinate_transform_info>
|
||||
<layer_coordinate_transform layerid="multipoint20170309173637804" srcDatumTransform="-1" destDatumTransform="-1" srcAuthId="EPSG:4326" destAuthId="EPSG:4326"/>
|
||||
<layer_coordinate_transform layerid="polys20170309163723865" srcDatumTransform="-1" destDatumTransform="-1" srcAuthId="EPSG:4326" destAuthId="EPSG:4326"/>
|
||||
<layer_coordinate_transform layerid="points20170309163100401" srcDatumTransform="-1" destDatumTransform="-1" srcAuthId="EPSG:4326" destAuthId="EPSG:4326"/>
|
||||
<layer_coordinate_transform layerid="lines20170309163100396" srcDatumTransform="-1" destDatumTransform="-1" srcAuthId="EPSG:4326" destAuthId="EPSG:4326"/>
|
||||
</layer_coordinate_transform_info>
|
||||
</mapcanvas>
|
||||
<layer-tree-canvas>
|
||||
<custom-order enabled="0">
|
||||
<item>multipoint20170309173637804</item>
|
||||
</custom-order>
|
||||
</layer-tree-canvas>
|
||||
<legend updateDrawingOrder="true">
|
||||
<legendgroup open="true" checked="Qt::Checked" name="groupEmbedded">
|
||||
<legendlayer open="true" checked="Qt::Checked" showFeatureCount="0" drawingOrder="-1" name="multipoint">
|
||||
<filegroup open="true" hidden="false">
|
||||
<legendlayerfile layerid="multipoint20170309173637804" visible="1" isInOverview="0"/>
|
||||
</filegroup>
|
||||
</legendlayer>
|
||||
</legendgroup>
|
||||
</legend>
|
||||
<projectlayers>
|
||||
<maplayer autoRefreshTime="0" geometry="Point" simplifyMaxScale="1" simplifyDrawingTol="1" autoRefreshEnabled="0" simplifyDrawingHints="1" minimumScale="0" readOnly="0" type="vector" maximumScale="1e+8" simplifyAlgorithm="0" simplifyLocal="1" hasScaleBasedVisibilityFlag="0">
|
||||
<extent>
|
||||
<xmin>-117.43241304327183627</xmin>
|
||||
<ymin>23.34297522286225401</ymin>
|
||||
<xmax>-82.46123907456862412</xmax>
|
||||
<ymax>46.15253197558359943</ymax>
|
||||
</extent>
|
||||
<id>multipoint20170309173637804</id>
|
||||
<datasource>../multipoint.shp</datasource>
|
||||
<keywordList>
|
||||
<value></value>
|
||||
</keywordList>
|
||||
<layername>multipoint</layername>
|
||||
<srs>
|
||||
<spatialrefsys>
|
||||
<proj4>+proj=longlat +datum=WGS84 +no_defs</proj4>
|
||||
<srsid>3452</srsid>
|
||||
<srid>4326</srid>
|
||||
<authid>EPSG:4326</authid>
|
||||
<description>WGS 84</description>
|
||||
<projectionacronym>longlat</projectionacronym>
|
||||
<ellipsoidacronym>WGS84</ellipsoidacronym>
|
||||
<geographicflag>true</geographicflag>
|
||||
</spatialrefsys>
|
||||
</srs>
|
||||
<provider encoding="UTF-8">ogr</provider>
|
||||
<vectorjoins/>
|
||||
<layerDependencies/>
|
||||
<dataDependencies/>
|
||||
<expressionfields/>
|
||||
<map-layer-style-manager current="">
|
||||
<map-layer-style name=""/>
|
||||
</map-layer-style-manager>
|
||||
<renderer-v2 enableorderby="0" forceraster="0" symbollevels="0" type="singleSymbol">
|
||||
<symbols>
|
||||
<symbol clip_to_extent="1" type="marker" alpha="1" name="0">
|
||||
<layer enabled="1" pass="0" class="SimpleMarker" locked="0">
|
||||
<prop v="0" k="angle"/>
|
||||
<prop v="124,179,68,255" k="color"/>
|
||||
<prop v="1" k="horizontal_anchor_point"/>
|
||||
<prop v="bevel" k="joinstyle"/>
|
||||
<prop v="circle" k="name"/>
|
||||
<prop v="0,0" k="offset"/>
|
||||
<prop v="0,0,0,0,0,0" k="offset_map_unit_scale"/>
|
||||
<prop v="MM" k="offset_unit"/>
|
||||
<prop v="0,0,0,255" k="outline_color"/>
|
||||
<prop v="solid" k="outline_style"/>
|
||||
<prop v="0" k="outline_width"/>
|
||||
<prop v="0,0,0,0,0,0" k="outline_width_map_unit_scale"/>
|
||||
<prop v="MM" k="outline_width_unit"/>
|
||||
<prop v="diameter" k="scale_method"/>
|
||||
<prop v="2" k="size"/>
|
||||
<prop v="0,0,0,0,0,0" k="size_map_unit_scale"/>
|
||||
<prop v="MM" k="size_unit"/>
|
||||
<prop v="1" k="vertical_anchor_point"/>
|
||||
<data_defined_properties>
|
||||
<Option type="Map">
|
||||
<Option value="" type="QString" name="name"/>
|
||||
<Option name="properties"/>
|
||||
<Option value="collection" type="QString" name="type"/>
|
||||
</Option>
|
||||
</data_defined_properties>
|
||||
</layer>
|
||||
</symbol>
|
||||
</symbols>
|
||||
<rotation/>
|
||||
<sizescale/>
|
||||
</renderer-v2>
|
||||
<labeling type="simple"/>
|
||||
<customproperties/>
|
||||
<blendMode>0</blendMode>
|
||||
<featureBlendMode>0</featureBlendMode>
|
||||
<layerTransparency>0</layerTransparency>
|
||||
<fieldConfiguration>
|
||||
<field name="Id">
|
||||
<editWidget type="">
|
||||
<config>
|
||||
<Option/>
|
||||
</config>
|
||||
</editWidget>
|
||||
</field>
|
||||
</fieldConfiguration>
|
||||
<annotationform></annotationform>
|
||||
<aliases>
|
||||
<alias index="0" field="Id" name=""/>
|
||||
</aliases>
|
||||
<excludeAttributesWMS/>
|
||||
<excludeAttributesWFS/>
|
||||
<defaults>
|
||||
<default expression="" field="Id"/>
|
||||
</defaults>
|
||||
<constraints>
|
||||
<constraint exp_strength="0" notnull_strength="0" constraints="0" unique_strength="0" field="Id"/>
|
||||
</constraints>
|
||||
<constraintExpressions>
|
||||
<constraint exp="" desc="" field="Id"/>
|
||||
</constraintExpressions>
|
||||
<attributeactions>
|
||||
<defaultAction value="{00000000-0000-0000-0000-000000000000}" key="Canvas"/>
|
||||
</attributeactions>
|
||||
<attributetableconfig actionWidgetStyle="dropDown" sortOrder="0" sortExpression="">
|
||||
<columns/>
|
||||
</attributetableconfig>
|
||||
<editform></editform>
|
||||
<editforminit/>
|
||||
<editforminitcodesource>0</editforminitcodesource>
|
||||
<editforminitfilepath></editforminitfilepath>
|
||||
<editforminitcode><![CDATA[]]></editforminitcode>
|
||||
<featformsuppress>0</featformsuppress>
|
||||
<editorlayout>generatedlayout</editorlayout>
|
||||
<widgets/>
|
||||
<conditionalstyles>
|
||||
<rowstyles/>
|
||||
<fieldstyles/>
|
||||
</conditionalstyles>
|
||||
<expressionfields/>
|
||||
<previewExpression></previewExpression>
|
||||
<mapTip></mapTip>
|
||||
</maplayer>
|
||||
</projectlayers>
|
||||
<properties>
|
||||
<WMSContactPhone type="QString"></WMSContactPhone>
|
||||
<WCSLayers type="QStringList"/>
|
||||
<WMSContactPerson type="QString"></WMSContactPerson>
|
||||
<WFSTLayers>
|
||||
<Delete type="QStringList"/>
|
||||
<Insert type="QStringList"/>
|
||||
<Update type="QStringList"/>
|
||||
</WFSTLayers>
|
||||
<WMSRequestDefinedDataSources type="bool">false</WMSRequestDefinedDataSources>
|
||||
<WMSServiceCapabilities type="bool">false</WMSServiceCapabilities>
|
||||
<Measurement>
|
||||
<DistanceUnits type="QString">meters</DistanceUnits>
|
||||
<AreaUnits type="QString">m2</AreaUnits>
|
||||
</Measurement>
|
||||
<WMSContactPosition type="QString"></WMSContactPosition>
|
||||
<WMSServiceAbstract type="QString"></WMSServiceAbstract>
|
||||
<WCSUrl type="QString"></WCSUrl>
|
||||
<WMSFees type="QString">conditions unknown</WMSFees>
|
||||
<Gui>
|
||||
<SelectionColorAlphaPart type="int">255</SelectionColorAlphaPart>
|
||||
<SelectionColorRedPart type="int">255</SelectionColorRedPart>
|
||||
<SelectionColorBluePart type="int">0</SelectionColorBluePart>
|
||||
<CanvasColorBluePart type="int">255</CanvasColorBluePart>
|
||||
<CanvasColorGreenPart type="int">255</CanvasColorGreenPart>
|
||||
<CanvasColorRedPart type="int">255</CanvasColorRedPart>
|
||||
<SelectionColorGreenPart type="int">255</SelectionColorGreenPart>
|
||||
</Gui>
|
||||
<WMSOnlineResource type="QString"></WMSOnlineResource>
|
||||
<WMSPrecision type="QString">8</WMSPrecision>
|
||||
<WMSAddWktGeometry type="bool">false</WMSAddWktGeometry>
|
||||
<Legend>
|
||||
<filterByMap type="bool">false</filterByMap>
|
||||
</Legend>
|
||||
<WMSAccessConstraints type="QString">None</WMSAccessConstraints>
|
||||
<WMSRestrictedComposers type="QStringList"/>
|
||||
<Identify>
|
||||
<disabledLayers type="QStringList"/>
|
||||
</Identify>
|
||||
<WMSContactMail type="QString"></WMSContactMail>
|
||||
<WMSImageQuality type="int">90</WMSImageQuality>
|
||||
<WMSContactOrganization type="QString"></WMSContactOrganization>
|
||||
<WMSUrl type="QString"></WMSUrl>
|
||||
<WMSUseLayerIDs type="bool">true</WMSUseLayerIDs>
|
||||
<WMSServiceTitle type="QString"></WMSServiceTitle>
|
||||
<WFSLayers type="QStringList"/>
|
||||
<PositionPrecision>
|
||||
<Automatic type="bool">true</Automatic>
|
||||
<DegreeFormat type="QString">MU</DegreeFormat>
|
||||
<DecimalPlaces type="int">2</DecimalPlaces>
|
||||
</PositionPrecision>
|
||||
<WFSUrl type="QString"></WFSUrl>
|
||||
<Paths>
|
||||
<Absolute type="bool">false</Absolute>
|
||||
</Paths>
|
||||
<WMSKeywordList type="QStringList">
|
||||
<value></value>
|
||||
</WMSKeywordList>
|
||||
<SpatialRefSys>
|
||||
<ProjectCRSID type="int">3452</ProjectCRSID>
|
||||
<ProjectCrs type="QString">EPSG:4326</ProjectCrs>
|
||||
<ProjectCRSProj4String type="QString">+proj=longlat +datum=WGS84 +no_defs</ProjectCRSProj4String>
|
||||
</SpatialRefSys>
|
||||
<WMSSegmentizeFeatureInfoGeometry type="bool">false</WMSSegmentizeFeatureInfoGeometry>
|
||||
<Macros>
|
||||
<pythonCode type="QString"></pythonCode>
|
||||
</Macros>
|
||||
<DefaultStyles>
|
||||
<RandomColors type="bool">true</RandomColors>
|
||||
<Fill type="QString"></Fill>
|
||||
<ColorRamp type="QString"></ColorRamp>
|
||||
<Line type="QString"></Line>
|
||||
<Marker type="QString"></Marker>
|
||||
<AlphaInt type="int">255</AlphaInt>
|
||||
</DefaultStyles>
|
||||
<Measure>
|
||||
<Ellipsoid type="QString">NONE</Ellipsoid>
|
||||
</Measure>
|
||||
<WMSRestrictedLayers type="QStringList">
|
||||
<value>multipoint</value>
|
||||
</WMSRestrictedLayers>
|
||||
</properties>
|
||||
<visibility-presets/>
|
||||
<Annotations/>
|
||||
</qgis>
|