Merge pull request #7514 from rldhont/server-cache-manager
[Server][Feature][needs-docs] Server cache manager and WMTS service
133
python/server/auto_generated/qgsservercachefilter.sip.in
Normal file
@ -0,0 +1,133 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsservercachefilter.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsServerCacheFilter
|
||||
{
|
||||
%Docstring
|
||||
Class defining cache interface for QGIS Server plugins.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsservercachefilter.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsServerCacheFilter( const QgsServerInterface *serverInterface );
|
||||
%Docstring
|
||||
Constructor
|
||||
QgsServerInterface passed to plugins constructors
|
||||
and must be passed to QgsServerCacheFilter instances.
|
||||
%End
|
||||
|
||||
virtual ~QgsServerCacheFilter();
|
||||
|
||||
virtual QByteArray getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
%Docstring
|
||||
Returns cached document (or 0 if document not in cache) like capabilities
|
||||
|
||||
:param project: the project used to generate the document to provide path
|
||||
:param request: the request used to generate the document to provider parameters or data
|
||||
:param key: the key provided by the access control to identify different documents for the same request
|
||||
|
||||
:return: QByteArray of the cached document or an empty one if no corresponding document found
|
||||
%End
|
||||
|
||||
virtual bool setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
%Docstring
|
||||
Updates or inserts the document in cache like capabilities
|
||||
|
||||
:param doc: the document to cache
|
||||
:param project: the project used to generate the document to provide path
|
||||
:param request: the request used to generate the document to provider parameters or data
|
||||
:param key: the key provided by the access control to identify different documents for the same request
|
||||
|
||||
:return: true if the document has been cached
|
||||
%End
|
||||
|
||||
virtual bool deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
%Docstring
|
||||
Deletes the cached document
|
||||
|
||||
:param project: the project used to generate the document to provide path
|
||||
:param request: the request used to generate the document to provider parameters or data
|
||||
:param key: the key provided by the access control to identify different documents for the same request
|
||||
|
||||
:return: true if the document has been deleted
|
||||
%End
|
||||
|
||||
virtual bool deleteCachedDocuments( const QgsProject *project ) const;
|
||||
%Docstring
|
||||
Deletes all cached documents for a QGIS project
|
||||
|
||||
:param project: the project used to generate the documents to provide path
|
||||
|
||||
:return: true if the documents have been deleted
|
||||
%End
|
||||
|
||||
virtual QByteArray getCachedImage( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
%Docstring
|
||||
Returns cached image (or 0 if document not in cache) like tiles
|
||||
|
||||
:param project: the project used to generate the image to provide path
|
||||
:param request: the request used to generate the image to provider parameters or data
|
||||
:param key: the key provided by the access control to identify different images for the same request
|
||||
|
||||
:return: QByteArray of the cached image or an empty one if no corresponding image found
|
||||
%End
|
||||
|
||||
virtual bool setCachedImage( const QByteArray *img, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
%Docstring
|
||||
Updates or inserts the image in cache like tiles
|
||||
|
||||
:param img: the document to cache
|
||||
:param project: the project used to generate the image to provide path
|
||||
:param request: the request used to generate the image to provider parameters or data
|
||||
:param key: the key provided by the access control to identify different images for the same request
|
||||
|
||||
:return: true if the image has been cached
|
||||
%End
|
||||
|
||||
virtual bool deleteCachedImage( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
%Docstring
|
||||
Deletes the cached image
|
||||
|
||||
:param project: the project used to generate the image to provide path
|
||||
:param request: the request used to generate the image to provider parameters or data
|
||||
:param key: the key provided by the access control to identify different images for the same request
|
||||
|
||||
:return: true if the image has been deleted
|
||||
%End
|
||||
|
||||
virtual bool deleteCachedImages( const QgsProject *project ) const;
|
||||
%Docstring
|
||||
Deletes all cached images for a QGIS project
|
||||
|
||||
:param project: the project used to generate the images to provide path
|
||||
|
||||
:return: true if the images have been deleted
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
typedef QMultiMap<int, QgsServerCacheFilter *> QgsServerCacheFilterMap;
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsservercachefilter.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
143
python/server/auto_generated/qgsservercachemanager.sip.in
Normal file
@ -0,0 +1,143 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsservercachemanager.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsServerCacheManager
|
||||
{
|
||||
%Docstring
|
||||
A helper class that centralizes caches accesses given by all the server cache filter plugins.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsservercachemanager.h"
|
||||
#include "qgsservercachefilter.h"
|
||||
%End
|
||||
public:
|
||||
QgsServerCacheManager();
|
||||
%Docstring
|
||||
Constructor
|
||||
%End
|
||||
|
||||
QgsServerCacheManager( const QgsServerCacheManager © );
|
||||
%Docstring
|
||||
Copy constructor
|
||||
%End
|
||||
|
||||
|
||||
~QgsServerCacheManager();
|
||||
|
||||
bool getCachedDocument( QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
%Docstring
|
||||
Returns cached document (or 0 if document not in cache) like capabilities
|
||||
|
||||
:param doc: the document to update by content found in cache
|
||||
:param project: the project used to generate the document to provide path
|
||||
:param request: the request used to generate the document to provider parameters or data
|
||||
:param accessControl: the access control to identify different documents for the same request provided by server interface
|
||||
|
||||
:return: true if the document has been found in cache and the document's content set
|
||||
%End
|
||||
|
||||
bool setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
%Docstring
|
||||
Updates or inserts the document in cache like capabilities
|
||||
|
||||
:param doc: the document to cache
|
||||
:param project: the project used to generate the document to provide path
|
||||
:param request: the request used to generate the document to provider parameters or data
|
||||
:param accessControl: the access control to identify different documents for the same request provided by server interface
|
||||
|
||||
:return: true if the document has been cached
|
||||
%End
|
||||
|
||||
bool deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
%Docstring
|
||||
Deletes the cached document
|
||||
|
||||
:param project: the project used to generate the document to provide path
|
||||
:param request: the request used to generate the document to provider parameters or data
|
||||
:param accessControl: the access control to identify different documents for the same request provided by server interface
|
||||
|
||||
:return: true if the document has been deleted
|
||||
%End
|
||||
|
||||
bool deleteCachedDocuments( const QgsProject *project ) const;
|
||||
%Docstring
|
||||
Deletes all cached documents for a QGIS project
|
||||
|
||||
:param project: the project used to generate the document to provide path
|
||||
|
||||
:return: true if the document has been deleted
|
||||
%End
|
||||
|
||||
QByteArray getCachedImage( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
%Docstring
|
||||
Returns cached image (or 0 if image not in cache) like tiles
|
||||
|
||||
:param project: the project used to generate the image to provide path
|
||||
:param request: the request used to generate the image to provider parameters or data
|
||||
:param accessControl: the access control to identify different documents for the same request provided by server interface
|
||||
|
||||
:return: the cached image or 0 if no corresponding image found
|
||||
%End
|
||||
|
||||
bool setCachedImage( const QByteArray *img, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
%Docstring
|
||||
Updates or inserts the image in cache like tiles
|
||||
|
||||
:param img: the image to cache
|
||||
:param project: the project used to generate the image to provide path
|
||||
:param request: the request used to generate the image to provider parameters or data
|
||||
:param accessControl: the access control to identify different documents for the same request provided by server interface
|
||||
|
||||
:return: true if the image has been cached
|
||||
%End
|
||||
|
||||
bool deleteCachedImage( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
%Docstring
|
||||
Deletes the cached image
|
||||
|
||||
:param project: the project used to generate the image to provide path
|
||||
:param request: the request used to generate the image to provider parameters or data
|
||||
:param accessControl: the access control to identify different documents for the same request provided by server interface
|
||||
|
||||
:return: true if the image has been deleted
|
||||
%End
|
||||
|
||||
bool deleteCachedImages( const QgsProject *project ) const;
|
||||
%Docstring
|
||||
Deletes all cached images for a QGIS project
|
||||
|
||||
:param project: the project used to generate the images to provide path
|
||||
|
||||
:return: true if the images have been deleted
|
||||
%End
|
||||
|
||||
void registerServerCache( QgsServerCacheFilter *serverCache, int priority = 0 );
|
||||
%Docstring
|
||||
Register a server cache filter
|
||||
|
||||
:param serverCache: the server cache to add
|
||||
:param priority: the priority used to define the order
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/server/qgsservercachemanager.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -83,6 +83,23 @@ Register an access control filter
|
||||
virtual QgsAccessControl *accessControls() const = 0;
|
||||
%Docstring
|
||||
Gets the registered access control filters
|
||||
%End
|
||||
|
||||
virtual void registerServerCache( QgsServerCacheFilter *serverCache /Transfer/, int priority = 0 ) = 0;
|
||||
%Docstring
|
||||
Register a server cache filter
|
||||
|
||||
:param serverCache: the server cache to register
|
||||
:param priority: the priority used to order them
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
virtual QgsServerCacheManager *cacheManager() const = 0;
|
||||
%Docstring
|
||||
Gets the registered server cache filters
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
|
||||
virtual QString getEnv( const QString &name ) const = 0;
|
||||
|
@ -413,6 +413,17 @@ Returns the Layer ids list defined in a QGIS project as published in WCS.
|
||||
:param project: the QGIS project
|
||||
|
||||
:return: the Layer ids list.
|
||||
%End
|
||||
|
||||
QString wmtsServiceUrl( const QgsProject &project );
|
||||
%Docstring
|
||||
Returns the WMTS service url defined in a QGIS project.
|
||||
|
||||
:param project: the QGIS project
|
||||
|
||||
:return: url if defined in project, an empty string otherwise.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
%End
|
||||
};
|
||||
|
||||
|
@ -29,3 +29,9 @@
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include auto_generated/qgsaccesscontrol.sip
|
||||
%End
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include auto_generated/qgsservercachefilter.sip
|
||||
%End
|
||||
%If ( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
%Include auto_generated/qgsservercachemanager.sip
|
||||
%End
|
||||
|
@ -56,6 +56,7 @@
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgsunittypes.h"
|
||||
#include "qgstablewidgetitem.h"
|
||||
#include "qgstreewidgetitem.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgsprintlayout.h"
|
||||
#include "qgsmetadatawidget.h"
|
||||
@ -662,6 +663,49 @@ QgsProjectProperties::QgsProjectProperties( QgsMapCanvas *mapCanvas, QWidget *pa
|
||||
mWMSImageQualitySpinBox->setValue( imageQuality );
|
||||
}
|
||||
|
||||
mWMTSUrlLineEdit->setText( QgsProject::instance()->readEntry( QStringLiteral( "WMTSUrl" ), QStringLiteral( "/" ), QLatin1String( "" ) ) );
|
||||
mWMTSMinScaleLineEdit->setValue( QgsProject::instance()->readNumEntry( QStringLiteral( "WMTSMinScale" ), QStringLiteral( "/" ), 5000 ) );
|
||||
|
||||
bool wmtsProject = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Project" ) );
|
||||
bool wmtsPngProject = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Project" ) );
|
||||
bool wmtsJpegProject = QgsProject::instance()->readBoolEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Project" ) );
|
||||
QStringList wmtsGroupNameList = QgsProject::instance()->readListEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Group" ) );
|
||||
QStringList wmtsPngGroupNameList = QgsProject::instance()->readListEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Group" ) );
|
||||
QStringList wmtsJpegGroupNameList = QgsProject::instance()->readListEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Group" ) );
|
||||
QStringList wmtsLayerIdList = QgsProject::instance()->readListEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Layer" ) );
|
||||
QStringList wmtsPngLayerIdList = QgsProject::instance()->readListEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Layer" ) );
|
||||
QStringList wmtsJpegLayerIdList = QgsProject::instance()->readListEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Layer" ) );
|
||||
|
||||
QgsTreeWidgetItem *projItem = new QgsTreeWidgetItem( QStringList() << QStringLiteral( "Project" ) );
|
||||
projItem->setFlags( projItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
projItem->setCheckState( 1, wmtsProject ? Qt::Checked : Qt::Unchecked );
|
||||
projItem->setCheckState( 2, wmtsPngProject ? Qt::Checked : Qt::Unchecked );
|
||||
projItem->setCheckState( 3, wmtsJpegProject ? Qt::Checked : Qt::Unchecked );
|
||||
projItem->setData( 0, Qt::UserRole, QStringLiteral( "project" ) );
|
||||
twWmtsLayers->addTopLevelItem( projItem );
|
||||
populateWmtsTree( QgsProject::instance()->layerTreeRoot(), projItem );
|
||||
projItem->setExpanded( true );
|
||||
twWmtsLayers->header()->resizeSections( QHeaderView::ResizeToContents );
|
||||
for ( QTreeWidgetItem *item : twWmtsLayers->findItems( QString(), Qt::MatchContains | Qt::MatchRecursive, 1 ) )
|
||||
{
|
||||
QString itemType = item->data( 0, Qt::UserRole ).toString();
|
||||
if ( itemType == QLatin1String( "group" ) )
|
||||
{
|
||||
QString gName = item->data( 0, Qt::UserRole + 1 ).toString();
|
||||
item->setCheckState( 1, wmtsGroupNameList.contains( gName ) ? Qt::Checked : Qt::Unchecked );
|
||||
item->setCheckState( 2, wmtsPngGroupNameList.contains( gName ) ? Qt::Checked : Qt::Unchecked );
|
||||
item->setCheckState( 3, wmtsJpegGroupNameList.contains( gName ) ? Qt::Checked : Qt::Unchecked );
|
||||
}
|
||||
else if ( itemType == QLatin1String( "layer" ) )
|
||||
{
|
||||
QString lId = item->data( 0, Qt::UserRole + 1 ).toString();
|
||||
item->setCheckState( 1, wmtsLayerIdList.contains( lId ) ? Qt::Checked : Qt::Unchecked );
|
||||
item->setCheckState( 2, wmtsPngLayerIdList.contains( lId ) ? Qt::Checked : Qt::Unchecked );
|
||||
item->setCheckState( 3, wmtsJpegLayerIdList.contains( lId ) ? Qt::Checked : Qt::Unchecked );
|
||||
}
|
||||
}
|
||||
connect( twWmtsLayers, &QTreeWidget::itemChanged, this, &QgsProjectProperties::twWmtsItemChanged );
|
||||
|
||||
mWFSUrlLineEdit->setText( QgsProject::instance()->readEntry( QStringLiteral( "WFSUrl" ), QStringLiteral( "/" ), QLatin1String( "" ) ) );
|
||||
QStringList wfsLayerIdList = QgsProject::instance()->readListEntry( QStringLiteral( "WFSLayers" ), QStringLiteral( "/" ) );
|
||||
QStringList wfstUpdateLayerIdList = QgsProject::instance()->readListEntry( QStringLiteral( "WFSTLayers" ), QStringLiteral( "Update" ) );
|
||||
@ -1222,6 +1266,58 @@ void QgsProjectProperties::apply()
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMSImageQuality" ), QStringLiteral( "/" ), imageQualityValue );
|
||||
}
|
||||
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSUrl" ), QStringLiteral( "/" ), mWMTSUrlLineEdit->text() );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSMinScale" ), QStringLiteral( "/" ), mWMTSMinScaleLineEdit->value() );
|
||||
bool wmtsProject = false;
|
||||
bool wmtsPngProject = false;
|
||||
bool wmtsJpegProject = false;
|
||||
QStringList wmtsGroupList;
|
||||
QStringList wmtsPngGroupList;
|
||||
QStringList wmtsJpegGroupList;
|
||||
QStringList wmtsLayerList;
|
||||
QStringList wmtsPngLayerList;
|
||||
QStringList wmtsJpegLayerList;
|
||||
for ( const QTreeWidgetItem *item : twWmtsLayers->findItems( QString(), Qt::MatchContains | Qt::MatchRecursive, 1 ) )
|
||||
{
|
||||
if ( !item->checkState( 1 ) )
|
||||
continue;
|
||||
|
||||
QString itemType = item->data( 0, Qt::UserRole ).toString();
|
||||
if ( itemType == QLatin1String( "project" ) )
|
||||
{
|
||||
wmtsProject = true;
|
||||
wmtsPngProject = item->checkState( 2 );
|
||||
wmtsJpegProject = item->checkState( 3 );
|
||||
}
|
||||
else if ( itemType == QLatin1String( "group" ) )
|
||||
{
|
||||
QString gName = item->data( 0, Qt::UserRole + 1 ).toString();
|
||||
wmtsGroupList << gName;
|
||||
if ( item->checkState( 2 ) )
|
||||
wmtsPngGroupList << gName;
|
||||
if ( item->checkState( 3 ) )
|
||||
wmtsJpegGroupList << gName;
|
||||
}
|
||||
else if ( itemType == QLatin1String( "layer" ) )
|
||||
{
|
||||
QString lId = item->data( 0, Qt::UserRole + 1 ).toString();
|
||||
wmtsLayerList << lId;
|
||||
if ( item->checkState( 2 ) )
|
||||
wmtsPngLayerList << lId;
|
||||
if ( item->checkState( 3 ) )
|
||||
wmtsJpegLayerList << lId;
|
||||
}
|
||||
}
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Project" ), wmtsProject );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Project" ), wmtsPngProject );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Project" ), wmtsJpegProject );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Group" ), wmtsGroupList );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Group" ), wmtsPngGroupList );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Group" ), wmtsJpegGroupList );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Layer" ), wmtsLayerList );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Layer" ), wmtsPngLayerList );
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Layer" ), wmtsJpegLayerList );
|
||||
|
||||
QgsProject::instance()->writeEntry( QStringLiteral( "WFSUrl" ), QStringLiteral( "/" ), mWFSUrlLineEdit->text() );
|
||||
QStringList wfsLayerList;
|
||||
QStringList wfstUpdateLayerList;
|
||||
@ -1316,6 +1412,31 @@ void QgsProjectProperties::showProjectionsTab()
|
||||
mOptionsListWidget->setCurrentRow( 2 );
|
||||
}
|
||||
|
||||
void QgsProjectProperties::twWmtsItemChanged( QTreeWidgetItem *item, int column )
|
||||
{
|
||||
if ( column == 1 && !item->checkState( 1 ) )
|
||||
{
|
||||
item->setCheckState( 2, Qt::Unchecked );
|
||||
item->setCheckState( 3, Qt::Unchecked );
|
||||
}
|
||||
else if ( column == 1 && item->checkState( 1 ) &&
|
||||
!item->checkState( 2 ) && !item->checkState( 3 ) )
|
||||
{
|
||||
item->setCheckState( 2, Qt::Checked );
|
||||
item->setCheckState( 3, Qt::Checked );
|
||||
}
|
||||
else if ( ( column == 2 && item->checkState( 2 ) ) ||
|
||||
( column == 3 && item->checkState( 3 ) ) )
|
||||
{
|
||||
item->setCheckState( 1, Qt::Checked );
|
||||
}
|
||||
else if ( ( column == 2 && !item->checkState( 2 ) && !item->checkState( 3 ) ) ||
|
||||
( column == 3 && !item->checkState( 2 ) && !item->checkState( 3 ) ) )
|
||||
{
|
||||
item->setCheckState( 1, Qt::Unchecked );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProjectProperties::cbxWFSPubliedStateChanged( int aIdx )
|
||||
{
|
||||
QCheckBox *cb = qobject_cast<QCheckBox *>( twWFSLayers->cellWidget( aIdx, 1 ) );
|
||||
@ -1913,6 +2034,49 @@ void QgsProjectProperties::resetPythonMacros()
|
||||
"def closeProject():\n pass\n" );
|
||||
}
|
||||
|
||||
void QgsProjectProperties::populateWmtsTree( const QgsLayerTreeGroup *treeGroup, QgsTreeWidgetItem *treeItem )
|
||||
{
|
||||
for ( QgsLayerTreeNode *treeNode : treeGroup->children() )
|
||||
{
|
||||
QgsTreeWidgetItem *childItem = nullptr;
|
||||
if ( treeNode->nodeType() == QgsLayerTreeNode::NodeGroup )
|
||||
{
|
||||
QgsLayerTreeGroup *treeGroupChild = static_cast<QgsLayerTreeGroup *>( treeNode );
|
||||
QString gName = treeGroupChild->name();
|
||||
|
||||
childItem = new QgsTreeWidgetItem( QStringList() << gName );
|
||||
childItem->setFlags( childItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
|
||||
childItem->setData( 0, Qt::UserRole, QStringLiteral( "group" ) );
|
||||
childItem->setData( 0, Qt::UserRole + 1, gName );
|
||||
|
||||
treeItem->addChild( childItem );
|
||||
|
||||
populateWmtsTree( treeGroupChild, childItem );
|
||||
|
||||
treeItem->setExpanded( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsLayerTreeLayer *treeLayer = static_cast<QgsLayerTreeLayer *>( treeNode );
|
||||
QgsMapLayer *l = treeLayer->layer();
|
||||
|
||||
if ( !l )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
childItem = new QgsTreeWidgetItem( QStringList() << l->name() );
|
||||
childItem->setFlags( childItem->flags() | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
|
||||
childItem->setData( 0, Qt::UserRole, QStringLiteral( "layer" ) );
|
||||
childItem->setData( 0, Qt::UserRole + 1, l->id() );
|
||||
|
||||
treeItem->addChild( childItem );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsProjectProperties::checkOWS( QgsLayerTreeGroup *treeGroup, QStringList &owsNames, QStringList &encodingMessages )
|
||||
{
|
||||
QList< QgsLayerTreeNode * > treeGroupChildren = treeGroup->children();
|
||||
|
@ -31,6 +31,7 @@ class QgsStyle;
|
||||
class QgsExpressionContext;
|
||||
class QgsLayerTreeGroup;
|
||||
class QgsMetadataWidget;
|
||||
class QgsTreeWidgetItem;
|
||||
|
||||
/**
|
||||
* Dialog to set project level properties
|
||||
@ -135,6 +136,11 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
|
||||
void pbtnStyleFill_clicked();
|
||||
void pbtnStyleColorRamp_clicked();
|
||||
|
||||
/**
|
||||
* Slot to link WMTS checkboxes in tree widget
|
||||
*/
|
||||
void twWmtsItemChanged( QTreeWidgetItem *item, int column );
|
||||
|
||||
/**
|
||||
* Slot to link WFS checkboxes
|
||||
*/
|
||||
@ -213,6 +219,8 @@ class APP_EXPORT QgsProjectProperties : public QgsOptionsDialogBase, private Ui:
|
||||
QList<EllipsoidDefs> mEllipsoidList;
|
||||
int mEllipsoidIndex;
|
||||
|
||||
//! populate WMTS tree
|
||||
void populateWmtsTree( const QgsLayerTreeGroup *treeGroup, QgsTreeWidgetItem *treeItem );
|
||||
//! Check OWS configuration
|
||||
void checkOWS( QgsLayerTreeGroup *treeGroup, QStringList &owsNames, QStringList &encodingMessages );
|
||||
|
||||
|
@ -73,6 +73,8 @@ IF (WITH_SERVER_PLUGINS)
|
||||
qgsserverfilter.cpp
|
||||
qgsaccesscontrolfilter.cpp
|
||||
qgsaccesscontrol.cpp
|
||||
qgsservercachefilter.cpp
|
||||
qgsservercachemanager.cpp
|
||||
)
|
||||
ENDIF (WITH_SERVER_PLUGINS)
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
void QgsAccessControl::resolveFilterFeatures( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
Q_FOREACH ( QgsMapLayer *l, layers )
|
||||
for ( QgsMapLayer *l : layers )
|
||||
{
|
||||
if ( l->type() == QgsMapLayer::LayerType::VectorLayer )
|
||||
{
|
||||
|
@ -228,7 +228,7 @@ void QgsRequestHandler::parseInput()
|
||||
typedef QPair<QString, QString> pair_t;
|
||||
QUrlQuery query( inputString );
|
||||
QList<pair_t> items = query.queryItems();
|
||||
Q_FOREACH ( pair_t pair, items )
|
||||
for ( pair_t pair : items )
|
||||
{
|
||||
// QUrl::fromPercentEncoding doesn't replace '+' with space
|
||||
const QString key = QUrl::fromPercentEncoding( pair.first.replace( '+', ' ' ).toUtf8() );
|
||||
|
89
src/server/qgsservercachefilter.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/***************************************************************************
|
||||
qgsservercachefilter.cpp
|
||||
------------------------
|
||||
Cache interface for Qgis Server plugins
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgsservercachefilter.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
QgsServerCacheFilter::QgsServerCacheFilter( const QgsServerInterface *serverInterface )
|
||||
: mServerInterface( serverInterface )
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray QgsServerCacheFilter::getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool QgsServerCacheFilter::setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( doc );
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheFilter::deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheFilter::deleteCachedDocuments( const QgsProject *project ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray QgsServerCacheFilter::getCachedImage( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool QgsServerCacheFilter::setCachedImage( const QByteArray *img, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( img );
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheFilter::deleteCachedImage( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
Q_UNUSED( request );
|
||||
Q_UNUSED( key );
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheFilter::deleteCachedImages( const QgsProject *project ) const
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
return false;
|
||||
}
|
136
src/server/qgsservercachefilter.h
Normal file
@ -0,0 +1,136 @@
|
||||
/***************************************************************************
|
||||
qgsservercachefilter.h
|
||||
------------------------
|
||||
Cache interface for Qgis Server plugins
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 QGSSERVERCACHEFILTER_H
|
||||
#define QGSSERVERCACHEFILTER_H
|
||||
|
||||
#include <QMultiMap>
|
||||
#include <QDomDocument>
|
||||
#include <QObject>
|
||||
#include "qgsproject.h"
|
||||
#include "qgsserverrequest.h"
|
||||
#include "qgis_server.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
SIP_IF_MODULE( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
|
||||
class QgsServerInterface;
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsServerCacheFilter
|
||||
* \brief Class defining cache interface for QGIS Server plugins.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class SERVER_EXPORT QgsServerCacheFilter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* QgsServerInterface passed to plugins constructors
|
||||
* and must be passed to QgsServerCacheFilter instances.
|
||||
*/
|
||||
QgsServerCacheFilter( const QgsServerInterface *serverInterface );
|
||||
|
||||
virtual ~QgsServerCacheFilter() = default;
|
||||
|
||||
/**
|
||||
* Returns cached document (or 0 if document not in cache) like capabilities
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify different documents for the same request
|
||||
* \returns QByteArray of the cached document or an empty one if no corresponding document found
|
||||
*/
|
||||
virtual QByteArray getCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Updates or inserts the document in cache like capabilities
|
||||
* \param doc the document to cache
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify different documents for the same request
|
||||
* \returns true if the document has been cached
|
||||
*/
|
||||
virtual bool setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Deletes the cached document
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param key the key provided by the access control to identify different documents for the same request
|
||||
* \returns true if the document has been deleted
|
||||
*/
|
||||
virtual bool deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Deletes all cached documents for a QGIS project
|
||||
* \param project the project used to generate the documents to provide path
|
||||
* \returns true if the documents have been deleted
|
||||
*/
|
||||
virtual bool deleteCachedDocuments( const QgsProject *project ) const;
|
||||
|
||||
/**
|
||||
* Returns cached image (or 0 if document not in cache) like tiles
|
||||
* \param project the project used to generate the image to provide path
|
||||
* \param request the request used to generate the image to provider parameters or data
|
||||
* \param key the key provided by the access control to identify different images for the same request
|
||||
* \returns QByteArray of the cached image or an empty one if no corresponding image found
|
||||
*/
|
||||
virtual QByteArray getCachedImage( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Updates or inserts the image in cache like tiles
|
||||
* \param img the document to cache
|
||||
* \param project the project used to generate the image to provide path
|
||||
* \param request the request used to generate the image to provider parameters or data
|
||||
* \param key the key provided by the access control to identify different images for the same request
|
||||
* \returns true if the image has been cached
|
||||
*/
|
||||
virtual bool setCachedImage( const QByteArray *img, const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Deletes the cached image
|
||||
* \param project the project used to generate the image to provide path
|
||||
* \param request the request used to generate the image to provider parameters or data
|
||||
* \param key the key provided by the access control to identify different images for the same request
|
||||
* \returns true if the image has been deleted
|
||||
*/
|
||||
virtual bool deleteCachedImage( const QgsProject *project, const QgsServerRequest &request, const QString &key ) const;
|
||||
|
||||
/**
|
||||
* Deletes all cached images for a QGIS project
|
||||
* \param project the project used to generate the images to provide path
|
||||
* \returns true if the images have been deleted
|
||||
*/
|
||||
virtual bool deleteCachedImages( const QgsProject *project ) const;
|
||||
|
||||
private:
|
||||
|
||||
//! The server interface
|
||||
const QgsServerInterface *mServerInterface = nullptr;
|
||||
|
||||
};
|
||||
|
||||
//! The registry definition
|
||||
typedef QMultiMap<int, QgsServerCacheFilter *> QgsServerCacheFilterMap;
|
||||
|
||||
#endif // QGSSERVERCACHEFILTER_H
|
218
src/server/qgsservercachemanager.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/***************************************************************************
|
||||
qgsservercachemanager.cpp
|
||||
-------------------------
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgsservercachemanager.h"
|
||||
|
||||
QgsServerCacheManager::QgsServerCacheManager()
|
||||
{
|
||||
mPluginsServerCaches.reset( new QgsServerCacheFilterMap() );
|
||||
}
|
||||
|
||||
QgsServerCacheManager::QgsServerCacheManager( const QgsServerCacheManager © )
|
||||
{
|
||||
if ( copy.mPluginsServerCaches )
|
||||
{
|
||||
mPluginsServerCaches.reset( new QgsServerCacheFilterMap( *copy.mPluginsServerCaches ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mPluginsServerCaches.reset( nullptr );
|
||||
}
|
||||
}
|
||||
|
||||
QgsServerCacheManager &QgsServerCacheManager::operator=( const QgsServerCacheManager © )
|
||||
{
|
||||
if ( copy.mPluginsServerCaches )
|
||||
{
|
||||
mPluginsServerCaches.reset( new QgsServerCacheFilterMap( *copy.mPluginsServerCaches ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mPluginsServerCaches.reset( nullptr );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
QgsServerCacheManager::~QgsServerCacheManager()
|
||||
{
|
||||
mPluginsServerCaches.reset();
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::getCachedDocument( QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
bool cache = true;
|
||||
QString key = getCacheKey( cache, accessControl );
|
||||
|
||||
if ( !cache )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray content;
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
content = scIterator.value()->getCachedDocument( project, request, key );
|
||||
if ( !content.isEmpty() )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( content.isEmpty() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !doc->setContent( content ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
bool cache = true;
|
||||
QString key = getCacheKey( cache, accessControl );
|
||||
|
||||
if ( !cache )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->setCachedDocument( doc, project, request, key ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
bool cache = true;
|
||||
QString key = getCacheKey( cache, accessControl );
|
||||
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->deleteCachedDocument( project, request, key ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::deleteCachedDocuments( const QgsProject *project ) const
|
||||
{
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->deleteCachedDocuments( project ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray QgsServerCacheManager::getCachedImage( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
bool cache = true;
|
||||
QString key = getCacheKey( cache, accessControl );
|
||||
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
QByteArray content = scIterator.value()->getCachedImage( project, request, key );
|
||||
if ( !content.isEmpty() )
|
||||
{
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::setCachedImage( const QByteArray *img, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
bool cache = true;
|
||||
QString key = getCacheKey( cache, accessControl );
|
||||
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->setCachedImage( img, project, request, key ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::deleteCachedImage( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
bool cache = true;
|
||||
QString key = getCacheKey( cache, accessControl );
|
||||
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->deleteCachedImage( project, request, key ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsServerCacheManager::deleteCachedImages( const QgsProject *project ) const
|
||||
{
|
||||
QgsServerCacheFilterMap::const_iterator scIterator;
|
||||
for ( scIterator = mPluginsServerCaches->constBegin(); scIterator != mPluginsServerCaches->constEnd(); ++scIterator )
|
||||
{
|
||||
if ( scIterator.value()->deleteCachedImages( project ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QgsServerCacheManager::registerServerCache( QgsServerCacheFilter *serverCache, int priority )
|
||||
{
|
||||
mPluginsServerCaches->insert( priority, serverCache );
|
||||
}
|
||||
|
||||
QString QgsServerCacheManager::getCacheKey( bool &cache, QgsAccessControl *accessControl ) const
|
||||
{
|
||||
QStringList cacheKeyList;
|
||||
if ( accessControl )
|
||||
{
|
||||
cache = accessControl->fillCacheKey( cacheKeyList );
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = true;
|
||||
}
|
||||
return cacheKeyList.join( '-' );
|
||||
}
|
143
src/server/qgsservercachemanager.h
Normal file
@ -0,0 +1,143 @@
|
||||
/***************************************************************************
|
||||
qgsservercachemanager.h
|
||||
-----------------------
|
||||
|
||||
begin : 2018-07-05
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 QGSSERVERCACHEMANAGER_H
|
||||
#define QGSSERVERCACHEMANAGER_H
|
||||
|
||||
#include "qgsservercachefilter.h"
|
||||
#include "qgsaccesscontrol.h"
|
||||
#include "qgsserverrequest.h"
|
||||
|
||||
#include <QMultiMap>
|
||||
#include <QDomDocument>
|
||||
#include "qgsproject.h"
|
||||
#include "qgis_server.h"
|
||||
#include "qgis_sip.h"
|
||||
|
||||
SIP_IF_MODULE( HAVE_SERVER_PYTHON_PLUGINS )
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsServerCacheManager
|
||||
* \brief A helper class that centralizes caches accesses given by all the server cache filter plugins.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class SERVER_EXPORT QgsServerCacheManager
|
||||
{
|
||||
#ifdef SIP_RUN
|
||||
#include "qgsservercachefilter.h"
|
||||
#endif
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
QgsServerCacheManager();
|
||||
|
||||
//! Copy constructor
|
||||
QgsServerCacheManager( const QgsServerCacheManager © );
|
||||
|
||||
//! Assignment operator
|
||||
QgsServerCacheManager &operator=( const QgsServerCacheManager © );
|
||||
|
||||
//! Destructor
|
||||
~QgsServerCacheManager();
|
||||
|
||||
/**
|
||||
* Returns cached document (or 0 if document not in cache) like capabilities
|
||||
* \param doc the document to update by content found in cache
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param accessControl the access control to identify different documents for the same request provided by server interface
|
||||
* \returns true if the document has been found in cache and the document's content set
|
||||
*/
|
||||
bool getCachedDocument( QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
|
||||
/**
|
||||
* Updates or inserts the document in cache like capabilities
|
||||
* \param doc the document to cache
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param accessControl the access control to identify different documents for the same request provided by server interface
|
||||
* \returns true if the document has been cached
|
||||
*/
|
||||
bool setCachedDocument( const QDomDocument *doc, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
|
||||
/**
|
||||
* Deletes the cached document
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \param request the request used to generate the document to provider parameters or data
|
||||
* \param accessControl the access control to identify different documents for the same request provided by server interface
|
||||
* \returns true if the document has been deleted
|
||||
*/
|
||||
bool deleteCachedDocument( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
|
||||
/**
|
||||
* Deletes all cached documents for a QGIS project
|
||||
* \param project the project used to generate the document to provide path
|
||||
* \returns true if the document has been deleted
|
||||
*/
|
||||
bool deleteCachedDocuments( const QgsProject *project ) const;
|
||||
|
||||
/**
|
||||
* Returns cached image (or 0 if image not in cache) like tiles
|
||||
* \param project the project used to generate the image to provide path
|
||||
* \param request the request used to generate the image to provider parameters or data
|
||||
* \param accessControl the access control to identify different documents for the same request provided by server interface
|
||||
* \returns the cached image or 0 if no corresponding image found
|
||||
*/
|
||||
QByteArray getCachedImage( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
|
||||
/**
|
||||
* Updates or inserts the image in cache like tiles
|
||||
* \param img the image to cache
|
||||
* \param project the project used to generate the image to provide path
|
||||
* \param request the request used to generate the image to provider parameters or data
|
||||
* \param accessControl the access control to identify different documents for the same request provided by server interface
|
||||
* \returns true if the image has been cached
|
||||
*/
|
||||
bool setCachedImage( const QByteArray *img, const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
|
||||
/**
|
||||
* Deletes the cached image
|
||||
* \param project the project used to generate the image to provide path
|
||||
* \param request the request used to generate the image to provider parameters or data
|
||||
* \param accessControl the access control to identify different documents for the same request provided by server interface
|
||||
* \returns true if the image has been deleted
|
||||
*/
|
||||
bool deleteCachedImage( const QgsProject *project, const QgsServerRequest &request, QgsAccessControl *accessControl ) const;
|
||||
|
||||
/**
|
||||
* Deletes all cached images for a QGIS project
|
||||
* \param project the project used to generate the images to provide path
|
||||
* \returns true if the images have been deleted
|
||||
*/
|
||||
bool deleteCachedImages( const QgsProject *project ) const;
|
||||
|
||||
/**
|
||||
* Register a server cache filter
|
||||
* \param serverCache the server cache to add
|
||||
* \param priority the priority used to define the order
|
||||
*/
|
||||
void registerServerCache( QgsServerCacheFilter *serverCache, int priority = 0 );
|
||||
|
||||
private:
|
||||
QString getCacheKey( bool &cache, QgsAccessControl *accessControl ) const;
|
||||
//! The ServerCache plugins registry
|
||||
std::unique_ptr<QgsServerCacheFilterMap> mPluginsServerCaches = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
@ -30,9 +30,13 @@
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
#include "qgsaccesscontrolfilter.h"
|
||||
#include "qgsaccesscontrol.h"
|
||||
#include "qgsservercachefilter.h"
|
||||
#include "qgsservercachemanager.h"
|
||||
#else
|
||||
class QgsAccessControl;
|
||||
class QgsAccessControlFilter;
|
||||
class QgsServerCacheManager;
|
||||
class QgsServerCacheFilter;
|
||||
#endif
|
||||
#include "qgsserviceregistry.h"
|
||||
#include "qgis_server.h"
|
||||
@ -118,6 +122,20 @@ class SERVER_EXPORT QgsServerInterface
|
||||
//! Gets the registered access control filters
|
||||
virtual QgsAccessControl *accessControls() const = 0;
|
||||
|
||||
/**
|
||||
* Register a server cache filter
|
||||
* \param serverCache the server cache to register
|
||||
* \param priority the priority used to order them
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
virtual void registerServerCache( QgsServerCacheFilter *serverCache SIP_TRANSFER, int priority = 0 ) = 0;
|
||||
|
||||
/**
|
||||
* Gets the registered server cache filters
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
virtual QgsServerCacheManager *cacheManager() const = 0;
|
||||
|
||||
//! Returns an enrironment variable, used to pass environment variables to Python
|
||||
virtual QString getEnv( const QString &name ) const = 0;
|
||||
|
||||
|
@ -29,8 +29,7 @@ QgsServerInterfaceImpl::QgsServerInterfaceImpl( QgsCapabilitiesCache *capCache,
|
||||
mRequestHandler = nullptr;
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
mAccessControls = new QgsAccessControl();
|
||||
#else
|
||||
mAccessControls = nullptr;
|
||||
mCacheManager.reset( new QgsServerCacheManager() );
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -44,6 +43,7 @@ QgsServerInterfaceImpl::~QgsServerInterfaceImpl()
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
delete mAccessControls;
|
||||
mCacheManager.reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -84,6 +84,17 @@ void QgsServerInterfaceImpl::registerAccessControl( QgsAccessControlFilter *acce
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Register a new access control filter
|
||||
void QgsServerInterfaceImpl::registerServerCache( QgsServerCacheFilter *serverCache, int priority )
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
mCacheManager->registerServerCache( serverCache, priority );
|
||||
#else
|
||||
Q_UNUSED( serverCache );
|
||||
Q_UNUSED( priority );
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void QgsServerInterfaceImpl::removeConfigCacheEntry( const QString &path )
|
||||
{
|
||||
|
@ -50,8 +50,8 @@ class QgsServerInterfaceImpl : public QgsServerInterface
|
||||
QgsRequestHandler *requestHandler() override { return mRequestHandler; }
|
||||
void registerFilter( QgsServerFilter *filter, int priority = 0 ) override;
|
||||
QgsServerFiltersMap filters() override { return mFilters; }
|
||||
|
||||
//! Register an access control filter
|
||||
//
|
||||
void registerAccessControl( QgsAccessControlFilter *accessControl, int priority = 0 ) override;
|
||||
|
||||
/**
|
||||
@ -59,6 +59,23 @@ class QgsServerInterfaceImpl : public QgsServerInterface
|
||||
* \returns the access control helper
|
||||
*/
|
||||
QgsAccessControl *accessControls() const override { return mAccessControls; }
|
||||
|
||||
|
||||
/**
|
||||
* Registers a server cache filter
|
||||
* \param serverCache the server cache to register
|
||||
* \param priority the priority used to order them
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
void registerServerCache( QgsServerCacheFilter *serverCache SIP_TRANSFER, int priority = 0 ) override;
|
||||
|
||||
/**
|
||||
* Gets the helper over all the registered server cache filters
|
||||
* \returns the server cache helper
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
QgsServerCacheManager *cacheManager() const override { return mCacheManager.get(); }
|
||||
|
||||
QString getEnv( const QString &name ) const override;
|
||||
QString configFilePath() override { return mConfigFilePath; }
|
||||
void setConfigFilePath( const QString &configFilePath ) override;
|
||||
@ -74,6 +91,7 @@ class QgsServerInterfaceImpl : public QgsServerInterface
|
||||
QString mConfigFilePath;
|
||||
QgsServerFiltersMap mFilters;
|
||||
QgsAccessControl *mAccessControls = nullptr;
|
||||
std::unique_ptr<QgsServerCacheManager> mCacheManager = nullptr;
|
||||
QgsCapabilitiesCache *mCapabilitiesCache = nullptr;
|
||||
QgsRequestHandler *mRequestHandler = nullptr;
|
||||
QgsServiceRegistry *mServiceRegistry = nullptr;
|
||||
|
@ -90,7 +90,7 @@ bool QgsServerPlugins::initPlugins( QgsServerInterface *interface )
|
||||
//Init plugins: loads a list of installed plugins and filter them
|
||||
//for "server" metadata
|
||||
bool atLeastOneEnabled = false;
|
||||
Q_FOREACH ( const QString &pluginName, sPythonUtils->pluginList() )
|
||||
for ( const QString &pluginName : sPythonUtils->pluginList() )
|
||||
{
|
||||
QString pluginService = sPythonUtils->getPluginMetadata( pluginName, QStringLiteral( "server" ) );
|
||||
if ( pluginService == QLatin1String( "True" ) )
|
||||
|
@ -331,3 +331,8 @@ QStringList QgsServerProjectUtils::wcsLayerIds( const QgsProject &project )
|
||||
{
|
||||
return project.readListEntry( QStringLiteral( "WCSLayers" ), QStringLiteral( "/" ) );
|
||||
}
|
||||
|
||||
QString QgsServerProjectUtils::wmtsServiceUrl( const QgsProject &project )
|
||||
{
|
||||
return project.readEntry( QStringLiteral( "WMTSSUrl" ), QStringLiteral( "/" ), "" );
|
||||
}
|
||||
|
@ -40,313 +40,321 @@ namespace QgsServerProjectUtils
|
||||
|
||||
/**
|
||||
* Returns if owsService capabilities are enabled.
|
||||
* \param project the QGIS project
|
||||
* \returns if owsService capabilities are enabled.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns if owsService capabilities are enabled.
|
||||
*/
|
||||
SERVER_EXPORT bool owsServiceCapabilities( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService title defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService title if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService title if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceTitle( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService abstract defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService abstract if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService abstract if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceAbstract( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService keywords defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService keywords if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService keywords if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QStringList owsServiceKeywords( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService online resource defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService online resource if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService online resource if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceOnlineResource( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService contact organization defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact organization if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact organization if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceContactOrganization( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService contact position defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact position if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact position if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceContactPosition( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService contact person defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact person if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact person if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceContactPerson( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService contact mail defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact mail if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact mail if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceContactMail( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService contact phone defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact phone if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService contact phone if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceContactPhone( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService fees defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService fees if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService fees if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceFees( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the owsService access constraints defined in project.
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService access constraints if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the owsService access constraints if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString owsServiceAccessConstraints( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the maximum width for WMS images defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns width if defined in project, -1 otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns width if defined in project, -1 otherwise.
|
||||
*/
|
||||
SERVER_EXPORT int wmsMaxWidth( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the maximum height for WMS images defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns height if defined in project, -1 otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns height if defined in project, -1 otherwise.
|
||||
*/
|
||||
SERVER_EXPORT int wmsMaxHeight( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the quality for WMS images defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns quality if defined in project, -1 otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns quality if defined in project, -1 otherwise.
|
||||
*/
|
||||
SERVER_EXPORT int wmsImageQuality( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns if layer ids are used as name in WMS.
|
||||
* \param project the QGIS project
|
||||
* \returns if layer ids are used as name.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns if layer ids are used as name.
|
||||
*/
|
||||
SERVER_EXPORT bool wmsUseLayerIds( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns if the info format is SIA20145.
|
||||
* \param project the QGIS project
|
||||
* \returns if the info format is SIA20145.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns if the info format is SIA20145.
|
||||
*/
|
||||
SERVER_EXPORT bool wmsInfoFormatSia2045( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns if the geometry is displayed as Well Known Text in GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns if the geometry is displayed as Well Known Text in GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns if the geometry is displayed as Well Known Text in GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT bool wmsFeatureInfoAddWktGeometry( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns if the geometry has to be segmentize in GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns if the geometry has to be segmentize in GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns if the geometry has to be segmentize in GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT bool wmsFeatureInfoSegmentizeWktGeometry( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the geometry precision for GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns the geometry precision for GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the geometry precision for GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT int wmsFeatureInfoPrecision( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the document element name for XML GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns the document element name for XML GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the document element name for XML GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsFeatureInfoDocumentElement( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the document element namespace for XML GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns the document element namespace for XML GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the document element namespace for XML GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsFeatureInfoDocumentElementNs( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the schema URL for XML GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns the schema URL for XML GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the schema URL for XML GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsFeatureInfoSchema( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the mapping between layer name and wms layer name for GetFeatureInfo request.
|
||||
* \param project the QGIS project
|
||||
* \returns the mapping between layer name and wms layer name for GetFeatureInfo request.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the mapping between layer name and wms layer name for GetFeatureInfo request.
|
||||
*/
|
||||
SERVER_EXPORT QHash<QString, QString> wmsFeatureInfoLayerAliasMap( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns if Inspire is activated.
|
||||
* \param project the QGIS project
|
||||
* \returns if Inspire is activated.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns if Inspire is activated.
|
||||
*/
|
||||
SERVER_EXPORT bool wmsInspireActivate( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Inspire language.
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire language if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire language if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsInspireLanguage( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Inspire metadata URL.
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire metadata URL if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire metadata URL if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsInspireMetadataUrl( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Inspire metadata URL type.
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire metadata URL type if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire metadata URL type if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsInspireMetadataUrlType( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Inspire temporal reference.
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire temporal reference if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire temporal reference if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsInspireTemporalReference( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Inspire metadata date.
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire metadata date if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the Inspire metadata date if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsInspireMetadataDate( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the restricted composer list.
|
||||
* \param project the QGIS project
|
||||
* \returns the restricted composer list if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the restricted composer list if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wmsRestrictedComposers( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WMS service url defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsServiceUrl( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WMS root layer name defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns root layer name if defined in project, an empty string otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns root layer name if defined in project, an empty string otherwise.
|
||||
*/
|
||||
SERVER_EXPORT QString wmsRootName( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the restricted layer name list.
|
||||
* \param project the QGIS project
|
||||
* \returns the restricted layer name list if defined in project.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the restricted layer name list if defined in project.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wmsRestrictedLayers( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WMS output CRS list.
|
||||
* \param project the QGIS project
|
||||
* \returns the WMS output CRS list.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the WMS output CRS list.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wmsOutputCrsList( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WMS Extent restriction.
|
||||
* \param project the QGIS project
|
||||
* \returns the WMS Extent restriction.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the WMS Extent restriction.
|
||||
*/
|
||||
SERVER_EXPORT QgsRectangle wmsExtent( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WFS service url defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
*/
|
||||
SERVER_EXPORT QString wfsServiceUrl( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Layer ids list defined in a QGIS project as published in WFS.
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wfsLayerIds( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Layer precision defined in a QGIS project for the WFS GetFeature.
|
||||
* \param project the QGIS project
|
||||
* \param layerId the layer id in the project
|
||||
* \return the layer precision for WFS GetFeature.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \param layerId the layer id in the project
|
||||
* \return the layer precision for WFS GetFeature.
|
||||
*/
|
||||
|
||||
SERVER_EXPORT int wfsLayerPrecision( const QgsProject &project, const QString &layerId );
|
||||
|
||||
/**
|
||||
* Returns the Layer ids list defined in a QGIS project as published as WFS-T with update capabilities.
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wfstUpdateLayerIds( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Layer ids list defined in a QGIS project as published as WFS-T with insert capabilities.
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wfstInsertLayerIds( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Layer ids list defined in a QGIS project as published as WFS-T with delete capabilities.
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \return the Layer ids list.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wfstDeleteLayerIds( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WCS service url defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
*/
|
||||
SERVER_EXPORT QString wcsServiceUrl( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the Layer ids list defined in a QGIS project as published in WCS.
|
||||
* \param project the QGIS project
|
||||
* \returns the Layer ids list.
|
||||
*/
|
||||
* \param project the QGIS project
|
||||
* \returns the Layer ids list.
|
||||
*/
|
||||
SERVER_EXPORT QStringList wcsLayerIds( const QgsProject &project );
|
||||
|
||||
/**
|
||||
* Returns the WMTS service url defined in a QGIS project.
|
||||
* \param project the QGIS project
|
||||
* \returns url if defined in project, an empty string otherwise.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
SERVER_EXPORT QString wmtsServiceUrl( const QgsProject &project );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -70,7 +70,7 @@ void QgsServiceNativeLoader::loadModules( const QString &modulePath, QgsServiceR
|
||||
qDebug() << QString( "Checking %1 for native services modules" ).arg( moduleDir.path() );
|
||||
//QgsDebugMsg( QString( "Checking %1 for native services modules" ).arg( moduleDir.path() ) );
|
||||
|
||||
Q_FOREACH ( const QFileInfo &fi, moduleDir.entryInfoList() )
|
||||
for ( const QFileInfo &fi : moduleDir.entryInfoList() )
|
||||
{
|
||||
QgsServiceModule *module = loadNativeModule( fi.filePath() );
|
||||
if ( module )
|
||||
|
@ -10,4 +10,5 @@ ADD_SUBDIRECTORY(DummyService)
|
||||
ADD_SUBDIRECTORY(wms)
|
||||
ADD_SUBDIRECTORY(wfs)
|
||||
ADD_SUBDIRECTORY(wcs)
|
||||
ADD_SUBDIRECTORY(wmts)
|
||||
|
||||
|
@ -102,7 +102,7 @@ namespace QgsWcs
|
||||
};
|
||||
|
||||
|
||||
} // namespace QgsWfs
|
||||
} // namespace QgsWcs
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
|
@ -120,7 +120,7 @@ namespace QgsWcs
|
||||
if ( coveNameList.size() == 0 || coveNameList.contains( name ) )
|
||||
{
|
||||
QgsRasterLayer *rLayer = qobject_cast<QgsRasterLayer *>( layer );
|
||||
coveDescElement.appendChild( getCoverageOffering( doc, const_cast<QgsRasterLayer *>( rLayer ) ) );
|
||||
coveDescElement.appendChild( getCoverageOffering( doc, const_cast<QgsRasterLayer *>( rLayer ), project ) );
|
||||
}
|
||||
}
|
||||
return doc;
|
||||
|
@ -37,10 +37,29 @@ namespace QgsWcs
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QDomDocument doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
|
||||
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
|
||||
response.write( doc.toByteArray() );
|
||||
QDomDocument doc;
|
||||
const QDomDocument *capabilitiesDocument = nullptr;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
else //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cacheManager )
|
||||
{
|
||||
cacheManager->setCachedDocument( &doc, project, request, accessControl );
|
||||
}
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
|
||||
response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
@ -280,7 +299,7 @@ namespace QgsWcs
|
||||
#endif
|
||||
|
||||
QgsRasterLayer *rLayer = qobject_cast<QgsRasterLayer *>( layer );
|
||||
QDomElement layerElem = getCoverageOffering( doc, const_cast<QgsRasterLayer *>( rLayer ), true );
|
||||
QDomElement layerElem = getCoverageOffering( doc, const_cast<QgsRasterLayer *>( rLayer ), project, true );
|
||||
|
||||
contentMetadataElement.appendChild( layerElem );
|
||||
}
|
||||
|
@ -165,9 +165,7 @@ namespace QgsWcs
|
||||
// transform rect
|
||||
if ( requestCRS != rLayer->crs() )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform t( requestCRS, rLayer->crs() );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform t( requestCRS, rLayer->crs(), project );
|
||||
rect = t.transformBoundingBox( rect );
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace QgsWcs
|
||||
return QStringLiteral( "1.0.0" );
|
||||
}
|
||||
|
||||
QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, bool brief )
|
||||
QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief )
|
||||
{
|
||||
QDomElement layerElem;
|
||||
if ( brief )
|
||||
@ -73,9 +73,7 @@ namespace QgsWcs
|
||||
|
||||
//lonLatEnvelope
|
||||
QgsCoordinateReferenceSystem layerCrs = layer->crs();
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform t( layerCrs, QgsCoordinateReferenceSystem( 4326 ) );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform t( layerCrs, QgsCoordinateReferenceSystem( 4326 ), project );
|
||||
//transform
|
||||
QgsRectangle BBox;
|
||||
try
|
||||
@ -253,7 +251,7 @@ namespace QgsWcs
|
||||
q.removeAllQueryItems( QStringLiteral( "_DC" ) );
|
||||
|
||||
url.setQuery( q );
|
||||
href = url.toString( QUrl::FullyDecoded );
|
||||
href = url.toString();
|
||||
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ namespace QgsWcs
|
||||
/**
|
||||
* CoverageOffering or CoverageOfferingBrief element
|
||||
*/
|
||||
QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, bool brief = false );
|
||||
QDomElement getCoverageOffering( QDomDocument &doc, const QgsRasterLayer *layer, const QgsProject *project, bool brief = false );
|
||||
|
||||
/**
|
||||
* Service URL string
|
||||
@ -58,7 +58,7 @@ namespace QgsWcs
|
||||
//XXX At some point, should be moved to common library
|
||||
QgsRectangle parseBbox( const QString &bboxStr );
|
||||
|
||||
// Define namespaces used in WFS documents
|
||||
// Define namespaces used in WCS documents
|
||||
const QString WCS_NAMESPACE = QStringLiteral( "http://www.opengis.net/wcs" );
|
||||
const QString GML_NAMESPACE = QStringLiteral( "http://www.opengis.net/gml" );
|
||||
const QString OGC_NAMESPACE = QStringLiteral( "http://www.opengis.net/ogc" );
|
||||
|
@ -41,10 +41,29 @@ namespace QgsWfs
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QDomDocument doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
|
||||
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
|
||||
response.write( doc.toByteArray() );
|
||||
QDomDocument doc;
|
||||
const QDomDocument *capabilitiesDocument = nullptr;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
else //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cacheManager )
|
||||
{
|
||||
cacheManager->setCachedDocument( &doc, project, request, accessControl );
|
||||
}
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
|
||||
response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
@ -516,9 +535,7 @@ namespace QgsWfs
|
||||
QgsRectangle wgs84BoundingRect;
|
||||
if ( !layerExtent.isNull() )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform exGeoTransform( layer->crs(), wgs84 );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform exGeoTransform( layer->crs(), wgs84, project );
|
||||
try
|
||||
{
|
||||
wgs84BoundingRect = exGeoTransform.transformBoundingBox( layerExtent );
|
||||
|
@ -43,10 +43,29 @@ namespace QgsWfs
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QDomDocument doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
|
||||
response.setHeader( "Content-Type", "text/xml; charset=utf-8" );
|
||||
response.write( doc.toByteArray() );
|
||||
QDomDocument doc;
|
||||
const QDomDocument *capabilitiesDocument = nullptr;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
else //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cacheManager )
|
||||
{
|
||||
cacheManager->setCachedDocument( &doc, project, request, accessControl );
|
||||
}
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
|
||||
response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,9 +62,9 @@ namespace QgsWfs
|
||||
|
||||
QString createFeatureGeoJSON( QgsFeature *feat, const createFeatureParams ¶ms );
|
||||
|
||||
QDomElement createFeatureGML2( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms );
|
||||
QDomElement createFeatureGML2( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms, const QgsProject *project );
|
||||
|
||||
QDomElement createFeatureGML3( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms );
|
||||
QDomElement createFeatureGML3( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms, const QgsProject *project );
|
||||
|
||||
void hitGetFeature( const QgsServerRequest &request, QgsServerResponse &response, const QgsProject *project,
|
||||
QgsWfsParameters::Format format, int numberOfFeatures, const QStringList &typeNames );
|
||||
@ -74,7 +74,7 @@ namespace QgsWfs
|
||||
QgsRectangle *rect, const QStringList &typeNames );
|
||||
|
||||
void setGetFeature( QgsServerResponse &response, QgsWfsParameters::Format format, QgsFeature *feat, int featIdx,
|
||||
const createFeatureParams ¶ms );
|
||||
const createFeatureParams ¶ms, const QgsProject *project );
|
||||
|
||||
void endGetFeature( QgsServerResponse &response, QgsWfsParameters::Format format );
|
||||
|
||||
@ -155,9 +155,7 @@ namespace QgsWfs
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform transform( layer->crs(), requestCrs );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform transform( layer->crs(), requestCrs, project );
|
||||
try
|
||||
{
|
||||
if ( requestRect.isEmpty() )
|
||||
@ -319,7 +317,7 @@ namespace QgsWfs
|
||||
accessControl->filterFeatures( vlayer, featureRequest );
|
||||
|
||||
QStringList attributes = QStringList();
|
||||
Q_FOREACH ( int idx, attrIndexes )
|
||||
for ( int idx : attrIndexes )
|
||||
{
|
||||
attributes.append( vlayer->fields().field( idx ).name() );
|
||||
}
|
||||
@ -357,9 +355,7 @@ namespace QgsWfs
|
||||
|
||||
if ( !featureRequest.filterRect().isEmpty() )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform transform( outputCrs, vlayer->crs() );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform transform( outputCrs, vlayer->crs(), project );
|
||||
try
|
||||
{
|
||||
featureRequest.setFilterRect( transform.transform( featureRequest.filterRect() ) );
|
||||
@ -405,7 +401,7 @@ namespace QgsWfs
|
||||
|
||||
if ( iteratedFeatures >= aRequest.startIndex )
|
||||
{
|
||||
setGetFeature( response, aRequest.outputFormat, &feature, sentFeatures, cfp );
|
||||
setGetFeature( response, aRequest.outputFormat, &feature, sentFeatures, cfp, project );
|
||||
++sentFeatures;
|
||||
}
|
||||
++iteratedFeatures;
|
||||
@ -1169,7 +1165,7 @@ namespace QgsWfs
|
||||
}
|
||||
|
||||
void setGetFeature( QgsServerResponse &response, QgsWfsParameters::Format format, QgsFeature *feat, int featIdx,
|
||||
const createFeatureParams ¶ms )
|
||||
const createFeatureParams ¶ms, const QgsProject *project )
|
||||
{
|
||||
if ( !feat->isValid() )
|
||||
return;
|
||||
@ -1196,12 +1192,12 @@ namespace QgsWfs
|
||||
QDomElement featureElement;
|
||||
if ( format == QgsWfsParameters::Format::GML3 )
|
||||
{
|
||||
featureElement = createFeatureGML3( feat, gmlDoc, params );
|
||||
featureElement = createFeatureGML3( feat, gmlDoc, params, project );
|
||||
gmlDoc.appendChild( featureElement );
|
||||
}
|
||||
else
|
||||
{
|
||||
featureElement = createFeatureGML2( feat, gmlDoc, params );
|
||||
featureElement = createFeatureGML2( feat, gmlDoc, params, project );
|
||||
gmlDoc.appendChild( featureElement );
|
||||
}
|
||||
response.write( gmlDoc.toByteArray() );
|
||||
@ -1255,7 +1251,7 @@ namespace QgsWfs
|
||||
}
|
||||
|
||||
|
||||
QDomElement createFeatureGML2( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms )
|
||||
QDomElement createFeatureGML2( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms, const QgsProject *project )
|
||||
{
|
||||
//gml:FeatureMember
|
||||
QDomElement featureElement = doc.createElement( QStringLiteral( "gml:featureMember" )/*wfs:FeatureMember*/ );
|
||||
@ -1271,9 +1267,7 @@ namespace QgsWfs
|
||||
{
|
||||
int prec = params.precision;
|
||||
QgsCoordinateReferenceSystem crs = params.crs;
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform mTransform( crs, params.outputCrs );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform mTransform( crs, params.outputCrs, project );
|
||||
try
|
||||
{
|
||||
QgsGeometry transformed = geom;
|
||||
@ -1352,7 +1346,7 @@ namespace QgsWfs
|
||||
return featureElement;
|
||||
}
|
||||
|
||||
QDomElement createFeatureGML3( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms )
|
||||
QDomElement createFeatureGML3( QgsFeature *feat, QDomDocument &doc, const createFeatureParams ¶ms, const QgsProject *project )
|
||||
{
|
||||
//gml:FeatureMember
|
||||
QDomElement featureElement = doc.createElement( QStringLiteral( "gml:featureMember" )/*wfs:FeatureMember*/ );
|
||||
@ -1368,9 +1362,7 @@ namespace QgsWfs
|
||||
{
|
||||
int prec = params.precision;
|
||||
QgsCoordinateReferenceSystem crs = params.crs;
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform mTransform( crs, params.outputCrs );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform mTransform( crs, params.outputCrs, project );
|
||||
try
|
||||
{
|
||||
QgsGeometry transformed = geom;
|
||||
|
@ -53,7 +53,7 @@ namespace QgsWfs
|
||||
params.remove( QgsServerParameter::SERVICE );
|
||||
|
||||
url.setQuery( params.urlQuery() );
|
||||
href = url.toString( QUrl::FullyDecoded );
|
||||
href = url.toString();
|
||||
}
|
||||
|
||||
return href;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
QgsLayerRestorer::QgsLayerRestorer( const QList<QgsMapLayer *> &layers )
|
||||
{
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
QgsLayerSettings settings;
|
||||
settings.name = layer->name();
|
||||
|
@ -84,7 +84,7 @@ namespace QgsWms
|
||||
|
||||
// get the wms service url defined in project or keep the one from the
|
||||
// request url
|
||||
QString wmsHrefString = serviceUrl( request, project ).toString( QUrl::FullyDecoded );
|
||||
QString wmsHrefString = serviceUrl( request, project ).toString();
|
||||
|
||||
// get the wfs service url defined in project or take the same as the
|
||||
// wms service url
|
||||
@ -113,7 +113,7 @@ namespace QgsWms
|
||||
// WCS layers
|
||||
QStringList wcsLayerIds = QgsServerProjectUtils::wcsLayerIds( *project );
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, project->mapLayers() )
|
||||
for ( QgsMapLayer *layer : project->mapLayers() )
|
||||
{
|
||||
QString name = layer->name();
|
||||
if ( useLayerIds )
|
||||
|
@ -61,11 +61,12 @@ namespace QgsWms
|
||||
const QgsProject *project );
|
||||
|
||||
void appendLayerBoundingBox( QDomDocument &doc, QDomElement &layerElem, const QgsRectangle &layerExtent,
|
||||
const QgsCoordinateReferenceSystem &layerCRS, const QString &crsText );
|
||||
const QgsCoordinateReferenceSystem &layerCRS, const QString &crsText,
|
||||
const QgsProject *project );
|
||||
|
||||
void appendLayerBoundingBoxes( QDomDocument &doc, QDomElement &layerElem, const QgsRectangle &lExtent,
|
||||
const QgsCoordinateReferenceSystem &layerCRS, const QStringList &crsList,
|
||||
const QStringList &constrainedCrsList );
|
||||
const QStringList &constrainedCrsList, const QgsProject *project );
|
||||
|
||||
void appendCrsElementToLayer( QDomDocument &doc, QDomElement &layerElement, const QDomElement &precedingElement,
|
||||
const QString &crsText );
|
||||
@ -92,43 +93,61 @@ namespace QgsWms
|
||||
const QString &version, const QgsServerRequest &request,
|
||||
QgsServerResponse &response, bool projectSettings )
|
||||
{
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
|
||||
QDomDocument doc;
|
||||
const QDomDocument *capabilitiesDocument = nullptr;
|
||||
|
||||
// Data for WMS capabilities server memory cache
|
||||
QString configFilePath = serverIface->configFilePath();
|
||||
QgsCapabilitiesCache *capabilitiesCache = serverIface->capabilitiesCache();
|
||||
|
||||
QStringList cacheKeyList;
|
||||
cacheKeyList << ( projectSettings ? QStringLiteral( "projectSettings" ) : version );
|
||||
cacheKeyList << request.url().host();
|
||||
bool cache = true;
|
||||
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
if ( accessControl )
|
||||
cache = accessControl->fillCacheKey( cacheKeyList );
|
||||
#endif
|
||||
QString cacheKey = cacheKeyList.join( '-' );
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
|
||||
if ( !capabilitiesDocument && cache ) //capabilities xml not in cache plugins
|
||||
{
|
||||
capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
QString cacheKey = cacheKeyList.join( QStringLiteral( "-" ) );
|
||||
const QDomDocument *capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
if ( !capabilitiesDocument ) //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
QgsMessageLog::logMessage( QStringLiteral( "Capabilities document not found in cache" ) );
|
||||
QgsMessageLog::logMessage( QStringLiteral( "WMS capabilities document not found in cache" ) );
|
||||
|
||||
doc = getCapabilities( serverIface, project, version, request, projectSettings );
|
||||
|
||||
if ( cache )
|
||||
if ( cacheManager &&
|
||||
cacheManager->setCachedDocument( &doc, project, request, accessControl ) )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
else if ( cache )
|
||||
{
|
||||
capabilitiesCache->insertCapabilitiesDocument( configFilePath, cacheKey, &doc );
|
||||
capabilitiesDocument = capabilitiesCache->searchCapabilitiesDocument( configFilePath, cacheKey );
|
||||
}
|
||||
if ( !capabilitiesDocument )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
else
|
||||
{
|
||||
doc = doc.cloneNode().toDocument();
|
||||
capabilitiesDocument = &doc;
|
||||
QgsMessageLog::logMessage( QStringLiteral( "Set WMS capabilities document in cache" ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsMessageLog::logMessage( QStringLiteral( "Found capabilities document in cache" ) );
|
||||
QgsMessageLog::logMessage( QStringLiteral( "Found WMS capabilities document in cache" ) );
|
||||
}
|
||||
|
||||
response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
|
||||
@ -148,7 +167,7 @@ namespace QgsWms
|
||||
QUrl href = serviceUrl( request, project );
|
||||
|
||||
//href needs to be a prefix
|
||||
QString hrefString = href.toString( QUrl::FullyDecoded );
|
||||
QString hrefString = href.toString();
|
||||
hrefString.append( href.hasQuery() ? "&" : "?" );
|
||||
|
||||
// XML declaration
|
||||
@ -388,7 +407,7 @@ namespace QgsWms
|
||||
QUrl href = serviceUrl( request, project );
|
||||
|
||||
//href needs to be a prefix
|
||||
QString hrefString = href.toString( QUrl::FullyDecoded );
|
||||
QString hrefString = href.toString();
|
||||
hrefString.append( href.hasQuery() ? "&" : "?" );
|
||||
|
||||
QDomElement capabilityElem = doc.createElement( QStringLiteral( "Capability" )/*wms:Capability*/ );
|
||||
@ -992,7 +1011,7 @@ namespace QgsWms
|
||||
appendCrsElementsToLayer( doc, layerElem, crsList, outputCrsList );
|
||||
|
||||
//Ex_GeographicBoundingBox
|
||||
appendLayerBoundingBoxes( doc, layerElem, l->extent(), l->crs(), crsList, outputCrsList );
|
||||
appendLayerBoundingBoxes( doc, layerElem, l->extent(), l->crs(), crsList, outputCrsList, project );
|
||||
}
|
||||
|
||||
// add details about supported styles of the layer
|
||||
@ -1121,9 +1140,9 @@ namespace QgsWms
|
||||
QUrl href = serviceUrl( request, project );
|
||||
|
||||
//href needs to be a prefix
|
||||
QString hrefString = href.toString( QUrl::FullyDecoded );
|
||||
QString hrefString = href.toString();
|
||||
hrefString.append( href.hasQuery() ? "&" : "?" );
|
||||
Q_FOREACH ( QString styleName, currentLayer->styleManager()->styles() )
|
||||
for ( const QString &styleName : currentLayer->styleManager()->styles() )
|
||||
{
|
||||
QDomElement styleElem = doc.createElement( QStringLiteral( "Style" ) );
|
||||
QDomElement styleNameElem = doc.createElement( QStringLiteral( "Name" ) );
|
||||
@ -1222,7 +1241,7 @@ namespace QgsWms
|
||||
}
|
||||
else //no crs constraint
|
||||
{
|
||||
Q_FOREACH ( const QString &crs, crsList )
|
||||
for ( const QString &crs : crsList )
|
||||
{
|
||||
appendCrsElementToLayer( doc, layerElement, CRSPrecedingElement, crs );
|
||||
}
|
||||
@ -1246,7 +1265,7 @@ namespace QgsWms
|
||||
|
||||
void appendLayerBoundingBoxes( QDomDocument &doc, QDomElement &layerElem, const QgsRectangle &lExtent,
|
||||
const QgsCoordinateReferenceSystem &layerCRS, const QStringList &crsList,
|
||||
const QStringList &constrainedCrsList )
|
||||
const QStringList &constrainedCrsList, const QgsProject *project )
|
||||
{
|
||||
if ( layerElem.isNull() )
|
||||
{
|
||||
@ -1270,9 +1289,7 @@ namespace QgsWms
|
||||
QgsRectangle wgs84BoundingRect;
|
||||
if ( !layerExtent.isNull() )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform exGeoTransform( layerCRS, wgs84 );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform exGeoTransform( layerCRS, wgs84, project );
|
||||
try
|
||||
{
|
||||
wgs84BoundingRect = exGeoTransform.transformBoundingBox( layerExtent );
|
||||
@ -1330,21 +1347,22 @@ namespace QgsWms
|
||||
{
|
||||
for ( int i = constrainedCrsList.size() - 1; i >= 0; --i )
|
||||
{
|
||||
appendLayerBoundingBox( doc, layerElem, layerExtent, layerCRS, constrainedCrsList.at( i ) );
|
||||
appendLayerBoundingBox( doc, layerElem, layerExtent, layerCRS, constrainedCrsList.at( i ), project );
|
||||
}
|
||||
}
|
||||
else //no crs constraint
|
||||
{
|
||||
Q_FOREACH ( const QString &crs, crsList )
|
||||
for ( const QString &crs : crsList )
|
||||
{
|
||||
appendLayerBoundingBox( doc, layerElem, layerExtent, layerCRS, crs );
|
||||
appendLayerBoundingBox( doc, layerElem, layerExtent, layerCRS, crs, project );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void appendLayerBoundingBox( QDomDocument &doc, QDomElement &layerElem, const QgsRectangle &layerExtent,
|
||||
const QgsCoordinateReferenceSystem &layerCRS, const QString &crsText )
|
||||
const QgsCoordinateReferenceSystem &layerCRS, const QString &crsText,
|
||||
const QgsProject *project )
|
||||
{
|
||||
if ( layerElem.isNull() )
|
||||
{
|
||||
@ -1364,9 +1382,7 @@ namespace QgsWms
|
||||
QgsRectangle crsExtent;
|
||||
if ( !layerExtent.isNull() )
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform crsTransform( layerCRS, crs );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform crsTransform( layerCRS, crs, project );
|
||||
try
|
||||
{
|
||||
crsExtent = crsTransform.transformBoundingBox( layerExtent );
|
||||
@ -1479,9 +1495,7 @@ namespace QgsWms
|
||||
}
|
||||
|
||||
//get project crs
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform t( layerCrs, project->crs() );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform t( layerCrs, project->crs(), project );
|
||||
|
||||
//transform
|
||||
try
|
||||
@ -1584,7 +1598,7 @@ namespace QgsWms
|
||||
combinedBBox = mapRect;
|
||||
}
|
||||
}
|
||||
appendLayerBoundingBoxes( doc, groupElem, combinedBBox, groupCRS, combinedCRSSet.toList(), outputCrsList );
|
||||
appendLayerBoundingBoxes( doc, groupElem, combinedBBox, groupCRS, combinedCRSSet.toList(), outputCrsList, project );
|
||||
|
||||
}
|
||||
|
||||
|
@ -311,7 +311,7 @@ namespace QgsWms
|
||||
QUrl href = serviceUrl( request, project );
|
||||
|
||||
//href needs to be a prefix
|
||||
QString hrefString = href.toString( QUrl::FullyDecoded );
|
||||
QString hrefString = href.toString();
|
||||
hrefString.append( href.hasQuery() ? "&" : "?" );
|
||||
|
||||
// COntext Server Element with WMS service URL
|
||||
@ -405,9 +405,7 @@ namespace QgsWms
|
||||
// update combineBBox
|
||||
try
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
QgsCoordinateTransform t( l->crs(), project->crs() );
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
QgsCoordinateTransform t( l->crs(), project->crs(), project );
|
||||
QgsRectangle BBox = t.transformBoundingBox( l->extent() );
|
||||
if ( combinedBBox.isEmpty() )
|
||||
{
|
||||
@ -437,7 +435,7 @@ namespace QgsWms
|
||||
|
||||
void appendOwsLayerStyles( QDomDocument &doc, QDomElement &layerElem, QgsMapLayer *currentLayer )
|
||||
{
|
||||
Q_FOREACH ( QString styleName, currentLayer->styleManager()->styles() )
|
||||
for ( const QString &styleName : currentLayer->styleManager()->styles() )
|
||||
{
|
||||
QDomElement styleListElem = doc.createElement( QStringLiteral( "StyleList" ) );
|
||||
//only one default style in project file mode
|
||||
|
@ -133,7 +133,7 @@ namespace QgsWms
|
||||
// WMS restricted layers
|
||||
QStringList restrictedLayers = QgsServerProjectUtils::wmsRestrictedLayers( *project );
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, project->mapLayers() )
|
||||
for ( QgsMapLayer *layer : project->mapLayers() )
|
||||
{
|
||||
QString name = layer->name();
|
||||
if ( useLayerIds )
|
||||
@ -172,7 +172,7 @@ namespace QgsWms
|
||||
if ( vlayer->isSpatial() )
|
||||
{
|
||||
QString currentStyle = vlayer->styleManager()->currentStyle();
|
||||
Q_FOREACH ( QString styleName, vlayer->styleManager()->styles() )
|
||||
for ( const QString &styleName : vlayer->styleManager()->styles() )
|
||||
{
|
||||
vlayer->styleManager()->setCurrentStyle( styleName );
|
||||
QDomElement styleElem = vlayer->renderer()->writeSld( myDocument, styleName );
|
||||
|
@ -111,9 +111,9 @@ namespace QgsWms
|
||||
|
||||
QgsLayerTreeModelLegendNode *_findLegendNodeForRule( QgsLayerTreeModel *legendModel, const QString &rule )
|
||||
{
|
||||
Q_FOREACH ( QgsLayerTreeLayer *nodeLayer, legendModel->rootGroup()->findLayers() )
|
||||
for ( QgsLayerTreeLayer *nodeLayer : legendModel->rootGroup()->findLayers() )
|
||||
{
|
||||
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel->layerLegendNodes( nodeLayer ) )
|
||||
for ( QgsLayerTreeModelLegendNode *legendNode : legendModel->layerLegendNodes( nodeLayer ) )
|
||||
{
|
||||
if ( legendNode->data( Qt::DisplayRole ).toString() == rule )
|
||||
return legendNode;
|
||||
@ -181,7 +181,7 @@ namespace QgsWms
|
||||
std::reverse( layers.begin(), layers.end() );
|
||||
|
||||
// check permissions
|
||||
Q_FOREACH ( QgsMapLayer *ml, layers )
|
||||
for ( QgsMapLayer *ml : layers )
|
||||
checkLayerReadPermissions( ml );
|
||||
|
||||
// build layer tree model for legend
|
||||
@ -241,7 +241,7 @@ namespace QgsWms
|
||||
{
|
||||
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
|
||||
|
||||
Q_FOREACH ( const QString &id, mapSettings.layerIds() )
|
||||
for ( const QString &id : mapSettings.layerIds() )
|
||||
{
|
||||
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mProject->mapLayer( id ) );
|
||||
if ( !vl || !vl->renderer() )
|
||||
@ -276,7 +276,7 @@ namespace QgsWms
|
||||
context.expressionContext().setFeature( f );
|
||||
if ( moreSymbolsPerFeature )
|
||||
{
|
||||
Q_FOREACH ( QgsSymbol *s, r->originalSymbolsForFeature( f, context ) )
|
||||
for ( QgsSymbol *s : r->originalSymbolsForFeature( f, context ) )
|
||||
usedSymbols.insert( QgsSymbolLayerUtils::symbolProperties( s ) );
|
||||
}
|
||||
else
|
||||
@ -328,11 +328,11 @@ namespace QgsWms
|
||||
|
||||
// configure each layer with opacity, selection filter, ...
|
||||
bool updateMapExtent = mWmsParameters.bbox().isEmpty();
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
checkLayerReadPermissions( layer );
|
||||
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
for ( const QgsWmsParametersLayer ¶m : params )
|
||||
{
|
||||
if ( param.mNickname == layerNickname( *layer ) )
|
||||
{
|
||||
@ -677,11 +677,11 @@ namespace QgsWms
|
||||
|
||||
// configure each layer with opacity, selection filter, ...
|
||||
bool updateMapExtent = mWmsParameters.bbox().isEmpty();
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
checkLayerReadPermissions( layer );
|
||||
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
for ( const QgsWmsParametersLayer ¶m : params )
|
||||
{
|
||||
if ( param.mNickname == layerNickname( *layer ) )
|
||||
{
|
||||
@ -774,7 +774,7 @@ namespace QgsWms
|
||||
// get dxf layers
|
||||
QList< QgsDxfExport::DxfLayer > dxfLayers;
|
||||
int layerIdx = -1;
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
layerIdx++;
|
||||
if ( layer->type() != QgsMapLayer::VectorLayer )
|
||||
@ -784,7 +784,7 @@ namespace QgsWms
|
||||
|
||||
checkLayerReadPermissions( layer );
|
||||
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
for ( const QgsWmsParametersLayer ¶m : params )
|
||||
{
|
||||
if ( param.mNickname == layerNickname( *layer ) )
|
||||
{
|
||||
@ -951,11 +951,11 @@ namespace QgsWms
|
||||
// remove non identifiable layers
|
||||
//removeNonIdentifiableLayers( layers );
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
checkLayerReadPermissions( layer );
|
||||
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
for ( const QgsWmsParametersLayer ¶m : params )
|
||||
{
|
||||
if ( param.mNickname == layerNickname( *layer ) )
|
||||
{
|
||||
@ -1244,11 +1244,11 @@ namespace QgsWms
|
||||
//layers can have assigned a different name for GetCapabilities
|
||||
QHash<QString, QString> layerAliasMap = QgsServerProjectUtils::wmsFeatureInfoLayerAliasMap( *mProject );
|
||||
|
||||
Q_FOREACH ( QString queryLayer, queryLayers )
|
||||
for ( const QString &queryLayer : queryLayers )
|
||||
{
|
||||
bool validLayer = false;
|
||||
bool queryableLayer = true;
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
if ( queryLayer == layerNickname( *layer ) )
|
||||
{
|
||||
@ -1456,8 +1456,7 @@ namespace QgsWms
|
||||
mAccessControl->filterFeatures( layer, fReq );
|
||||
|
||||
QStringList attributes;
|
||||
QgsField field;
|
||||
Q_FOREACH ( field, layer->fields().toList() )
|
||||
for ( const QgsField &field : layer->fields().toList() )
|
||||
{
|
||||
attributes.append( field.name() );
|
||||
}
|
||||
@ -2368,13 +2367,13 @@ namespace QgsWms
|
||||
QStringList restrictedLayersNames;
|
||||
QgsLayerTreeGroup *root = mProject->layerTreeRoot();
|
||||
|
||||
Q_FOREACH ( QString l, restricted )
|
||||
for ( const QString &l : restricted )
|
||||
{
|
||||
QgsLayerTreeGroup *group = root->findGroup( l );
|
||||
if ( group )
|
||||
{
|
||||
QList<QgsLayerTreeLayer *> groupLayers = group->findLayers();
|
||||
Q_FOREACH ( QgsLayerTreeLayer *treeLayer, groupLayers )
|
||||
for ( QgsLayerTreeLayer *treeLayer : groupLayers )
|
||||
{
|
||||
restrictedLayersNames.append( treeLayer->name() );
|
||||
}
|
||||
@ -2387,7 +2386,7 @@ namespace QgsWms
|
||||
|
||||
// build output with names, ids or short name according to the configuration
|
||||
QList<QgsLayerTreeLayer *> layers = root->findLayers();
|
||||
Q_FOREACH ( QgsLayerTreeLayer *layer, layers )
|
||||
for ( QgsLayerTreeLayer *layer : layers )
|
||||
{
|
||||
if ( restrictedLayersNames.contains( layer->name() ) )
|
||||
{
|
||||
@ -2398,7 +2397,7 @@ namespace QgsWms
|
||||
|
||||
void QgsRenderer::initNicknameLayers()
|
||||
{
|
||||
Q_FOREACH ( QgsMapLayer *ml, mProject->mapLayers() )
|
||||
for ( QgsMapLayer *ml : mProject->mapLayers() )
|
||||
{
|
||||
mNicknameLayers[ layerNickname( *ml ) ] = ml;
|
||||
}
|
||||
@ -2469,7 +2468,7 @@ namespace QgsWms
|
||||
|
||||
// try to create highlight layer for each geometry
|
||||
QString crs = mWmsParameters.crs();
|
||||
Q_FOREACH ( QgsWmsParametersHighlightLayer param, params )
|
||||
for ( const QgsWmsParametersHighlightLayer ¶m : params )
|
||||
{
|
||||
// create sld document from symbology
|
||||
QDomDocument sldDoc;
|
||||
@ -2675,7 +2674,7 @@ namespace QgsWms
|
||||
{
|
||||
QList<QgsMapLayer *> layers;
|
||||
|
||||
Q_FOREACH ( QgsWmsParametersLayer param, params )
|
||||
for ( const QgsWmsParametersLayer ¶m : params )
|
||||
{
|
||||
QString nickname = param.mNickname;
|
||||
QString style = param.mStyle;
|
||||
@ -2798,7 +2797,7 @@ namespace QgsWms
|
||||
if ( layer->type() == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer *filteredLayer = qobject_cast<QgsVectorLayer *>( layer );
|
||||
Q_FOREACH ( QString filter, filters )
|
||||
for ( const QString &filter : filters )
|
||||
{
|
||||
if ( filter.startsWith( QStringLiteral( "<" ) ) && filter.endsWith( QStringLiteral( "Filter>" ) ) )
|
||||
{
|
||||
@ -2850,7 +2849,7 @@ namespace QgsWms
|
||||
{
|
||||
QgsFeatureIds selectedIds;
|
||||
|
||||
Q_FOREACH ( const QString &id, fids )
|
||||
for ( const QString &id : fids )
|
||||
{
|
||||
selectedIds.insert( STRING_TO_FID( id ) );
|
||||
}
|
||||
@ -2927,7 +2926,7 @@ namespace QgsWms
|
||||
{
|
||||
QList<QgsMapLayer *> wantedLayers;
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
if ( !layerScaleVisibility( *layer, scaleDenominator ) )
|
||||
continue;
|
||||
@ -2948,7 +2947,7 @@ namespace QgsWms
|
||||
{
|
||||
QList<QgsMapLayer *> wantedLayers;
|
||||
|
||||
Q_FOREACH ( QgsMapLayer *layer, layers )
|
||||
for ( QgsMapLayer *layer : layers )
|
||||
{
|
||||
if ( nonIdentifiableLayers.contains( layer->id() ) )
|
||||
continue;
|
||||
@ -2989,7 +2988,7 @@ namespace QgsWms
|
||||
// build layer tree
|
||||
rootGroup.clear();
|
||||
QList<QgsVectorLayerFeatureCounter *> counters;
|
||||
Q_FOREACH ( QgsMapLayer *ml, layers )
|
||||
for ( QgsMapLayer *ml : layers )
|
||||
{
|
||||
QgsLayerTreeLayer *lt = rootGroup.addLayer( ml );
|
||||
lt->setCustomProperty( QStringLiteral( "showFeatureCount" ), showFeatureCount );
|
||||
@ -3018,7 +3017,7 @@ namespace QgsWms
|
||||
HitTest hitTest;
|
||||
getMap( contentBasedMapSettings, &hitTest );
|
||||
|
||||
Q_FOREACH ( QgsLayerTreeNode *node, rootGroup.children() )
|
||||
for ( QgsLayerTreeNode *node : rootGroup.children() )
|
||||
{
|
||||
Q_ASSERT( QgsLayerTree::isLayer( node ) );
|
||||
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
|
||||
@ -3030,7 +3029,7 @@ namespace QgsWms
|
||||
const SymbolSet &usedSymbols = hitTest[vl];
|
||||
QList<int> order;
|
||||
int i = 0;
|
||||
Q_FOREACH ( const QgsLegendSymbolItem &legendItem, vl->renderer()->legendSymbolItems() )
|
||||
for ( const QgsLegendSymbolItem &legendItem : vl->renderer()->legendSymbolItems() )
|
||||
{
|
||||
QString sProp = QgsSymbolLayerUtils::symbolProperties( legendItem.legacyRuleKey() );
|
||||
if ( usedSymbols.contains( sProp ) )
|
||||
@ -3053,7 +3052,7 @@ namespace QgsWms
|
||||
if ( ! ruleDefined )
|
||||
{
|
||||
QList<QgsLayerTreeNode *> rootChildren = rootGroup.children();
|
||||
Q_FOREACH ( QgsLayerTreeNode *node, rootChildren )
|
||||
for ( QgsLayerTreeNode *node : rootChildren )
|
||||
{
|
||||
if ( QgsLayerTree::isLayer( node ) )
|
||||
{
|
||||
@ -3065,14 +3064,14 @@ namespace QgsWms
|
||||
// rule item titles
|
||||
if ( !drawLegendItemLabel )
|
||||
{
|
||||
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel->layerLegendNodes( nodeLayer ) )
|
||||
for ( QgsLayerTreeModelLegendNode *legendNode : legendModel->layerLegendNodes( nodeLayer ) )
|
||||
{
|
||||
legendNode->setUserLabel( QStringLiteral( " " ) ); // empty string = no override, so let's use one space
|
||||
}
|
||||
}
|
||||
else if ( !drawLegendLayerLabel )
|
||||
{
|
||||
Q_FOREACH ( QgsLayerTreeModelLegendNode *legendNode, legendModel->layerLegendNodes( nodeLayer ) )
|
||||
for ( QgsLayerTreeModelLegendNode *legendNode : legendModel->layerLegendNodes( nodeLayer ) )
|
||||
{
|
||||
if ( legendNode->isEmbeddedInParent() )
|
||||
legendNode->setEmbeddedInParent( false );
|
||||
|
65
src/server/services/wmts/CMakeLists.txt
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
########################################################
|
||||
# Files
|
||||
|
||||
SET (wmts_SRCS
|
||||
qgswmts.cpp
|
||||
qgswmtsutils.cpp
|
||||
qgswmtsgetcapabilities.cpp
|
||||
qgswmtsgettile.cpp
|
||||
qgswmtsgetfeatureinfo.cpp
|
||||
qgswmtsparameters.cpp
|
||||
)
|
||||
|
||||
SET (wmts_MOC_HDRS
|
||||
qgswmtsparameters.h
|
||||
)
|
||||
|
||||
########################################################
|
||||
# Build
|
||||
|
||||
QT5_WRAP_CPP(wmts_MOC_SRCS ${wmts_MOC_HDRS})
|
||||
|
||||
ADD_LIBRARY (wmts MODULE ${wmts_SRCS} ${wmts_MOC_SRCS} ${wmts_MOC_HDRS})
|
||||
|
||||
|
||||
INCLUDE_DIRECTORIES(SYSTEM
|
||||
${GDAL_INCLUDE_DIR}
|
||||
${POSTGRES_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_BINARY_DIR}/src/core
|
||||
${CMAKE_BINARY_DIR}/src/python
|
||||
${CMAKE_BINARY_DIR}/src/analysis
|
||||
${CMAKE_BINARY_DIR}/src/server
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
../wms
|
||||
../../../core
|
||||
../../../core/dxf
|
||||
../../../core/expression
|
||||
../../../core/geometry
|
||||
../../../core/metadata
|
||||
../../../core/raster
|
||||
../../../core/symbology
|
||||
../../../core/layertree
|
||||
../..
|
||||
..
|
||||
.
|
||||
)
|
||||
|
||||
|
||||
TARGET_LINK_LIBRARIES(wmts
|
||||
qgis_core
|
||||
qgis_server
|
||||
)
|
||||
|
||||
|
||||
########################################################
|
||||
# Install
|
||||
|
||||
INSTALL(TARGETS wmts
|
||||
RUNTIME DESTINATION ${QGIS_SERVER_MODULE_DIR}
|
||||
LIBRARY DESTINATION ${QGIS_SERVER_MODULE_DIR}
|
||||
)
|
||||
|
131
src/server/services/wmts/qgswmts.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
qgswmts.cpp
|
||||
-------------------------
|
||||
begin : July 23 , 2018
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgsmodule.h"
|
||||
#include "qgswmtsutils.h"
|
||||
#include "qgswmtsgetcapabilities.h"
|
||||
#include "qgswmtsgettile.h"
|
||||
#include "qgswmtsgetfeatureinfo.h"
|
||||
|
||||
#define QSTR_COMPARE( str, lit )\
|
||||
(str.compare( QStringLiteral( lit ), Qt::CaseInsensitive ) == 0)
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::Service
|
||||
* \brief OGC web service specialized for WMTS
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class Service: public QgsService
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for WMTS service.
|
||||
* \param serverIface Interface for plugins.
|
||||
*/
|
||||
Service( QgsServerInterface *serverIface )
|
||||
: mServerIface( serverIface )
|
||||
{}
|
||||
|
||||
QString name() const override { return QStringLiteral( "WMTS" ); }
|
||||
QString version() const override { return implementationVersion(); }
|
||||
|
||||
bool allowMethod( QgsServerRequest::Method method ) const override
|
||||
{
|
||||
return method == QgsServerRequest::GetMethod || method == QgsServerRequest::PostMethod;
|
||||
}
|
||||
|
||||
void executeRequest( const QgsServerRequest &request, QgsServerResponse &response,
|
||||
const QgsProject *project ) override
|
||||
{
|
||||
Q_UNUSED( project );
|
||||
|
||||
const QgsWmtsParameters params( QUrlQuery( request.url() ) );
|
||||
|
||||
// Set the default version
|
||||
QString versionString = params.version();
|
||||
if ( versionString.isEmpty() )
|
||||
{
|
||||
versionString = version(); // defined in qgswfsutils.h
|
||||
}
|
||||
|
||||
// Get the request
|
||||
QString req = params.value( QgsServerParameter::name( QgsServerParameter::REQUEST ) );
|
||||
if ( req.isEmpty() )
|
||||
{
|
||||
throw QgsServiceException( QStringLiteral( "OperationNotSupported" ),
|
||||
QStringLiteral( "Please check the value of the REQUEST parameter" ) );
|
||||
}
|
||||
|
||||
if ( QSTR_COMPARE( req, "GetCapabilities" ) )
|
||||
{
|
||||
writeGetCapabilities( mServerIface, project, versionString, request, response );
|
||||
}
|
||||
else if ( QSTR_COMPARE( req, "GetTile" ) )
|
||||
{
|
||||
writeGetTile( mServerIface, project, versionString, request, response );
|
||||
}
|
||||
else if ( QSTR_COMPARE( req, "GetFeatureInfo" ) )
|
||||
{
|
||||
writeGetFeatureInfo( mServerIface, project, versionString, request, response );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Operation not supported
|
||||
throw QgsServiceException( QStringLiteral( "OperationNotSupported" ),
|
||||
QStringLiteral( "Request %1 is not supported" ).arg( req ) );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QgsServerInterface *mServerIface = nullptr;
|
||||
};
|
||||
|
||||
|
||||
} // namespace QgsWmts
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmtsModule
|
||||
* \brief Service module specialized for WMTS
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsWmtsModule: public QgsServiceModule
|
||||
{
|
||||
public:
|
||||
void registerSelf( QgsServiceRegistry ®istry, QgsServerInterface *serverIface ) override
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "WMTSModule::registerSelf called" ) );
|
||||
registry.registerService( new QgsWmts::Service( serverIface ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Entry points
|
||||
QGISEXTERN QgsServiceModule *QGS_ServiceModule_Init()
|
||||
{
|
||||
static QgsWmtsModule module;
|
||||
return &module;
|
||||
}
|
||||
QGISEXTERN void QGS_ServiceModule_Exit( QgsServiceModule * )
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
571
src/server/services/wmts/qgswmtsgetcapabilities.cpp
Normal file
@ -0,0 +1,571 @@
|
||||
/***************************************************************************
|
||||
qgswmtsgecapabilities.cpp
|
||||
-------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgswmtsutils.h"
|
||||
#include "qgsserverprojectutils.h"
|
||||
#include "qgswmtsgetcapabilities.h"
|
||||
|
||||
#include "qgsproject.h"
|
||||
#include "qgsexception.h"
|
||||
#include "qgsmapserviceexception.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void appendLayerElements( QDomDocument &doc, QDomElement &contentsElement,
|
||||
QList< layerDef > wmtsLayers, QList< tileMatrixSetDef > tmsList,
|
||||
const QgsProject *project );
|
||||
|
||||
void appendTileMatrixSetElements( QDomDocument &doc, QDomElement &contentsElement,
|
||||
QList< tileMatrixSetDef > tmsList );
|
||||
}
|
||||
|
||||
/**
|
||||
* Output WMTS GetCapabilities response
|
||||
*/
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request, QgsServerResponse &response )
|
||||
{
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
|
||||
QDomDocument doc;
|
||||
const QDomDocument *capabilitiesDocument = nullptr;
|
||||
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager && cacheManager->getCachedDocument( &doc, project, request, accessControl ) )
|
||||
{
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
else //capabilities xml not in cache. Create a new one
|
||||
{
|
||||
doc = createGetCapabilitiesDocument( serverIface, project, version, request );
|
||||
|
||||
if ( cacheManager )
|
||||
{
|
||||
cacheManager->setCachedDocument( &doc, project, request, accessControl );
|
||||
}
|
||||
capabilitiesDocument = &doc;
|
||||
}
|
||||
|
||||
response.setHeader( QStringLiteral( "Content-Type" ), QStringLiteral( "text/xml; charset=utf-8" ) );
|
||||
response.write( capabilitiesDocument->toByteArray() );
|
||||
}
|
||||
|
||||
|
||||
QDomDocument createGetCapabilitiesDocument( QgsServerInterface *serverIface, const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request )
|
||||
{
|
||||
Q_UNUSED( version );
|
||||
|
||||
QDomDocument doc;
|
||||
|
||||
//wmts:Capabilities element
|
||||
QDomElement wmtsCapabilitiesElement = doc.createElement( QStringLiteral( "Capabilities" )/*wmts:Capabilities*/ );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns" ), WMTS_NAMESPACE );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:gml" ), GML_NAMESPACE );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:ows" ), OWS_NAMESPACE );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xlink" ), QStringLiteral( "http://www.w3.org/1999/xlink" ) );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "xmlns:xsi" ), QStringLiteral( "http://www.w3.org/2001/XMLSchema-instance" ) );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "xsi:schemaLocation" ), WMTS_NAMESPACE + " http://schemas.opengis.net/wmts/1.0/wmtsGetCapabilities_response.xsd" );
|
||||
wmtsCapabilitiesElement.setAttribute( QStringLiteral( "version" ), implementationVersion() );
|
||||
doc.appendChild( wmtsCapabilitiesElement );
|
||||
|
||||
//INSERT ServiceIdentification
|
||||
wmtsCapabilitiesElement.appendChild( getServiceIdentificationElement( doc, project ) );
|
||||
|
||||
//INSERT ServiceProvider
|
||||
wmtsCapabilitiesElement.appendChild( getServiceProviderElement( doc, project ) );
|
||||
|
||||
//INSERT OperationsMetadata
|
||||
wmtsCapabilitiesElement.appendChild( getOperationsMetadataElement( doc, project, request ) );
|
||||
|
||||
//INSERT Contents
|
||||
wmtsCapabilitiesElement.appendChild( getContentsElement( doc, serverIface, project ) );
|
||||
|
||||
return doc;
|
||||
|
||||
}
|
||||
|
||||
QDomElement getServiceIdentificationElement( QDomDocument &doc, const QgsProject *project )
|
||||
{
|
||||
//Service identification
|
||||
QDomElement serviceElem = doc.createElement( QStringLiteral( "ows:ServiceIdentification" ) );
|
||||
|
||||
//Service type
|
||||
QDomElement typeElem = doc.createElement( QStringLiteral( "ows:ServiceType" ) );
|
||||
QDomText typeText = doc.createTextNode( QStringLiteral( "OGC WMTS" ) );
|
||||
typeElem.appendChild( typeText );
|
||||
serviceElem.appendChild( typeElem );
|
||||
|
||||
//Service type version
|
||||
QDomElement typeVersionElem = doc.createElement( QStringLiteral( "ows:ServiceTypeVersion" ) );
|
||||
QDomText typeVersionText = doc.createTextNode( implementationVersion() );
|
||||
typeVersionElem.appendChild( typeVersionText );
|
||||
serviceElem.appendChild( typeVersionElem );
|
||||
|
||||
QString title = QgsServerProjectUtils::owsServiceTitle( *project );
|
||||
if ( !title.isEmpty() )
|
||||
{
|
||||
QDomElement titleElem = doc.createElement( QStringLiteral( "ows:Title" ) );
|
||||
QDomText titleText = doc.createTextNode( title );
|
||||
titleElem.appendChild( titleText );
|
||||
serviceElem.appendChild( titleElem );
|
||||
}
|
||||
|
||||
QString abstract = QgsServerProjectUtils::owsServiceAbstract( *project );
|
||||
if ( !abstract.isEmpty() )
|
||||
{
|
||||
QDomElement abstractElem = doc.createElement( QStringLiteral( "ows:Abstract" ) );
|
||||
QDomText abstractText = doc.createCDATASection( abstract );
|
||||
abstractElem.appendChild( abstractText );
|
||||
serviceElem.appendChild( abstractElem );
|
||||
}
|
||||
|
||||
QStringList keywords = QgsServerProjectUtils::owsServiceKeywords( *project );
|
||||
if ( !keywords.isEmpty() )
|
||||
{
|
||||
QDomElement keywordsElem = doc.createElement( QStringLiteral( "ows:Keywords" ) );
|
||||
for ( const QString &k : keywords )
|
||||
{
|
||||
QDomElement keywordElem = doc.createElement( QStringLiteral( "ows:Keyword" ) );
|
||||
QDomText keywordText = doc.createTextNode( k );
|
||||
keywordElem.appendChild( keywordText );
|
||||
keywordsElem.appendChild( keywordElem );
|
||||
}
|
||||
serviceElem.appendChild( keywordsElem );
|
||||
}
|
||||
|
||||
QDomElement feesElem = doc.createElement( QStringLiteral( "ows:Fees" ) );
|
||||
QDomText feesText = doc.createTextNode( QStringLiteral( "None" ) ); // default value if fees are unknown
|
||||
QString fees = QgsServerProjectUtils::owsServiceFees( *project );
|
||||
if ( !fees.isEmpty() )
|
||||
{
|
||||
feesText = doc.createTextNode( fees );
|
||||
}
|
||||
feesElem.appendChild( feesText );
|
||||
serviceElem.appendChild( feesElem );
|
||||
|
||||
QDomElement accessConstraintsElem = doc.createElement( QStringLiteral( "ows:AccessConstraints" ) );
|
||||
QDomText accessConstraintsText = doc.createTextNode( QStringLiteral( "None" ) ); // default value if access constraints are unknown
|
||||
QString accessConstraints = QgsServerProjectUtils::owsServiceAccessConstraints( *project );
|
||||
if ( !accessConstraints.isEmpty() )
|
||||
{
|
||||
accessConstraintsText = doc.createTextNode( accessConstraints );
|
||||
}
|
||||
accessConstraintsElem.appendChild( accessConstraintsText );
|
||||
serviceElem.appendChild( accessConstraintsElem );
|
||||
|
||||
//End
|
||||
return serviceElem;
|
||||
}
|
||||
|
||||
QDomElement getServiceProviderElement( QDomDocument &doc, const QgsProject *project )
|
||||
{
|
||||
//Service provider
|
||||
QDomElement serviceElem = doc.createElement( QStringLiteral( "ows:ServiceProvider" ) );
|
||||
|
||||
QString contactOrganization = QgsServerProjectUtils::owsServiceContactOrganization( *project );
|
||||
if ( !contactOrganization.isEmpty() )
|
||||
{
|
||||
QDomElement contactOrganizationElem = doc.createElement( QStringLiteral( "ows:ProviderName" ) );
|
||||
QDomText contactOrganizationText = doc.createTextNode( contactOrganization );
|
||||
contactOrganizationElem.appendChild( contactOrganizationText );
|
||||
serviceElem.appendChild( contactOrganizationElem );
|
||||
}
|
||||
|
||||
QString onlineResource = QgsServerProjectUtils::owsServiceOnlineResource( *project );
|
||||
if ( !onlineResource.isEmpty() )
|
||||
{
|
||||
QDomElement onlineResourceElem = doc.createElement( QStringLiteral( "ows:ProviderSite" ) );
|
||||
onlineResourceElem.setAttribute( QStringLiteral( "xlink:href" ), onlineResource );
|
||||
serviceElem.appendChild( onlineResourceElem );
|
||||
}
|
||||
|
||||
//Contact information
|
||||
QString contactPerson = QgsServerProjectUtils::owsServiceContactPerson( *project );
|
||||
QString contactPosition = QgsServerProjectUtils::owsServiceContactPosition( *project );
|
||||
QString contactMail = QgsServerProjectUtils::owsServiceContactMail( *project );
|
||||
QString contactPhone = QgsServerProjectUtils::owsServiceContactPhone( *project );
|
||||
if ( !contactPerson.isEmpty() ||
|
||||
!contactPosition.isEmpty() ||
|
||||
!contactMail.isEmpty() ||
|
||||
!contactPhone.isEmpty() )
|
||||
{
|
||||
QDomElement serviceContactElem = doc.createElement( QStringLiteral( "ows:ServiceContact" ) );
|
||||
if ( !contactPerson.isEmpty() )
|
||||
{
|
||||
QDomElement contactPersonElem = doc.createElement( QStringLiteral( "ows:IndividualName" ) );
|
||||
QDomText contactPersonText = doc.createTextNode( contactPerson );
|
||||
contactPersonElem.appendChild( contactPersonText );
|
||||
serviceContactElem.appendChild( contactPersonElem );
|
||||
}
|
||||
if ( !contactPosition.isEmpty() )
|
||||
{
|
||||
QDomElement contactPositionElem = doc.createElement( QStringLiteral( "ows:PositionName" ) );
|
||||
QDomText contactPositionText = doc.createTextNode( contactPosition );
|
||||
contactPositionElem.appendChild( contactPositionText );
|
||||
serviceContactElem.appendChild( contactPositionElem );
|
||||
}
|
||||
if ( !contactMail.isEmpty() ||
|
||||
!contactPhone.isEmpty() )
|
||||
{
|
||||
QDomElement contactInfoElem = doc.createElement( QStringLiteral( "ows:ContactInfo" ) );
|
||||
if ( !contactMail.isEmpty() )
|
||||
{
|
||||
QDomElement contactAddressElem = doc.createElement( QStringLiteral( "ows:Address" ) );
|
||||
QDomElement contactAddressMailElem = doc.createElement( QStringLiteral( "ows:ElectronicMailAddress" ) );
|
||||
QDomText contactAddressMailText = doc.createTextNode( contactMail );
|
||||
contactAddressMailElem.appendChild( contactAddressMailText );
|
||||
contactAddressElem.appendChild( contactAddressMailElem );
|
||||
contactInfoElem.appendChild( contactAddressElem );
|
||||
}
|
||||
if ( !contactPhone.isEmpty() )
|
||||
{
|
||||
QDomElement contactPhoneElem = doc.createElement( QStringLiteral( "ows:Phone" ) );
|
||||
QDomElement contactVoiceElem = doc.createElement( QStringLiteral( "ows:Voice" ) );
|
||||
QDomText contactVoiceText = doc.createTextNode( contactPhone );
|
||||
contactVoiceElem.appendChild( contactVoiceText );
|
||||
contactPhoneElem.appendChild( contactVoiceElem );
|
||||
contactInfoElem.appendChild( contactPhoneElem );
|
||||
}
|
||||
serviceContactElem.appendChild( contactInfoElem );
|
||||
}
|
||||
serviceElem.appendChild( serviceContactElem );
|
||||
}
|
||||
|
||||
//End
|
||||
return serviceElem;
|
||||
}
|
||||
|
||||
QDomElement getOperationsMetadataElement( QDomDocument &doc, const QgsProject *project, const QgsServerRequest &request )
|
||||
{
|
||||
//ows:OperationsMetadata element
|
||||
QDomElement operationsMetadataElement = doc.createElement( QStringLiteral( "ows:OperationsMetadata" )/*ows:OperationsMetadata*/ );
|
||||
|
||||
//ows:Operation element with name GetCapabilities
|
||||
QDomElement getCapabilitiesElement = doc.createElement( QStringLiteral( "ows:Operation" )/*ows:Operation*/ );
|
||||
getCapabilitiesElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetCapabilities" ) );
|
||||
operationsMetadataElement.appendChild( getCapabilitiesElement );
|
||||
|
||||
//ows:DCP
|
||||
QDomElement dcpElement = doc.createElement( QStringLiteral( "ows:DCP" )/*ows:DCP*/ );
|
||||
getCapabilitiesElement.appendChild( dcpElement );
|
||||
QDomElement httpElement = doc.createElement( QStringLiteral( "ows:HTTP" )/*ows:HTTP*/ );
|
||||
dcpElement.appendChild( httpElement );
|
||||
|
||||
//Prepare url
|
||||
QString hrefString = serviceUrl( request, project );
|
||||
|
||||
//ows:Get
|
||||
QDomElement getElement = doc.createElement( QStringLiteral( "ows:Get" )/*ows:Get*/ );
|
||||
getElement.setAttribute( QStringLiteral( "xlink:href" ), hrefString );
|
||||
httpElement.appendChild( getElement );
|
||||
|
||||
//ows:Operation element with name GetTile
|
||||
QDomElement getTileElement = getCapabilitiesElement.cloneNode().toElement();//this is the same as 'GetCapabilities'
|
||||
getTileElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetTile" ) );
|
||||
operationsMetadataElement.appendChild( getTileElement );
|
||||
|
||||
//ows:Operation element with name GetFeatureInfo
|
||||
QDomElement getFeatureInfoElement = getCapabilitiesElement.cloneNode().toElement();//this is the same as 'GetCapabilities'
|
||||
getFeatureInfoElement.setAttribute( QStringLiteral( "name" ), QStringLiteral( "GetFeatureInfo" ) );
|
||||
operationsMetadataElement.appendChild( getFeatureInfoElement );
|
||||
|
||||
// End
|
||||
return operationsMetadataElement;
|
||||
}
|
||||
|
||||
QDomElement getContentsElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project )
|
||||
{
|
||||
/*
|
||||
* Adding layer list in ContentMetadata
|
||||
*/
|
||||
QDomElement contentsElement = doc.createElement( QStringLiteral( "Contents" )/*wmts:Contents*/ );
|
||||
|
||||
QList< tileMatrixSetDef > tmsList = getTileMatrixSetList( project );
|
||||
if ( !tmsList.isEmpty() )
|
||||
{
|
||||
// get layer list
|
||||
QList< layerDef > wmtsLayers = getWmtsLayerList( serverIface, project );
|
||||
if ( !wmtsLayers.isEmpty() )
|
||||
{
|
||||
appendLayerElements( doc, contentsElement, wmtsLayers, tmsList, project );
|
||||
}
|
||||
|
||||
appendTileMatrixSetElements( doc, contentsElement, tmsList );
|
||||
}
|
||||
|
||||
//End
|
||||
return contentsElement;
|
||||
}
|
||||
namespace
|
||||
{
|
||||
void appendLayerElements( QDomDocument &doc, QDomElement &contentsElement,
|
||||
QList< layerDef > wmtsLayers, QList< tileMatrixSetDef > tmsList,
|
||||
const QgsProject *project )
|
||||
{
|
||||
QgsCoordinateReferenceSystem wgs84 = QgsCoordinateReferenceSystem::fromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
|
||||
// Define InfoFormat helper
|
||||
std::function < void ( QDomElement &, const QString & ) > appendInfoFormat = [&doc]( QDomElement & elem, const QString & format )
|
||||
{
|
||||
QDomElement formatElem = doc.createElement( QStringLiteral( "InfoFormat" )/*wmts:InfoFormat*/ );
|
||||
formatElem.appendChild( doc.createTextNode( format ) );
|
||||
elem.appendChild( formatElem );
|
||||
};
|
||||
|
||||
for ( const layerDef &wmtsLayer : wmtsLayers )
|
||||
{
|
||||
if ( wmtsLayer.id.isEmpty() )
|
||||
continue;
|
||||
|
||||
QDomElement layerElem = doc.createElement( QStringLiteral( "Layer" ) );
|
||||
|
||||
QDomElement layerIdElem = doc.createElement( QStringLiteral( "ows:Identifier" ) );
|
||||
QDomText layerIdText = doc.createTextNode( wmtsLayer.id );
|
||||
layerIdElem.appendChild( layerIdText );
|
||||
layerElem.appendChild( layerIdElem );
|
||||
|
||||
if ( !wmtsLayer.title.isEmpty() )
|
||||
{
|
||||
// Layer title
|
||||
QDomElement layerTitleElem = doc.createElement( QStringLiteral( "ows:Title" ) );
|
||||
QDomText layerTitleText = doc.createTextNode( wmtsLayer.title );
|
||||
layerTitleElem.appendChild( layerTitleText );
|
||||
layerElem.appendChild( layerTitleElem );
|
||||
}
|
||||
|
||||
if ( !wmtsLayer.abstract.isEmpty() )
|
||||
{
|
||||
// Layer abstract
|
||||
QDomElement layerAbstElem = doc.createElement( QStringLiteral( "ows:Abstract" ) );
|
||||
QDomText layerAbstText = doc.createTextNode( project->title() );
|
||||
layerAbstElem.appendChild( layerAbstText );
|
||||
layerElem.appendChild( layerAbstElem );
|
||||
}
|
||||
|
||||
// WGS84 bounding box
|
||||
QDomElement wgs84BBoxElement = doc.createElement( QStringLiteral( "ows:WGS84BoundingBox" ) );
|
||||
QDomElement wgs84LowerCornerElement = doc.createElement( QStringLiteral( "LowerCorner" ) );
|
||||
QDomText wgs84LowerCornerText = doc.createTextNode( qgsDoubleToString( wmtsLayer.wgs84BoundingRect.xMinimum(), 6 ) + ' ' + qgsDoubleToString( wmtsLayer.wgs84BoundingRect.yMinimum(), 6 ) );
|
||||
wgs84LowerCornerElement.appendChild( wgs84LowerCornerText );
|
||||
wgs84BBoxElement.appendChild( wgs84LowerCornerElement );
|
||||
QDomElement wgs84UpperCornerElement = doc.createElement( QStringLiteral( "UpperCorner" ) );
|
||||
QDomText wgs84UpperCornerText = doc.createTextNode( qgsDoubleToString( wmtsLayer.wgs84BoundingRect.xMaximum(), 6 ) + ' ' + qgsDoubleToString( wmtsLayer.wgs84BoundingRect.yMaximum(), 6 ) );
|
||||
wgs84UpperCornerElement.appendChild( wgs84UpperCornerText );
|
||||
wgs84BBoxElement.appendChild( wgs84UpperCornerElement );
|
||||
layerElem.appendChild( wgs84BBoxElement );
|
||||
|
||||
// Other bounding boxes
|
||||
for ( const tileMatrixSetDef &tms : tmsList )
|
||||
{
|
||||
if ( tms.ref == QLatin1String( "EPSG:4326" ) )
|
||||
continue;
|
||||
|
||||
QgsRectangle rect;
|
||||
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( tms.ref );
|
||||
QgsCoordinateTransform exGeoTransform( wgs84, crs, project );
|
||||
try
|
||||
{
|
||||
rect = exGeoTransform.transformBoundingBox( wmtsLayer.wgs84BoundingRect );
|
||||
}
|
||||
catch ( const QgsCsException & )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QDomElement bboxElement = doc.createElement( QStringLiteral( "ows:BoundingBox" ) );
|
||||
bboxElement.setAttribute( QStringLiteral( "crs" ), tms.ref );
|
||||
QDomElement lowerCornerElement = doc.createElement( QStringLiteral( "LowerCorner" ) );
|
||||
QDomText lowerCornerText = doc.createTextNode( qgsDoubleToString( rect.xMinimum(), 6 ) + ' ' + qgsDoubleToString( rect.yMinimum(), 6 ) );
|
||||
lowerCornerElement.appendChild( lowerCornerText );
|
||||
bboxElement.appendChild( lowerCornerElement );
|
||||
QDomElement upperCornerElement = doc.createElement( QStringLiteral( "UpperCorner" ) );
|
||||
QDomText upperCornerText = doc.createTextNode( qgsDoubleToString( rect.xMaximum(), 6 ) + ' ' + qgsDoubleToString( rect.yMaximum(), 6 ) );
|
||||
upperCornerElement.appendChild( upperCornerText );
|
||||
bboxElement.appendChild( upperCornerElement );
|
||||
layerElem.appendChild( bboxElement );
|
||||
}
|
||||
|
||||
// Layer Style
|
||||
QDomElement layerStyleElem = doc.createElement( QStringLiteral( "Style" ) );
|
||||
layerStyleElem.setAttribute( QStringLiteral( "isDefault" ), QStringLiteral( "true" ) );
|
||||
QDomElement layerStyleIdElem = doc.createElement( QStringLiteral( "ows:Identifier" ) );
|
||||
QDomText layerStyleIdText = doc.createTextNode( QStringLiteral( "default" ) );
|
||||
layerStyleIdElem.appendChild( layerStyleIdText );
|
||||
layerStyleElem.appendChild( layerStyleIdElem );
|
||||
QDomElement layerStyleTitleElem = doc.createElement( QStringLiteral( "ows:Title" ) );
|
||||
QDomText layerStyleTitleText = doc.createTextNode( QStringLiteral( "default" ) );
|
||||
layerStyleTitleElem.appendChild( layerStyleTitleText );
|
||||
layerStyleElem.appendChild( layerStyleTitleElem );
|
||||
layerElem.appendChild( layerStyleElem );
|
||||
|
||||
for ( const QString &format : wmtsLayer.formats )
|
||||
{
|
||||
QDomElement layerFormatElem = doc.createElement( QStringLiteral( "Format" ) );
|
||||
QDomText layerFormatText = doc.createTextNode( format );
|
||||
layerFormatElem.appendChild( layerFormatText );
|
||||
layerElem.appendChild( layerFormatElem );
|
||||
}
|
||||
|
||||
if ( wmtsLayer.queryable )
|
||||
{
|
||||
appendInfoFormat( layerElem, QStringLiteral( "text/plain" ) );
|
||||
appendInfoFormat( layerElem, QStringLiteral( "text/html" ) );
|
||||
appendInfoFormat( layerElem, QStringLiteral( "text/xml" ) );
|
||||
appendInfoFormat( layerElem, QStringLiteral( "application/vnd.ogc.gml" ) );
|
||||
appendInfoFormat( layerElem, QStringLiteral( "application/vnd.ogc.gml/3.1.1" ) );
|
||||
}
|
||||
|
||||
for ( const tileMatrixSetDef &tms : tmsList )
|
||||
{
|
||||
tileMatrixSetLinkDef tmsl = getLayerTileMatrixSetLink( wmtsLayer, tms, project );
|
||||
if ( tmsl.ref.isEmpty() || tmsl.ref != tms.ref )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//wmts:TileMatrixSetLink
|
||||
QDomElement tmslElement = doc.createElement( QStringLiteral( "TileMatrixSetLink" )/*wmts:TileMatrixSetLink*/ );
|
||||
|
||||
QDomElement identifierElem = doc.createElement( QStringLiteral( "TileMatrixSet" ) );
|
||||
QDomText identifierText = doc.createTextNode( tms.ref );
|
||||
identifierElem.appendChild( identifierText );
|
||||
tmslElement.appendChild( identifierElem );
|
||||
|
||||
//wmts:TileMatrixSetLimits
|
||||
QDomElement tmsLimitsElement = doc.createElement( QStringLiteral( "TileMatrixSetLimits" )/*wmts:TileMatrixSetLimits*/ );
|
||||
for ( int tmIdx : tmsl.tileMatrixLimits.keys() )
|
||||
{
|
||||
QDomElement tmLimitsElement = doc.createElement( QStringLiteral( "TileMatrixLimits" )/*wmts:TileMatrixLimits*/ );
|
||||
|
||||
QDomElement tmIdentifierElem = doc.createElement( QStringLiteral( "TileMatrix" ) );
|
||||
QDomText tmIdentifierText = doc.createTextNode( QString::number( tmIdx ) );
|
||||
tmIdentifierElem.appendChild( tmIdentifierText );
|
||||
tmLimitsElement.appendChild( tmIdentifierElem );
|
||||
|
||||
tileMatrixLimitDef tml = tmsl.tileMatrixLimits[tmIdx];
|
||||
|
||||
QDomElement minTileColElem = doc.createElement( QStringLiteral( "MinTileCol" ) );
|
||||
QDomText minTileColText = doc.createTextNode( QString::number( tml.minCol ) );
|
||||
minTileColElem.appendChild( minTileColText );
|
||||
tmLimitsElement.appendChild( minTileColElem );
|
||||
|
||||
QDomElement maxTileColElem = doc.createElement( QStringLiteral( "MaxTileCol" ) );
|
||||
QDomText maxTileColText = doc.createTextNode( QString::number( tml.maxCol ) );
|
||||
maxTileColElem.appendChild( maxTileColText );
|
||||
tmLimitsElement.appendChild( maxTileColElem );
|
||||
|
||||
QDomElement minTileRowElem = doc.createElement( QStringLiteral( "MinTileRow" ) );
|
||||
QDomText minTileRowText = doc.createTextNode( QString::number( tml.minRow ) );
|
||||
minTileRowElem.appendChild( minTileRowText );
|
||||
tmLimitsElement.appendChild( minTileRowElem );
|
||||
|
||||
QDomElement maxTileRowElem = doc.createElement( QStringLiteral( "MaxTileRow" ) );
|
||||
QDomText maxTileRowText = doc.createTextNode( QString::number( tml.maxRow ) );
|
||||
maxTileRowElem.appendChild( maxTileRowText );
|
||||
tmLimitsElement.appendChild( maxTileRowElem );
|
||||
|
||||
tmsLimitsElement.appendChild( tmLimitsElement );
|
||||
}
|
||||
tmslElement.appendChild( tmsLimitsElement );
|
||||
|
||||
layerElem.appendChild( tmslElement );
|
||||
}
|
||||
|
||||
contentsElement.appendChild( layerElem );
|
||||
}
|
||||
}
|
||||
|
||||
void appendTileMatrixSetElements( QDomDocument &doc, QDomElement &contentsElement,
|
||||
QList< tileMatrixSetDef > tmsList )
|
||||
{
|
||||
for ( const tileMatrixSetDef &tms : tmsList )
|
||||
{
|
||||
//wmts:TileMatrixSet
|
||||
QDomElement tmsElement = doc.createElement( QStringLiteral( "TileMatrixSet" )/*wmts:TileMatrixSet*/ );
|
||||
|
||||
QDomElement identifierElem = doc.createElement( QStringLiteral( "ows:Identifier" ) );
|
||||
QDomText identifierText = doc.createTextNode( tms.ref );
|
||||
identifierElem.appendChild( identifierText );
|
||||
tmsElement.appendChild( identifierElem );
|
||||
|
||||
QDomElement crsElem = doc.createElement( QStringLiteral( "ows:SupportedCRS" ) );
|
||||
QDomText crsText = doc.createTextNode( tms.ref );
|
||||
crsElem.appendChild( crsText );
|
||||
tmsElement.appendChild( crsElem );
|
||||
|
||||
//wmts:TileMatrix
|
||||
int tmIdx = 0;
|
||||
for ( const tileMatrixDef &tm : tms.tileMatrixList )
|
||||
{
|
||||
QDomElement tmElement = doc.createElement( QStringLiteral( "TileMatrix" )/*wmts:TileMatrix*/ );
|
||||
|
||||
QDomElement tmIdentifierElem = doc.createElement( QStringLiteral( "ows:Identifier" ) );
|
||||
QDomText tmIdentifierText = doc.createTextNode( QString::number( tmIdx ) );
|
||||
tmIdentifierElem.appendChild( tmIdentifierText );
|
||||
tmElement.appendChild( tmIdentifierElem );
|
||||
|
||||
QDomElement tmScaleDenomElem = doc.createElement( QStringLiteral( "ScaleDenominator" ) );
|
||||
QDomText tmScaleDenomText = doc.createTextNode( qgsDoubleToString( tm.scaleDenominator, 6 ) );
|
||||
tmScaleDenomElem.appendChild( tmScaleDenomText );
|
||||
tmElement.appendChild( tmScaleDenomElem );
|
||||
|
||||
QDomElement tmTopLeftCornerElem = doc.createElement( QStringLiteral( "TopLeftCorner" ) );
|
||||
QDomText tmTopLeftCornerText = doc.createTextNode( qgsDoubleToString( tm.left, 6 ) + ' ' + qgsDoubleToString( tm.top, 6 ) );
|
||||
tmTopLeftCornerElem.appendChild( tmTopLeftCornerText );
|
||||
tmElement.appendChild( tmTopLeftCornerElem );
|
||||
|
||||
QDomElement tmTileWidthElem = doc.createElement( QStringLiteral( "TileWidth" ) );
|
||||
QDomText tmTileWidthText = doc.createTextNode( QString::number( 256 ) );
|
||||
tmTileWidthElem.appendChild( tmTileWidthText );
|
||||
tmElement.appendChild( tmTileWidthElem );
|
||||
|
||||
QDomElement tmTileHeightElem = doc.createElement( QStringLiteral( "TileHeight" ) );
|
||||
QDomText tmTileHeightText = doc.createTextNode( QString::number( 256 ) );
|
||||
tmTileHeightElem.appendChild( tmTileHeightText );
|
||||
tmElement.appendChild( tmTileHeightElem );
|
||||
|
||||
QDomElement tmColElem = doc.createElement( QStringLiteral( "MatrixWidth" ) );
|
||||
QDomText tmColText = doc.createTextNode( QString::number( tm.col ) );
|
||||
tmColElem.appendChild( tmColText );
|
||||
tmElement.appendChild( tmColElem );
|
||||
|
||||
QDomElement tmRowElem = doc.createElement( QStringLiteral( "MatrixHeight" ) );
|
||||
QDomText tmRowText = doc.createTextNode( QString::number( tm.row ) );
|
||||
tmRowElem.appendChild( tmRowText );
|
||||
tmElement.appendChild( tmRowElem );
|
||||
|
||||
tmsElement.appendChild( tmElement );
|
||||
++tmIdx;
|
||||
}
|
||||
|
||||
contentsElement.appendChild( tmsElement );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace QgsWmts
|
||||
|
||||
|
||||
|
62
src/server/services/wmts/qgswmtsgetcapabilities.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
qgswmtsgecapabilities.h
|
||||
-------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 QGSWMTSGETCAPABILITIES_H
|
||||
#define QGSWMTSGETCAPABILITIES_H
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
/**
|
||||
* Create Contents element for get capabilities document
|
||||
*/
|
||||
QDomElement getContentsElement( QDomDocument &doc, QgsServerInterface *serverIface, const QgsProject *project );
|
||||
|
||||
/**
|
||||
* Create OperationsMetadata element for get capabilities document
|
||||
*/
|
||||
QDomElement getOperationsMetadataElement( QDomDocument &doc, const QgsProject *project, const QgsServerRequest &request );
|
||||
|
||||
/**
|
||||
* Create ServiceProvider element for get capabilities document
|
||||
*/
|
||||
QDomElement getServiceProviderElement( QDomDocument &doc, const QgsProject *project );
|
||||
|
||||
/**
|
||||
* Create ServiceIdentification element for get capabilities document
|
||||
*/
|
||||
QDomElement getServiceIdentificationElement( QDomDocument &doc, const QgsProject *project );
|
||||
|
||||
/**
|
||||
* Create get capabilities document
|
||||
*/
|
||||
QDomDocument createGetCapabilitiesDocument( QgsServerInterface *serverIface,
|
||||
const QgsProject *project, const QString &version,
|
||||
const QgsServerRequest &request );
|
||||
|
||||
/**
|
||||
* Output WCS GetCapabilities response
|
||||
*/
|
||||
void writeGetCapabilities( QgsServerInterface *serverIface, const QgsProject *project,
|
||||
const QString &version, const QgsServerRequest &request,
|
||||
QgsServerResponse &response );
|
||||
|
||||
} // namespace QgsWcs
|
||||
|
||||
#endif
|
||||
|
52
src/server/services/wmts/qgswmtsgetfeatureinfo.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
qgswmtsgetfeatureinfo.cpp
|
||||
-------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgswmtsutils.h"
|
||||
#include "qgswmtsparameters.h"
|
||||
#include "qgswmtsgetfeatureinfo.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
void writeGetFeatureInfo( QgsServerInterface *serverIface, const QgsProject *project,
|
||||
const QString &version, const QgsServerRequest &request,
|
||||
QgsServerResponse &response )
|
||||
{
|
||||
Q_UNUSED( version );
|
||||
const QgsWmtsParameters params( QUrlQuery( request.url() ) );
|
||||
|
||||
// WMS query
|
||||
QUrlQuery query = translateWmtsParamToWmsQueryItem( QStringLiteral( "GetFeatureInfo" ), params, project, serverIface );
|
||||
|
||||
// GetFeatureInfo query items
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::QUERY_LAYERS ), params.layer() );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::I ), params.i() );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::J ), params.j() );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::INFO_FORMAT ), params.infoFormatAsString() );
|
||||
|
||||
QgsServerParameters wmsParams( query );
|
||||
QgsServerRequest wmsRequest( "?" + query.query( QUrl::FullyDecoded ) );
|
||||
QgsService *service = serverIface->serviceRegistry()->getService( wmsParams.service(), wmsParams.version() );
|
||||
service->executeRequest( wmsRequest, response, project );
|
||||
}
|
||||
|
||||
} // namespace QgsWmts
|
||||
|
||||
|
||||
|
||||
|
28
src/server/services/wmts/qgswmtsgetfeatureinfo.h
Normal file
@ -0,0 +1,28 @@
|
||||
/***************************************************************************
|
||||
qgswmtsgetfeatureinfo.h
|
||||
-------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
/**
|
||||
* Output GetFeatureInfo response
|
||||
*/
|
||||
void writeGetFeatureInfo( QgsServerInterface *serverIface, const QgsProject *project,
|
||||
const QString &version, const QgsServerRequest &request,
|
||||
QgsServerResponse &response );
|
||||
|
||||
} // namespace QgsWmts
|
84
src/server/services/wmts/qgswmtsgettile.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/***************************************************************************
|
||||
qgswmtsgettile.cpp
|
||||
-------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgswmtsutils.h"
|
||||
#include "qgswmtsparameters.h"
|
||||
#include "qgswmtsgettile.h"
|
||||
|
||||
#include <QImage>
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
void writeGetTile( QgsServerInterface *serverIface, const QgsProject *project,
|
||||
const QString &version, const QgsServerRequest &request,
|
||||
QgsServerResponse &response )
|
||||
{
|
||||
Q_UNUSED( version );
|
||||
const QgsWmtsParameters params( QUrlQuery( request.url() ) );
|
||||
|
||||
// WMS query
|
||||
QUrlQuery query = translateWmtsParamToWmsQueryItem( QStringLiteral( "GetMap" ), params, project, serverIface );
|
||||
|
||||
// Get cached image
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
QgsServerCacheManager *cacheManager = serverIface->cacheManager();
|
||||
if ( cacheManager )
|
||||
{
|
||||
QgsWmtsParameters::Format f = params.format();
|
||||
QString contentType;
|
||||
QString saveFormat;
|
||||
std::unique_ptr<QImage> image;
|
||||
if ( f == QgsWmtsParameters::Format::JPG )
|
||||
{
|
||||
contentType = QStringLiteral( "image/jpeg" );
|
||||
saveFormat = QStringLiteral( "JPEG" );
|
||||
image = qgis::make_unique<QImage>( 256, 256, QImage::Format_RGB32 );
|
||||
}
|
||||
else
|
||||
{
|
||||
contentType = QStringLiteral( "image/png" );
|
||||
saveFormat = QStringLiteral( "PNG" );
|
||||
image = qgis::make_unique<QImage>( 256, 256, QImage::Format_ARGB32_Premultiplied );
|
||||
}
|
||||
|
||||
QByteArray content = cacheManager->getCachedImage( project, request, accessControl );
|
||||
if ( !content.isEmpty() && image->loadFromData( content ) )
|
||||
{
|
||||
response.setHeader( QStringLiteral( "Content-Type" ), contentType );
|
||||
image->save( response.io(), qPrintable( saveFormat ) );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QgsServerParameters wmsParams( query );
|
||||
QgsServerRequest wmsRequest( "?" + query.query( QUrl::FullyDecoded ) );
|
||||
QgsService *service = serverIface->serviceRegistry()->getService( wmsParams.service(), wmsParams.version() );
|
||||
service->executeRequest( wmsRequest, response, project );
|
||||
if ( cacheManager )
|
||||
{
|
||||
QByteArray content = response.data();
|
||||
if ( !content.isEmpty() )
|
||||
cacheManager->setCachedImage( &content, project, request, accessControl );
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QgsWmts
|
||||
|
||||
|
||||
|
||||
|
28
src/server/services/wmts/qgswmtsgettile.h
Normal file
@ -0,0 +1,28 @@
|
||||
/***************************************************************************
|
||||
qgswmtsgettile.h
|
||||
-------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
/**
|
||||
* Output GetTile response
|
||||
*/
|
||||
void writeGetTile( QgsServerInterface *serverIface, const QgsProject *project,
|
||||
const QString &version, const QgsServerRequest &request,
|
||||
QgsServerResponse &response );
|
||||
|
||||
} // namespace QgsWmts
|
310
src/server/services/wmts/qgswmtsparameters.cpp
Normal file
@ -0,0 +1,310 @@
|
||||
/***************************************************************************
|
||||
qgswmtsparameters.cpp
|
||||
--------------------
|
||||
begin : Aug 10, 2018
|
||||
copyright : (C) 2018 by René-Luc Dhont
|
||||
email : rldhont at 3liz 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 "qgswmtsparameters.h"
|
||||
#include "qgsmessagelog.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
//
|
||||
// QgsWmsParameterForWmts
|
||||
//
|
||||
QString QgsWmsParameterForWmts::name( const QgsWmsParameterForWmts::Name name )
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWmsParameterForWmts::Name>() );
|
||||
return metaEnum.valueToKey( name );
|
||||
}
|
||||
|
||||
QgsWmsParameterForWmts::Name QgsWmsParameterForWmts::name( const QString &name )
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWmsParameterForWmts::Name>() );
|
||||
return ( QgsWmsParameterForWmts::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
|
||||
}
|
||||
|
||||
//
|
||||
// QgsWmtsParameter
|
||||
//
|
||||
QgsWmtsParameter::QgsWmtsParameter( const QgsWmtsParameter::Name name,
|
||||
const QVariant::Type type,
|
||||
const QVariant defaultValue )
|
||||
: QgsServerParameterDefinition( type, defaultValue )
|
||||
, mName( name )
|
||||
{
|
||||
}
|
||||
|
||||
int QgsWmtsParameter::toInt() const
|
||||
{
|
||||
bool ok = false;
|
||||
const int val = QgsServerParameterDefinition::toInt( ok );
|
||||
|
||||
if ( !ok )
|
||||
{
|
||||
raiseError();
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void QgsWmtsParameter::raiseError() const
|
||||
{
|
||||
const QString msg = QString( "%1 ('%2') cannot be converted into %3" ).arg( name( mName ), toString(), typeName() );
|
||||
QgsServerParameterDefinition::raiseError( msg );
|
||||
}
|
||||
|
||||
QString QgsWmtsParameter::name( const QgsWmtsParameter::Name name )
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWmtsParameter::Name>() );
|
||||
return metaEnum.valueToKey( name );
|
||||
}
|
||||
|
||||
QgsWmtsParameter::Name QgsWmtsParameter::name( const QString &name )
|
||||
{
|
||||
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWmtsParameter::Name>() );
|
||||
return ( QgsWmtsParameter::Name ) metaEnum.keyToValue( name.toUpper().toStdString().c_str() );
|
||||
}
|
||||
|
||||
//
|
||||
// QgsWmtsParameters
|
||||
//
|
||||
QgsWmtsParameters::QgsWmtsParameters()
|
||||
: QgsServerParameters()
|
||||
{
|
||||
// Available version number
|
||||
mVersions.append( QgsProjectVersion( 1, 0, 0 ) );
|
||||
|
||||
const QgsWmtsParameter pLayer = QgsWmtsParameter( QgsWmtsParameter::LAYER );
|
||||
save( pLayer );
|
||||
|
||||
const QgsWmtsParameter pFormat = QgsWmtsParameter( QgsWmtsParameter::FORMAT );
|
||||
save( pFormat );
|
||||
|
||||
const QgsWmtsParameter pTileMatrix = QgsWmtsParameter( QgsWmtsParameter::TILEMATRIX,
|
||||
QVariant::Int,
|
||||
QVariant( -1 ) );
|
||||
save( pTileMatrix );
|
||||
|
||||
const QgsWmtsParameter pTileRow = QgsWmtsParameter( QgsWmtsParameter::TILEROW,
|
||||
QVariant::Int,
|
||||
QVariant( -1 ) );
|
||||
save( pTileRow );
|
||||
|
||||
const QgsWmtsParameter pTileCol = QgsWmtsParameter( QgsWmtsParameter::TILECOL,
|
||||
QVariant::Int,
|
||||
QVariant( -1 ) );
|
||||
save( pTileCol );
|
||||
|
||||
const QgsWmtsParameter pInfoFormat( QgsWmtsParameter::INFOFORMAT );
|
||||
save( pInfoFormat );
|
||||
|
||||
const QgsWmtsParameter pI( QgsWmtsParameter::I,
|
||||
QVariant::Int,
|
||||
QVariant( -1 ) );
|
||||
save( pI );
|
||||
|
||||
const QgsWmtsParameter pJ( QgsWmtsParameter::J,
|
||||
QVariant::Int,
|
||||
QVariant( -1 ) );
|
||||
save( pJ );
|
||||
}
|
||||
|
||||
QgsWmtsParameters::QgsWmtsParameters( const QgsServerParameters ¶meters )
|
||||
: QgsWmtsParameters()
|
||||
{
|
||||
load( parameters.urlQuery() );
|
||||
}
|
||||
|
||||
bool QgsWmtsParameters::loadParameter( const QString &key, const QString &value )
|
||||
{
|
||||
bool loaded = false;
|
||||
|
||||
const QgsWmtsParameter::Name name = QgsWmtsParameter::name( key );
|
||||
if ( name >= 0 )
|
||||
{
|
||||
mWmtsParameters[name].mValue = value;
|
||||
if ( ! mWmtsParameters[name].isValid() )
|
||||
{
|
||||
mWmtsParameters[name].raiseError();
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void QgsWmtsParameters::save( const QgsWmtsParameter ¶meter )
|
||||
{
|
||||
mWmtsParameters[ parameter.mName ] = parameter;
|
||||
}
|
||||
|
||||
void QgsWmtsParameters::dump() const
|
||||
{
|
||||
log( "WMTS Request parameters:" );
|
||||
for ( auto parameter : mWmtsParameters.toStdMap() )
|
||||
{
|
||||
const QString value = parameter.second.toString();
|
||||
|
||||
if ( ! value.isEmpty() )
|
||||
{
|
||||
const QString name = QgsWmtsParameter::name( parameter.first );
|
||||
log( QStringLiteral( " - %1 : %2" ).arg( name, value ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !version().isEmpty() )
|
||||
log( QStringLiteral( " - VERSION : %1" ).arg( version() ) );
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::layer() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::LAYER ].toString();
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::formatAsString() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::FORMAT ].toString();
|
||||
}
|
||||
|
||||
QgsWmtsParameters::Format QgsWmtsParameters::format() const
|
||||
{
|
||||
QString fStr = formatAsString();
|
||||
|
||||
if ( fStr.isEmpty() )
|
||||
return Format::NONE;
|
||||
|
||||
Format f = Format::PNG;
|
||||
if ( fStr.compare( QLatin1String( "jpg" ), Qt::CaseInsensitive ) == 0
|
||||
|| fStr.compare( QLatin1String( "jpeg" ), Qt::CaseInsensitive ) == 0
|
||||
|| fStr.compare( QLatin1String( "image/jpeg" ), Qt::CaseInsensitive ) == 0 )
|
||||
f = Format::JPG;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::tileMatrixSet() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILEMATRIXSET ].toString();
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::tileMatrix() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILEMATRIX ].toString();
|
||||
}
|
||||
|
||||
int QgsWmtsParameters::tileMatrixAsInt() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILEMATRIX ].toInt();
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::tileRow() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILEROW ].toString();
|
||||
}
|
||||
|
||||
int QgsWmtsParameters::tileRowAsInt() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILEROW ].toInt();
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::tileCol() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILECOL ].toString();
|
||||
}
|
||||
|
||||
int QgsWmtsParameters::tileColAsInt() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::TILECOL ].toInt();
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::infoFormatAsString() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::INFOFORMAT ].toString();
|
||||
}
|
||||
|
||||
QgsWmtsParameters::Format QgsWmtsParameters::infoFormat() const
|
||||
{
|
||||
QString fStr = infoFormatAsString();
|
||||
|
||||
Format f = Format::TEXT;
|
||||
if ( fStr.isEmpty() )
|
||||
return f;
|
||||
|
||||
if ( fStr.startsWith( QLatin1String( "text/xml" ), Qt::CaseInsensitive ) )
|
||||
f = Format::XML;
|
||||
else if ( fStr.startsWith( QLatin1String( "text/html" ), Qt::CaseInsensitive ) )
|
||||
f = Format::HTML;
|
||||
else if ( fStr.startsWith( QLatin1String( "text/plain" ), Qt::CaseInsensitive ) )
|
||||
f = Format::TEXT;
|
||||
else if ( fStr.startsWith( QLatin1String( "application/vnd.ogc.gml" ), Qt::CaseInsensitive ) )
|
||||
f = Format::GML;
|
||||
else
|
||||
f = Format::NONE;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
int QgsWmtsParameters::infoFormatVersion() const
|
||||
{
|
||||
if ( infoFormat() != Format::GML )
|
||||
return -1;
|
||||
|
||||
QString fStr = infoFormatAsString();
|
||||
if ( fStr.startsWith( QLatin1String( "application/vnd.ogc.gml/3" ), Qt::CaseInsensitive ) )
|
||||
return 3;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::i() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::I ].toString();
|
||||
}
|
||||
|
||||
QString QgsWmtsParameters::j() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::J ].toString();
|
||||
}
|
||||
|
||||
int QgsWmtsParameters::iAsInt() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::I ].toInt();
|
||||
}
|
||||
|
||||
int QgsWmtsParameters::jAsInt() const
|
||||
{
|
||||
return mWmtsParameters[ QgsWmtsParameter::J ].toInt();
|
||||
}
|
||||
|
||||
QgsProjectVersion QgsWmtsParameters::versionAsNumber() const
|
||||
{
|
||||
QString vStr = version();
|
||||
QgsProjectVersion version;
|
||||
|
||||
if ( vStr.isEmpty() )
|
||||
version = QgsProjectVersion( 1, 0, 0 ); // default value
|
||||
else if ( mVersions.contains( QgsProjectVersion( vStr ) ) )
|
||||
version = QgsProjectVersion( vStr );
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
void QgsWmtsParameters::log( const QString &msg ) const
|
||||
{
|
||||
QgsMessageLog::logMessage( msg, "Server", Qgis::Info );
|
||||
}
|
||||
}
|
328
src/server/services/wmts/qgswmtsparameters.h
Normal file
@ -0,0 +1,328 @@
|
||||
/***************************************************************************
|
||||
qgswmtsparameters.h
|
||||
-------------------
|
||||
begin : Aug 10, 2018
|
||||
copyright : (C) 2018 by René-Luc Dhont
|
||||
email : rldhont at 3liz 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 QGSWMTSPARAMETERS_H
|
||||
#define QGSWMTSPARAMETERS_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QMetaEnum>
|
||||
|
||||
#include "qgswmtsserviceexception.h"
|
||||
#include "qgsserverrequest.h"
|
||||
#include "qgsprojectversion.h"
|
||||
#include "qgsserverparameters.h"
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::QgsWmsParameterForWmts
|
||||
* \brief WMS parameter used by WMTS service.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsWmsParameterForWmts : public QgsServerParameterDefinition
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
//! Available parameters for translating WMTS requests to WMS requests
|
||||
enum Name
|
||||
{
|
||||
UNKNOWN,
|
||||
LAYERS,
|
||||
STYLES,
|
||||
CRS,
|
||||
BBOX,
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
FORMAT,
|
||||
TRANSPARENT,
|
||||
DPI,
|
||||
QUERY_LAYERS,
|
||||
I,
|
||||
J,
|
||||
INFO_FORMAT
|
||||
};
|
||||
Q_ENUM( Name )
|
||||
|
||||
/**
|
||||
* Converts a parameter's name into its string representation.
|
||||
*/
|
||||
static QString name( const QgsWmsParameterForWmts::Name );
|
||||
|
||||
/**
|
||||
* Converts a string into a parameter's name (UNKNOWN in case of an
|
||||
* invalid string).
|
||||
*/
|
||||
static QgsWmsParameterForWmts::Name name( const QString &name );
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::QgsWmtsParameter
|
||||
* \brief WMTS parameter received from the client.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsWmtsParameter : public QgsServerParameterDefinition
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
//! Available parameters for WMTS requests
|
||||
enum Name
|
||||
{
|
||||
UNKNOWN,
|
||||
LAYER,
|
||||
FORMAT,
|
||||
TILEMATRIXSET,
|
||||
TILEMATRIX,
|
||||
TILEROW,
|
||||
TILECOL,
|
||||
INFOFORMAT,
|
||||
I,
|
||||
J
|
||||
};
|
||||
Q_ENUM( Name )
|
||||
|
||||
/**
|
||||
* Constructor for QgsWmtsParameter.
|
||||
* \param name Name of the WMS parameter
|
||||
* \param type Type of the parameter
|
||||
* \param defaultValue Default value of the parameter
|
||||
*/
|
||||
QgsWmtsParameter( const QgsWmtsParameter::Name name = QgsWmtsParameter::UNKNOWN,
|
||||
const QVariant::Type type = QVariant::String,
|
||||
const QVariant defaultValue = QVariant( "" ) );
|
||||
|
||||
/**
|
||||
* Default destructor for QgsWmtsParameter.
|
||||
*/
|
||||
virtual ~QgsWmtsParameter() = default;
|
||||
|
||||
/**
|
||||
* Converts the parameter into an integer.
|
||||
* \returns An integer
|
||||
* \throws QgsBadRequestException Invalid parameter exception
|
||||
*/
|
||||
int toInt() const;
|
||||
|
||||
/**
|
||||
* Raises an error in case of an invalid conversion.
|
||||
* \throws QgsBadRequestException Invalid parameter exception
|
||||
*/
|
||||
void raiseError() const;
|
||||
|
||||
/**
|
||||
* Converts a parameter's name into its string representation.
|
||||
*/
|
||||
static QString name( const QgsWmtsParameter::Name );
|
||||
|
||||
/**
|
||||
* Converts a string into a parameter's name (UNKNOWN in case of an
|
||||
* invalid string).
|
||||
*/
|
||||
static QgsWmtsParameter::Name name( const QString &name );
|
||||
|
||||
QgsWmtsParameter::Name mName;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::QgsWmtsParameters
|
||||
* \brief Provides an interface to retrieve and manipulate WMTS parameters received from the client.
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsWmtsParameters : public QgsServerParameters
|
||||
{
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
|
||||
//! Output format for the response
|
||||
enum Format
|
||||
{
|
||||
NONE,
|
||||
JPG,
|
||||
PNG,
|
||||
TEXT,
|
||||
XML,
|
||||
HTML,
|
||||
GML
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for WMTS parameters with specific values.
|
||||
* \param parameters Map of parameters where keys are parameters' names.
|
||||
*/
|
||||
QgsWmtsParameters( const QgsServerParameters ¶meters );
|
||||
|
||||
/**
|
||||
* Constructor for WMTS parameters with default values only.
|
||||
*/
|
||||
QgsWmtsParameters();
|
||||
|
||||
/**
|
||||
* Default destructor for QgsWmtsParameters.
|
||||
*/
|
||||
virtual ~QgsWmtsParameters() = default;
|
||||
|
||||
/**
|
||||
* Dumps parameters.
|
||||
*/
|
||||
void dump() const;
|
||||
|
||||
/**
|
||||
* Returns VERSION parameter if defined or its default value.
|
||||
* \returns version
|
||||
*/
|
||||
QgsProjectVersion versionAsNumber() const;
|
||||
|
||||
/**
|
||||
* Returns LAYER parameter as a string.
|
||||
* \returns layer parameter as string
|
||||
*/
|
||||
QString layer() const;
|
||||
|
||||
/**
|
||||
* Returns FORMAT parameter as a string.
|
||||
* \returns Format parameter as string
|
||||
*/
|
||||
QString formatAsString() const;
|
||||
|
||||
/**
|
||||
* Returns format. If the FORMAT parameter is not used, then the
|
||||
* default value is NONE.
|
||||
* \returns format
|
||||
*/
|
||||
Format format() const;
|
||||
|
||||
/**
|
||||
* Returns TILEMATRIXSET parameter as a string.
|
||||
* \returns tileMatrixSet parameter as string
|
||||
*/
|
||||
QString tileMatrixSet() const;
|
||||
|
||||
/**
|
||||
* Returns TILEMATRIX parameter as a string.
|
||||
* \returns tileMatrix parameter as string
|
||||
*/
|
||||
QString tileMatrix() const;
|
||||
|
||||
/**
|
||||
* Returns TILEMATRIX parameter as an int or its default value if not
|
||||
* defined. An exception is raised if TILEMATRIX is defined and cannot be
|
||||
* converted.
|
||||
* \returns tileMatrix parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int tileMatrixAsInt() const;
|
||||
|
||||
/**
|
||||
* Returns TILEROW parameter as a string.
|
||||
* \returns tileRow parameter as string
|
||||
*/
|
||||
QString tileRow() const;
|
||||
|
||||
/**
|
||||
* Returns TILEROW parameter as an int or its default value if not
|
||||
* defined. An exception is raised if TILEROW is defined and cannot be
|
||||
* converted.
|
||||
* \returns tileRow parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int tileRowAsInt() const;
|
||||
|
||||
/**
|
||||
* Returns TILECOL parameter as a string.
|
||||
* \returns tileCol parameter as string
|
||||
*/
|
||||
QString tileCol() const;
|
||||
|
||||
/**
|
||||
* Returns TILECOL parameter as an int or its default value if not
|
||||
* defined. An exception is raised if TILECOL is defined and cannot be
|
||||
* converted.
|
||||
* \returns tileCol parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int tileColAsInt() const;
|
||||
|
||||
/**
|
||||
* Returns INFO_FORMAT parameter as a string.
|
||||
* \returns INFO_FORMAT parameter as string
|
||||
*/
|
||||
QString infoFormatAsString() const;
|
||||
|
||||
/**
|
||||
* Returns infoFormat. If the INFO_FORMAT parameter is not used, then the
|
||||
* default value is text/plain.
|
||||
* \returns infoFormat
|
||||
*/
|
||||
Format infoFormat() const;
|
||||
|
||||
/**
|
||||
* Returns the infoFormat version for GML. If the INFO_FORMAT is not GML,
|
||||
* then the default value is -1.
|
||||
* \returns infoFormat version
|
||||
*/
|
||||
int infoFormatVersion() const;
|
||||
|
||||
/**
|
||||
* Returns I parameter or an empty string if not defined.
|
||||
* \returns i parameter
|
||||
*/
|
||||
QString i() const;
|
||||
|
||||
/**
|
||||
* Returns I parameter as an int or its default value if not
|
||||
* defined. An exception is raised if I is defined and cannot be
|
||||
* converted.
|
||||
* \returns i parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int iAsInt() const;
|
||||
|
||||
/**
|
||||
* Returns J parameter or an empty string if not defined.
|
||||
* \returns j parameter
|
||||
*/
|
||||
QString j() const;
|
||||
|
||||
/**
|
||||
* Returns J parameter as an int or its default value if not
|
||||
* defined. An exception is raised if J is defined and cannot be
|
||||
* converted.
|
||||
* \returns j parameter
|
||||
* \throws QgsBadRequestException
|
||||
*/
|
||||
int jAsInt() const;
|
||||
|
||||
private:
|
||||
bool loadParameter( const QString &name, const QString &key ) override;
|
||||
void save( const QgsWmtsParameter ¶meter );
|
||||
|
||||
void log( const QString &msg ) const;
|
||||
|
||||
QList<QgsProjectVersion> mVersions;
|
||||
QMap<QgsWmtsParameter::Name, QgsWmtsParameter> mWmtsParameters;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
105
src/server/services/wmts/qgswmtsserviceexception.h
Normal file
@ -0,0 +1,105 @@
|
||||
/***************************************************************************
|
||||
qgswmtsserviceexception.h
|
||||
------------------------
|
||||
begin : July 23, 2018
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 QGSWMTSSERVICEEXCEPTION_H
|
||||
#define QGSWMTSSERVICEEXCEPTION_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "qgsserverexception.h"
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::QgsServiceException
|
||||
* \brief Exception class for WMTS services
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsServiceException : public QgsOgcServiceException
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsServiceException (empty locator attribute).
|
||||
* \param code Error code name
|
||||
* \param message Exception message to return to the client
|
||||
* \param responseCode HTTP error code
|
||||
*/
|
||||
QgsServiceException( const QString &code, const QString &message,
|
||||
int responseCode = 200 )
|
||||
: QgsOgcServiceException( code, message, QString(), responseCode, QStringLiteral( "1.0.0" ) )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Constructor for QgsServiceException.
|
||||
* \param code Error code name
|
||||
* \param message Exception message to return to the client
|
||||
* \param locator Locator attribute according to OGC specifications
|
||||
* \param responseCode HTTP error code
|
||||
*/
|
||||
QgsServiceException( const QString &code, const QString &message, const QString &locator,
|
||||
int responseCode = 200 )
|
||||
: QgsOgcServiceException( code, message, locator, responseCode, QStringLiteral( "1.0.0" ) )
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::QgsSecurityAccessException
|
||||
* \brief Exception thrown when data access violates access controls
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsSecurityAccessException: public QgsServiceException
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsSecurityAccessException (Security code name).
|
||||
* \param message Exception message to return to the client
|
||||
* \param locator Locator attribute according to OGC specifications
|
||||
*/
|
||||
QgsSecurityAccessException( const QString &message, const QString &locator = QString() )
|
||||
: QgsServiceException( QStringLiteral( "Security" ), message, locator, 403 )
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* \class QgsWmts::QgsRequestNotWellFormedException
|
||||
* \brief Exception thrown in case of malformed request
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
class QgsRequestNotWellFormedException: public QgsServiceException
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsRequestNotWellFormedException (RequestNotWellFormed code name).
|
||||
* \param message Exception message to return to the client
|
||||
* \param locator Locator attribute according to OGC specifications
|
||||
*/
|
||||
QgsRequestNotWellFormedException( const QString &message, const QString &locator = QString() )
|
||||
: QgsServiceException( QStringLiteral( "RequestNotWellFormed" ), message, locator, 400 )
|
||||
{}
|
||||
};
|
||||
} // namespace QgsWmts
|
||||
|
||||
#endif
|
||||
|
719
src/server/services/wmts/qgswmtsutils.cpp
Normal file
@ -0,0 +1,719 @@
|
||||
/***************************************************************************
|
||||
qgswmtsutils.cpp
|
||||
-------------------------
|
||||
begin : July 23, 2018
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 "qgswmtsutils.h"
|
||||
#include "qgswmtsparameters.h"
|
||||
#include "qgsconfigcache.h"
|
||||
#include "qgsserverprojectutils.h"
|
||||
|
||||
#include "qgsproject.h"
|
||||
#include "qgsexception.h"
|
||||
#include "qgsmapserviceexception.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
#include "qgslayertree.h"
|
||||
#include "qgslayertreemodel.h"
|
||||
#include "qgslayertreemodellegendnode.h"
|
||||
#include "qgssettings.h"
|
||||
|
||||
|
||||
namespace QgsWmts
|
||||
{
|
||||
namespace
|
||||
{
|
||||
QMap< QgsUnitTypes::DistanceUnit, double> populateInchesPerUnit();
|
||||
QMap< QString, tileMatrixInfo> populateTileMatrixInfoMap();
|
||||
|
||||
QgsCoordinateReferenceSystem wgs84 = QgsCoordinateReferenceSystem::fromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
|
||||
|
||||
int DOTS_PER_INCH = 72;
|
||||
double METERS_PER_INCH = 0.02540005080010160020;
|
||||
QMap< QgsUnitTypes::DistanceUnit, double> INCHES_PER_UNIT = populateInchesPerUnit();
|
||||
int tileWidth = 256;
|
||||
int tileHeight = 256;
|
||||
|
||||
QMap< QString, tileMatrixInfo> tileMatrixInfoMap = populateTileMatrixInfoMap();
|
||||
}
|
||||
|
||||
QString implementationVersion()
|
||||
{
|
||||
return QStringLiteral( "1.0.0" );
|
||||
}
|
||||
|
||||
|
||||
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project )
|
||||
{
|
||||
QString href;
|
||||
if ( project )
|
||||
{
|
||||
href = QgsServerProjectUtils::wmtsServiceUrl( *project );
|
||||
}
|
||||
|
||||
// Build default url
|
||||
if ( href.isEmpty() )
|
||||
{
|
||||
QUrl url = request.url();
|
||||
|
||||
QgsWmtsParameters params;
|
||||
params.load( QUrlQuery( url ) );
|
||||
params.remove( QgsServerParameter::REQUEST );
|
||||
params.remove( QgsServerParameter::VERSION_SERVICE );
|
||||
params.remove( QgsServerParameter::SERVICE );
|
||||
|
||||
url.setQuery( params.urlQuery() );
|
||||
href = url.toString();
|
||||
}
|
||||
|
||||
return href;
|
||||
}
|
||||
|
||||
tileMatrixInfo getTileMatrixInfo( const QString &crsStr, const QgsProject *project )
|
||||
{
|
||||
if ( tileMatrixInfoMap.contains( crsStr ) )
|
||||
return tileMatrixInfoMap[crsStr];
|
||||
|
||||
tileMatrixInfo tmi;
|
||||
tmi.ref = crsStr;
|
||||
|
||||
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( crsStr );
|
||||
QgsCoordinateTransform crsTransform( wgs84, crs, project );
|
||||
try
|
||||
{
|
||||
tmi.extent = crsTransform.transformBoundingBox( crs.bounds() );
|
||||
}
|
||||
catch ( QgsCsException &cse )
|
||||
{
|
||||
Q_UNUSED( cse );
|
||||
}
|
||||
|
||||
tmi.unit = crs.mapUnits();
|
||||
|
||||
// calculate tile matrix scale denominator
|
||||
double scaleDenominator = 0.0;
|
||||
int colRes = ( tmi.extent.xMaximum() - tmi.extent.xMinimum() ) / tileWidth;
|
||||
int rowRes = ( tmi.extent.yMaximum() - tmi.extent.yMinimum() ) / tileHeight;
|
||||
if ( colRes > rowRes )
|
||||
scaleDenominator = std::ceil( colRes * INCHES_PER_UNIT[ tmi.unit ] * METERS_PER_INCH / 0.00028 );
|
||||
else
|
||||
scaleDenominator = std::ceil( rowRes * INCHES_PER_UNIT[ tmi.unit ] * METERS_PER_INCH / 0.00028 );
|
||||
|
||||
// Update extent to get a square one
|
||||
QgsRectangle extent = tmi.extent;
|
||||
double res = 0.00028 * scaleDenominator / METERS_PER_INCH / INCHES_PER_UNIT[ tmi.unit ];
|
||||
int col = std::ceil( ( extent.xMaximum() - extent.xMinimum() ) / ( tileWidth * res ) );
|
||||
int row = std::ceil( ( extent.yMaximum() - extent.yMinimum() ) / ( tileHeight * res ) );
|
||||
if ( col > 1 || row > 1 )
|
||||
{
|
||||
// Update scale
|
||||
if ( col > row )
|
||||
{
|
||||
res = col * res;
|
||||
scaleDenominator = col * scaleDenominator;
|
||||
}
|
||||
else
|
||||
{
|
||||
res = row * res;
|
||||
scaleDenominator = row * scaleDenominator;
|
||||
}
|
||||
// set col and row to 1 for the square
|
||||
col = 1;
|
||||
row = 1;
|
||||
}
|
||||
// Calculate extent
|
||||
double left = ( extent.xMinimum() + ( extent.xMaximum() - extent.xMinimum() ) / 2.0 ) - ( col / 2.0 ) * ( tileWidth * res );
|
||||
double bottom = ( extent.yMinimum() + ( extent.yMaximum() - extent.yMinimum() ) / 2.0 ) - ( row / 2.0 ) * ( tileHeight * res );
|
||||
double right = ( extent.xMinimum() + ( extent.xMaximum() - extent.xMinimum() ) / 2.0 ) + ( col / 2.0 ) * ( tileWidth * res );
|
||||
double top = ( extent.yMinimum() + ( extent.yMaximum() - extent.yMinimum() ) / 2.0 ) + ( row / 2.0 ) * ( tileHeight * res );
|
||||
tmi.extent = QgsRectangle( left, bottom, right, top );
|
||||
|
||||
tmi.scaleDenominator = scaleDenominator;
|
||||
|
||||
tileMatrixInfoMap[crsStr] = tmi;
|
||||
|
||||
return tmi;
|
||||
}
|
||||
|
||||
tileMatrixSetDef getTileMatrixSet( tileMatrixInfo tmi, double minScale )
|
||||
{
|
||||
QList< tileMatrixDef > tileMatrixList;
|
||||
double scaleDenominator = tmi.scaleDenominator;
|
||||
QgsRectangle extent = tmi.extent;
|
||||
QgsUnitTypes::DistanceUnit unit = tmi.unit;
|
||||
|
||||
while ( scaleDenominator >= minScale )
|
||||
{
|
||||
double scale = scaleDenominator;
|
||||
double res = 0.00028 * scale / METERS_PER_INCH / INCHES_PER_UNIT[ unit ];
|
||||
int col = std::ceil( ( extent.xMaximum() - extent.xMinimum() ) / ( tileWidth * res ) );
|
||||
int row = std::ceil( ( extent.yMaximum() - extent.yMinimum() ) / ( tileHeight * res ) );
|
||||
double left = ( extent.xMinimum() + ( extent.xMaximum() - extent.xMinimum() ) / 2.0 ) - ( col / 2.0 ) * ( tileWidth * res );
|
||||
double top = ( extent.yMinimum() + ( extent.yMaximum() - extent.yMinimum() ) / 2.0 ) + ( row / 2.0 ) * ( tileHeight * res );
|
||||
|
||||
tileMatrixDef tm;
|
||||
tm.resolution = res;
|
||||
tm.scaleDenominator = scale;
|
||||
tm.col = col;
|
||||
tm.row = row;
|
||||
tm.left = std::max( left, extent.xMinimum() );
|
||||
tm.top = std::min( top, extent.yMaximum() );
|
||||
tileMatrixList.append( tm );
|
||||
|
||||
scaleDenominator = scale / 2;
|
||||
}
|
||||
|
||||
tileMatrixSetDef tms;
|
||||
tms.ref = tmi.ref;
|
||||
tms.extent = extent;
|
||||
tms.unit = unit;
|
||||
tms.tileMatrixList = tileMatrixList;
|
||||
|
||||
return tms;
|
||||
}
|
||||
|
||||
double getProjectMinScale( const QgsProject *project )
|
||||
{
|
||||
double scale = -1.0;
|
||||
|
||||
// default scales
|
||||
QgsSettings settings;
|
||||
QStringList scaleList = settings.value( QStringLiteral( "Map/scales" ), PROJECT_SCALES ).toString().split( ',' );
|
||||
//load project scales
|
||||
bool projectScales = project->readBoolEntry( QStringLiteral( "Scales" ), QStringLiteral( "/useProjectScales" ) );
|
||||
if ( projectScales )
|
||||
{
|
||||
scaleList = project->readListEntry( QStringLiteral( "Scales" ), QStringLiteral( "/ScalesList" ) );
|
||||
}
|
||||
// get min and max scales
|
||||
if ( !scaleList.isEmpty() )
|
||||
{
|
||||
for ( const QString &scaleText : scaleList )
|
||||
{
|
||||
double scaleValue = scaleText.toDouble();
|
||||
if ( scale == -1.0 )
|
||||
{
|
||||
scale = scaleValue;
|
||||
}
|
||||
else if ( scaleValue < scale )
|
||||
{
|
||||
scale = scaleValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( scale < 500.0 )
|
||||
{
|
||||
return 500.0;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
QList< tileMatrixSetDef > getTileMatrixSetList( const QgsProject *project )
|
||||
{
|
||||
QList< tileMatrixSetDef > tmsList;
|
||||
|
||||
double minScale = project->readNumEntry( QStringLiteral( "WMTSMinScale" ), QStringLiteral( "/" ), -1.0 );
|
||||
if ( minScale == -1.0 )
|
||||
{
|
||||
minScale = getProjectMinScale( project );
|
||||
}
|
||||
|
||||
QStringList crsList = QgsServerProjectUtils::wmsOutputCrsList( *project );
|
||||
for ( const QString &crsStr : crsList )
|
||||
{
|
||||
tileMatrixInfo tmi = getTileMatrixInfo( crsStr, project );
|
||||
if ( tmi.scaleDenominator > 0.0 )
|
||||
{
|
||||
tmsList.append( getTileMatrixSet( tmi, minScale ) );
|
||||
}
|
||||
}
|
||||
|
||||
return tmsList;
|
||||
}
|
||||
|
||||
QList< layerDef > getWmtsLayerList( QgsServerInterface *serverIface, const QgsProject *project )
|
||||
{
|
||||
QList< layerDef > wmtsLayers;
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
#endif
|
||||
QgsCoordinateReferenceSystem wgs84 = QgsCoordinateReferenceSystem::fromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
|
||||
|
||||
QStringList nonIdentifiableLayers = project->nonIdentifiableLayers();
|
||||
|
||||
// WMTS Project configuration
|
||||
bool wmtsProject = project->readBoolEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Project" ) );
|
||||
|
||||
// Root Layer name
|
||||
QString rootLayerName = QgsServerProjectUtils::wmsRootName( *project );
|
||||
if ( rootLayerName.isEmpty() && !project->title().isEmpty() )
|
||||
{
|
||||
rootLayerName = project->title();
|
||||
}
|
||||
|
||||
if ( wmtsProject && !rootLayerName.isEmpty() )
|
||||
{
|
||||
layerDef pLayer;
|
||||
pLayer.id = rootLayerName;
|
||||
|
||||
if ( !project->title().isEmpty() )
|
||||
{
|
||||
pLayer.title = project->title();
|
||||
pLayer.abstract = project->title();
|
||||
}
|
||||
|
||||
//transform the project native CRS into WGS84
|
||||
QgsRectangle projRect = QgsServerProjectUtils::wmsExtent( *project );
|
||||
QgsCoordinateReferenceSystem projCrs = project->crs();
|
||||
QgsCoordinateTransform exGeoTransform( projCrs, wgs84, project );
|
||||
try
|
||||
{
|
||||
pLayer.wgs84BoundingRect = exGeoTransform.transformBoundingBox( projRect );
|
||||
}
|
||||
catch ( const QgsCsException & )
|
||||
{
|
||||
pLayer.wgs84BoundingRect = QgsRectangle( -180, -90, 180, 90 );
|
||||
}
|
||||
|
||||
// Formats
|
||||
bool wmtsPngProject = project->readBoolEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Project" ) );
|
||||
if ( wmtsPngProject )
|
||||
pLayer.formats << QStringLiteral( "image/png" );
|
||||
bool wmtsJpegProject = project->readBoolEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Project" ) );
|
||||
if ( wmtsJpegProject )
|
||||
pLayer.formats << QStringLiteral( "image/jpeg" );
|
||||
|
||||
// Project is not queryable in WMS
|
||||
//pLayer.queryable = ( nonIdentifiableLayers.count() != project->count() );
|
||||
pLayer.queryable = false;
|
||||
|
||||
wmtsLayers.append( pLayer );
|
||||
}
|
||||
|
||||
QStringList wmtsGroupNameList = project->readListEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Group" ) );
|
||||
if ( !wmtsGroupNameList.isEmpty() )
|
||||
{
|
||||
QgsLayerTreeGroup *treeRoot = project->layerTreeRoot();
|
||||
|
||||
QStringList wmtsPngGroupNameList = project->readListEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Group" ) );
|
||||
QStringList wmtsJpegGroupNameList = project->readListEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Group" ) );
|
||||
|
||||
for ( const QString &gName : wmtsGroupNameList )
|
||||
{
|
||||
QgsLayerTreeGroup *treeGroup = treeRoot->findGroup( gName );
|
||||
if ( !treeGroup )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
layerDef pLayer;
|
||||
pLayer.id = treeGroup->customProperty( QStringLiteral( "wmsShortName" ) ).toString();
|
||||
if ( pLayer.id.isEmpty() )
|
||||
pLayer.id = gName;
|
||||
|
||||
pLayer.title = treeGroup->customProperty( QStringLiteral( "wmsTitle" ) ).toString();
|
||||
if ( pLayer.title.isEmpty() )
|
||||
pLayer.title = gName;
|
||||
|
||||
pLayer.abstract = treeGroup->customProperty( QStringLiteral( "wmsAbstract" ) ).toString();
|
||||
|
||||
QgsRectangle wgs84BoundingRect;
|
||||
bool queryable = false;
|
||||
double maxScale = 0.0;
|
||||
double minScale = 0.0;
|
||||
for ( QgsLayerTreeLayer *layer : treeGroup->findLayers() )
|
||||
{
|
||||
QgsMapLayer *l = layer->layer();
|
||||
if ( !l )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//transform the layer native CRS into WGS84
|
||||
QgsCoordinateReferenceSystem layerCrs = l->crs();
|
||||
QgsCoordinateTransform exGeoTransform( layerCrs, wgs84, project );
|
||||
try
|
||||
{
|
||||
wgs84BoundingRect.combineExtentWith( exGeoTransform.transformBoundingBox( l->extent() ) );
|
||||
}
|
||||
catch ( const QgsCsException & )
|
||||
{
|
||||
wgs84BoundingRect.combineExtentWith( QgsRectangle( -180, -90, 180, 90 ) );
|
||||
}
|
||||
if ( !queryable && !nonIdentifiableLayers.contains( l->id() ) )
|
||||
{
|
||||
queryable = true;
|
||||
}
|
||||
|
||||
double lMaxScale = l->maximumScale();
|
||||
if ( lMaxScale > 0.0 && lMaxScale > maxScale )
|
||||
{
|
||||
maxScale = lMaxScale;
|
||||
}
|
||||
double lMinScale = l->minimumScale();
|
||||
if ( lMinScale > 0.0 && ( minScale == 0.0 || lMinScale < minScale ) )
|
||||
{
|
||||
minScale = lMinScale;
|
||||
}
|
||||
}
|
||||
pLayer.wgs84BoundingRect = wgs84BoundingRect;
|
||||
pLayer.queryable = queryable;
|
||||
pLayer.maxScale = maxScale;
|
||||
pLayer.minScale = minScale;
|
||||
|
||||
// Formats
|
||||
if ( wmtsPngGroupNameList.contains( gName ) )
|
||||
pLayer.formats << QStringLiteral( "image/png" );
|
||||
if ( wmtsJpegGroupNameList.contains( gName ) )
|
||||
pLayer.formats << QStringLiteral( "image/jpeg" );
|
||||
|
||||
wmtsLayers.append( pLayer );
|
||||
}
|
||||
}
|
||||
|
||||
QStringList wmtsLayerIdList = project->readListEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Layer" ) );
|
||||
QStringList wmtsPngLayerIdList = project->readListEntry( QStringLiteral( "WMTSPngLayers" ), QStringLiteral( "Layer" ) );
|
||||
QStringList wmtsJpegLayerIdList = project->readListEntry( QStringLiteral( "WMTSJpegLayers" ), QStringLiteral( "Layer" ) );
|
||||
|
||||
for ( const QString &lId : wmtsLayerIdList )
|
||||
{
|
||||
QgsMapLayer *l = project->mapLayer( lId );
|
||||
if ( !l )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
if ( !accessControl->layerReadPermission( l ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
layerDef pLayer;
|
||||
pLayer.id = l->name();
|
||||
if ( !l->shortName().isEmpty() )
|
||||
pLayer.id = l->shortName();
|
||||
pLayer.id = pLayer.id.replace( ' ', '_' );
|
||||
|
||||
pLayer.title = l->title();
|
||||
pLayer.abstract = l->abstract();
|
||||
|
||||
//transform the layer native CRS into WGS84
|
||||
QgsCoordinateReferenceSystem layerCrs = l->crs();
|
||||
QgsCoordinateTransform exGeoTransform( layerCrs, wgs84, project );
|
||||
try
|
||||
{
|
||||
pLayer.wgs84BoundingRect = exGeoTransform.transformBoundingBox( l->extent() );
|
||||
}
|
||||
catch ( const QgsCsException & )
|
||||
{
|
||||
pLayer.wgs84BoundingRect = QgsRectangle( -180, -90, 180, 90 );
|
||||
}
|
||||
|
||||
// Formats
|
||||
if ( wmtsPngLayerIdList.contains( lId ) )
|
||||
pLayer.formats << QStringLiteral( "image/png" );
|
||||
if ( wmtsJpegLayerIdList.contains( lId ) )
|
||||
pLayer.formats << QStringLiteral( "image/jpeg" );
|
||||
|
||||
pLayer.queryable = ( !nonIdentifiableLayers.contains( l->id() ) );
|
||||
|
||||
pLayer.maxScale = l->maximumScale();
|
||||
pLayer.minScale = l->minimumScale();
|
||||
|
||||
wmtsLayers.append( pLayer );
|
||||
}
|
||||
return wmtsLayers;
|
||||
}
|
||||
|
||||
tileMatrixSetLinkDef getLayerTileMatrixSetLink( const layerDef layer, const tileMatrixSetDef tms, const QgsProject *project )
|
||||
{
|
||||
tileMatrixSetLinkDef tmsl;
|
||||
|
||||
QMap< int, tileMatrixLimitDef > tileMatrixLimits;
|
||||
|
||||
QgsRectangle rect( layer.wgs84BoundingRect );
|
||||
if ( tms.ref != QLatin1String( "EPSG:4326" ) )
|
||||
{
|
||||
QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromOgcWmsCrs( tms.ref );
|
||||
QgsCoordinateReferenceSystem wgs84 = QgsCoordinateReferenceSystem::fromOgcWmsCrs( GEO_EPSG_CRS_AUTHID );
|
||||
QgsCoordinateTransform exGeoTransform( wgs84, crs, project );
|
||||
try
|
||||
{
|
||||
rect = exGeoTransform.transformBoundingBox( layer.wgs84BoundingRect );
|
||||
}
|
||||
catch ( const QgsCsException & )
|
||||
{
|
||||
return tmsl;
|
||||
}
|
||||
}
|
||||
tmsl.ref = tms.ref;
|
||||
|
||||
rect = rect.intersect( tms.extent );
|
||||
|
||||
int tmIdx = -1;
|
||||
for ( const tileMatrixDef &tm : tms.tileMatrixList )
|
||||
{
|
||||
++tmIdx;
|
||||
|
||||
if ( layer.maxScale > 0.0 && tm.scaleDenominator > layer.maxScale )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ( layer.minScale > 0.0 && tm.scaleDenominator < layer.minScale )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double res = tm.resolution;
|
||||
|
||||
tileMatrixLimitDef tml;
|
||||
tml.minCol = std::floor( ( rect.xMinimum() - tm.left ) / ( tileWidth * res ) );
|
||||
tml.maxCol = std::ceil( ( rect.xMaximum() - tm.left ) / ( tileWidth * res ) ) - 1;
|
||||
tml.minRow = std::floor( ( tm.top - rect.yMaximum() ) / ( tileHeight * res ) );
|
||||
tml.maxRow = std::ceil( ( tm.top - rect.yMinimum() ) / ( tileHeight * res ) ) - 1;
|
||||
|
||||
tileMatrixLimits[tmIdx] = tml;
|
||||
}
|
||||
|
||||
tmsl.tileMatrixLimits = tileMatrixLimits;
|
||||
return tmsl;
|
||||
}
|
||||
|
||||
QUrlQuery translateWmtsParamToWmsQueryItem( const QString &request, const QgsWmtsParameters ¶ms,
|
||||
const QgsProject *project, QgsServerInterface *serverIface )
|
||||
{
|
||||
//defining Layer
|
||||
QString layer = params.layer();
|
||||
//read Layer
|
||||
if ( layer.isEmpty() )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "Layer is mandatory" ) );
|
||||
}
|
||||
//check layer value
|
||||
bool wmtsProject = project->readBoolEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Project" ) );
|
||||
QStringList wmtsGroupNameList = project->readListEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Group" ) );
|
||||
QStringList wmtsLayerIdList = project->readListEntry( QStringLiteral( "WMTSLayers" ), QStringLiteral( "Layer" ) );
|
||||
QStringList wmtsLayerIds;
|
||||
if ( wmtsProject )
|
||||
{
|
||||
// Root Layer name
|
||||
QString rootLayerId = QgsServerProjectUtils::wmsRootName( *project );
|
||||
if ( rootLayerId.isEmpty() )
|
||||
{
|
||||
rootLayerId = project->title();
|
||||
}
|
||||
if ( !rootLayerId.isEmpty() )
|
||||
{
|
||||
wmtsLayerIds << rootLayerId;
|
||||
}
|
||||
}
|
||||
if ( !wmtsGroupNameList.isEmpty() )
|
||||
{
|
||||
QgsLayerTreeGroup *treeRoot = project->layerTreeRoot();
|
||||
for ( const QString &gName : wmtsGroupNameList )
|
||||
{
|
||||
QgsLayerTreeGroup *treeGroup = treeRoot->findGroup( gName );
|
||||
if ( !treeGroup )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QString groupLayerId = treeGroup->customProperty( QStringLiteral( "wmsShortName" ) ).toString();
|
||||
if ( groupLayerId.isEmpty() )
|
||||
{
|
||||
groupLayerId = gName;
|
||||
}
|
||||
wmtsLayerIds << groupLayerId;
|
||||
}
|
||||
}
|
||||
if ( !wmtsLayerIdList.isEmpty() )
|
||||
{
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
QgsAccessControl *accessControl = serverIface->accessControls();
|
||||
#endif
|
||||
for ( const QString &lId : wmtsLayerIdList )
|
||||
{
|
||||
QgsMapLayer *l = project->mapLayer( lId );
|
||||
if ( !l )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#ifdef HAVE_SERVER_PYTHON_PLUGINS
|
||||
if ( !accessControl->layerReadPermission( l ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
QString layerLayerId = l->shortName();
|
||||
if ( layerLayerId.isEmpty() )
|
||||
{
|
||||
layerLayerId = l->name();
|
||||
}
|
||||
wmtsLayerIds << layerLayerId;
|
||||
}
|
||||
}
|
||||
if ( !wmtsLayerIds.contains( layer ) )
|
||||
{
|
||||
QString msg = QObject::tr( "Layer '%1' not found" ).arg( layer );
|
||||
throw QgsBadRequestException( QStringLiteral( "LayerNotDefined" ), msg );
|
||||
}
|
||||
|
||||
//defining Format
|
||||
QString format = params.formatAsString();
|
||||
//read Format
|
||||
if ( format.isEmpty() )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "Format is mandatory" ) );
|
||||
}
|
||||
|
||||
//defining TileMatrixSet ref
|
||||
QString tms_ref = params.tileMatrixSet();
|
||||
//read TileMatrixSet
|
||||
if ( tms_ref.isEmpty() )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "TileMatrixSet is mandatory" ) );
|
||||
}
|
||||
|
||||
// verifying TileMatricSet value
|
||||
QStringList crsList = QgsServerProjectUtils::wmsOutputCrsList( *project );
|
||||
if ( !crsList.contains( tms_ref ) )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "TileMatrixSet is unknown" ) );
|
||||
}
|
||||
|
||||
tileMatrixInfo tmi = getTileMatrixInfo( tms_ref, project );
|
||||
if ( tmi.scaleDenominator == 0.0 )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "TileMatrixSet is unknown" ) );
|
||||
}
|
||||
tileMatrixSetDef tms = getTileMatrixSet( tmi, getProjectMinScale( project ) );
|
||||
|
||||
//difining TileMatrix idx
|
||||
int tm_idx = params.tileMatrixAsInt();
|
||||
//read TileMatrix
|
||||
if ( tm_idx < 0 || tms.tileMatrixList.count() < tm_idx )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "TileMatrix is unknown" ) );
|
||||
}
|
||||
tileMatrixDef tm = tms.tileMatrixList.at( tm_idx );
|
||||
|
||||
//defining TileRow
|
||||
int tr = params.tileRowAsInt();
|
||||
//read TileRow
|
||||
if ( tr < 0 || tm.row <= tr )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "TileRow is unknown" ) );
|
||||
}
|
||||
|
||||
//defining TileCol
|
||||
int tc = params.tileColAsInt();
|
||||
//read TileCol
|
||||
if ( tc < 0 || tm.col <= tc )
|
||||
{
|
||||
throw QgsRequestNotWellFormedException( QStringLiteral( "TileCol is unknown" ) );
|
||||
}
|
||||
|
||||
int tileWidth = 256;
|
||||
int tileHeight = 256;
|
||||
double res = tm.resolution;
|
||||
double minx = tm.left + tc * ( tileWidth * res );
|
||||
double miny = tm.top - ( tr + 1 ) * ( tileHeight * res );
|
||||
double maxx = tm.left + ( tc + 1 ) * ( tileWidth * res );
|
||||
double maxy = tm.top - tr * ( tileHeight * res );
|
||||
QString bbox;
|
||||
if ( tms.ref == "EPSG:4326" )
|
||||
{
|
||||
bbox = qgsDoubleToString( miny, 6 ) + ',' +
|
||||
qgsDoubleToString( minx, 6 ) + ',' +
|
||||
qgsDoubleToString( maxy, 6 ) + ',' +
|
||||
qgsDoubleToString( maxx, 6 );
|
||||
}
|
||||
else
|
||||
{
|
||||
bbox = qgsDoubleToString( minx, 6 ) + ',' +
|
||||
qgsDoubleToString( miny, 6 ) + ',' +
|
||||
qgsDoubleToString( maxx, 6 ) + ',' +
|
||||
qgsDoubleToString( maxy, 6 );
|
||||
}
|
||||
|
||||
QUrlQuery query;
|
||||
if ( !params.value( QStringLiteral( "MAP" ) ).isEmpty() )
|
||||
{
|
||||
query.addQueryItem( QgsServerParameter::name( QgsServerParameter::MAP ), params.value( QStringLiteral( "MAP" ) ) );
|
||||
}
|
||||
query.addQueryItem( QgsServerParameter::name( QgsServerParameter::SERVICE ), QStringLiteral( "WMS" ) );
|
||||
query.addQueryItem( QgsServerParameter::name( QgsServerParameter::VERSION_SERVICE ), QStringLiteral( "1.3.0" ) );
|
||||
query.addQueryItem( QgsServerParameter::name( QgsServerParameter::REQUEST ), request );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::LAYERS ), layer );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::STYLES ), QString() );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::CRS ), tms.ref );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::BBOX ), bbox );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::WIDTH ), QStringLiteral( "256" ) );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::HEIGHT ), QStringLiteral( "256" ) );
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::FORMAT ), format );
|
||||
if ( params.format() == QgsWmtsParameters::Format::PNG )
|
||||
{
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::TRANSPARENT ), QStringLiteral( "true" ) );
|
||||
}
|
||||
query.addQueryItem( QgsWmsParameterForWmts::name( QgsWmsParameterForWmts::DPI ), QStringLiteral( "96" ) );
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
QMap< QgsUnitTypes::DistanceUnit, double> populateInchesPerUnit()
|
||||
{
|
||||
QMap< QgsUnitTypes::DistanceUnit, double> m;
|
||||
m[ QgsUnitTypes::DistanceMeters ] = 39.37;
|
||||
m[ QgsUnitTypes::DistanceFeet ] = 12.0;
|
||||
m[ QgsUnitTypes::DistanceYards ] = 36.0;
|
||||
m[ QgsUnitTypes::DistanceMiles ] = 63360.0;
|
||||
m[ QgsUnitTypes::DistanceDegrees ] = 4374754.0;
|
||||
m[ QgsUnitTypes::DistanceKilometers ] = m[ QgsUnitTypes::DistanceMeters ] * 1000.0;
|
||||
m[ QgsUnitTypes::DistanceNauticalMiles ] = m[ QgsUnitTypes::DistanceMeters ] * 1852.0;
|
||||
m[ QgsUnitTypes::DistanceCentimeters ] = m[ QgsUnitTypes::DistanceMeters ] / 100.0;
|
||||
m[ QgsUnitTypes::DistanceMillimeters ] = m[ QgsUnitTypes::DistanceMeters ] / 1000.0;
|
||||
return m;
|
||||
}
|
||||
|
||||
QMap< QString, tileMatrixInfo> populateTileMatrixInfoMap()
|
||||
{
|
||||
QMap< QString, tileMatrixInfo> m;
|
||||
|
||||
// Tile matrix information
|
||||
// to build tile matrix set like Google Mercator or TMS
|
||||
tileMatrixInfo tmi3857;
|
||||
tmi3857.ref = QStringLiteral( "EPSG:3857" );
|
||||
tmi3857.extent = QgsRectangle( -20037508.3427892480, -20037508.3427892480, 20037508.3427892480, 20037508.3427892480 );
|
||||
tmi3857.scaleDenominator = 559082264.0287179;
|
||||
tmi3857.unit = QgsUnitTypes::DistanceMeters;
|
||||
m[tmi3857.ref] = tmi3857;
|
||||
|
||||
|
||||
tileMatrixInfo tmi4326;
|
||||
tmi4326.ref = QStringLiteral( "EPSG:4326" );
|
||||
tmi4326.extent = QgsRectangle( -180, -90, 180, 90 );
|
||||
tmi4326.scaleDenominator = 279541132.0143588675418869;
|
||||
tmi4326.unit = QgsUnitTypes::DistanceDegrees;
|
||||
m[tmi4326.ref] = tmi4326;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace QgsWmts
|
||||
|
||||
|
145
src/server/services/wmts/qgswmtsutils.h
Normal file
@ -0,0 +1,145 @@
|
||||
/***************************************************************************
|
||||
qgswmtsutils.h
|
||||
|
||||
Define WMTS service utility functions
|
||||
------------------------------------
|
||||
begin : July 23 , 2017
|
||||
copyright : (C) 2018 by René-Luc D'Hont
|
||||
email : rldhont at 3liz 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 QGSWMTSUTILS_H
|
||||
#define QGSWMTSUTILS_H
|
||||
|
||||
#include "qgsmodule.h"
|
||||
#include "qgswmtsparameters.h"
|
||||
#include "qgswmtsserviceexception.h"
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
/**
|
||||
* \ingroup server
|
||||
* WMTS implementation
|
||||
* \since QGIS 3.4
|
||||
*/
|
||||
|
||||
//! WMTS implementation
|
||||
namespace QgsWmts
|
||||
{
|
||||
|
||||
struct tileMatrixInfo
|
||||
{
|
||||
QString ref;
|
||||
|
||||
QgsRectangle extent;
|
||||
|
||||
double scaleDenominator = 0.0;
|
||||
|
||||
QgsUnitTypes::DistanceUnit unit;
|
||||
};
|
||||
|
||||
struct tileMatrixDef
|
||||
{
|
||||
double resolution = 0.0;
|
||||
|
||||
double scaleDenominator = 0.0;
|
||||
|
||||
int col = 0;
|
||||
|
||||
int row = 0;
|
||||
|
||||
double left = 0.0;
|
||||
|
||||
double top = 0.0;
|
||||
};
|
||||
|
||||
struct tileMatrixSetDef
|
||||
{
|
||||
QString ref;
|
||||
|
||||
QgsRectangle extent;
|
||||
|
||||
QgsUnitTypes::DistanceUnit unit;
|
||||
|
||||
QList< tileMatrixDef > tileMatrixList;
|
||||
};
|
||||
|
||||
struct tileMatrixLimitDef
|
||||
{
|
||||
int minCol;
|
||||
|
||||
int maxCol;
|
||||
|
||||
int minRow;
|
||||
|
||||
int maxRow;
|
||||
};
|
||||
|
||||
struct tileMatrixSetLinkDef
|
||||
{
|
||||
QString ref;
|
||||
|
||||
QMap< int, tileMatrixLimitDef > tileMatrixLimits;
|
||||
};
|
||||
|
||||
struct layerDef
|
||||
{
|
||||
QString id;
|
||||
|
||||
QString title;
|
||||
|
||||
QString abstract;
|
||||
|
||||
QgsRectangle wgs84BoundingRect;
|
||||
|
||||
QStringList formats;
|
||||
|
||||
bool queryable = false;
|
||||
|
||||
double maxScale = 0.0;
|
||||
|
||||
double minScale = 0.0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the highest version supported by this implementation
|
||||
*/
|
||||
QString implementationVersion();
|
||||
|
||||
/**
|
||||
* Service URL string
|
||||
*/
|
||||
QString serviceUrl( const QgsServerRequest &request, const QgsProject *project );
|
||||
|
||||
// Define namespaces used in WMTS documents
|
||||
const QString WMTS_NAMESPACE = QStringLiteral( "http://www.opengis.net/wmts/1.0" );
|
||||
const QString GML_NAMESPACE = QStringLiteral( "http://www.opengis.net/gml" );
|
||||
const QString OWS_NAMESPACE = QStringLiteral( "http://www.opengis.net/ows/1.1" );
|
||||
|
||||
tileMatrixInfo getTileMatrixInfo( const QString &crsStr, const QgsProject *project );
|
||||
tileMatrixSetDef getTileMatrixSet( tileMatrixInfo tmi, double minScale );
|
||||
double getProjectMinScale( const QgsProject *project );
|
||||
QList< tileMatrixSetDef > getTileMatrixSetList( const QgsProject *project );
|
||||
|
||||
QList< layerDef > getWmtsLayerList( QgsServerInterface *serverIface, const QgsProject *project );
|
||||
tileMatrixSetLinkDef getLayerTileMatrixSetLink( const layerDef layer, const tileMatrixSetDef tms, const QgsProject *project );
|
||||
|
||||
/**
|
||||
* Translate WMTS parameters to WMS query item
|
||||
*/
|
||||
QUrlQuery translateWmtsParamToWmsQueryItem( const QString &request, const QgsWmtsParameters ¶ms,
|
||||
const QgsProject *project, QgsServerInterface *serverIface );
|
||||
|
||||
} // namespace QgsWmts
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -2467,6 +2467,89 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsCollapsibleGroupBox" name="grpWmtsCapabilities">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>3</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>WMTS capabilities</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_20">
|
||||
<item row="0" column="0">
|
||||
<widget class="QTreeWidget" name="twWmtsLayers">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Layer</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Published</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>PNG</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>JPEG</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_16">
|
||||
<item>
|
||||
<widget class="QLabel" name="mWMTSMinScaleLabel">
|
||||
<property name="text">
|
||||
<string>Minimum scale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="mWMTSMinScaleLineEdit">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>5000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_15">
|
||||
<item>
|
||||
<widget class="QLabel" name="mWMTSUrlLabel">
|
||||
<property name="text">
|
||||
<string>Advertised URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="mWMTSUrlLineEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsCollapsibleGroupBox" name="grpWFSCapabilities">
|
||||
<property name="sizePolicy">
|
||||
@ -2916,6 +2999,9 @@
|
||||
<tabstop>mMaxWidthLineEdit</tabstop>
|
||||
<tabstop>mMaxHeightLineEdit</tabstop>
|
||||
<tabstop>mWMSImageQualitySpinBox</tabstop>
|
||||
<tabstop>twWmtsLayers</tabstop>
|
||||
<tabstop>mWMTSMinScaleLineEdit</tabstop>
|
||||
<tabstop>mWMTSUrlLineEdit</tabstop>
|
||||
<tabstop>twWFSLayers</tabstop>
|
||||
<tabstop>pbnWFSLayersSelectAll</tabstop>
|
||||
<tabstop>pbnWFSLayersDeselectAll</tabstop>
|
||||
|
@ -269,6 +269,8 @@ IF (WITH_SERVER)
|
||||
ADD_PYTHON_TEST(PyQgsServerAccessControlWFS test_qgsserver_accesscontrol_wfs.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerAccessControlWCS test_qgsserver_accesscontrol_wcs.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerAccessControlWFSTransactional test_qgsserver_accesscontrol_wfs_transactional.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerCacheManager test_qgsserver_cachemanager.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWMTS test_qgsserver_wmts.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWFS test_qgsserver_wfs.py)
|
||||
ADD_PYTHON_TEST(PyQgsServerWFST test_qgsserver_wfst.py)
|
||||
ADD_PYTHON_TEST(PyQgsOfflineEditingWFS test_offline_editing_wfs.py)
|
||||
|
420
tests/src/python/test_qgsserver_cachemanager.py
Normal file
@ -0,0 +1,420 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsServer.
|
||||
|
||||
.. note:: 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.
|
||||
"""
|
||||
__author__ = 'René-Luc DHONT'
|
||||
__date__ = '19/07/2018'
|
||||
__copyright__ = 'Copyright 2015, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
print('CTEST_FULL_OUTPUT')
|
||||
|
||||
import qgis # NOQA
|
||||
|
||||
import os
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
import tempfile
|
||||
import hashlib
|
||||
|
||||
from qgis.testing import unittest
|
||||
from utilities import unitTestDataPath
|
||||
from qgis.server import QgsServer, QgsServerCacheFilter, QgsServerRequest, QgsBufferServerRequest, QgsBufferServerResponse
|
||||
from qgis.core import QgsApplication, QgsFontUtils, QgsProject
|
||||
from qgis.PyQt.QtCore import QIODevice, QFile, QByteArray, QBuffer
|
||||
from qgis.PyQt.QtGui import QImage
|
||||
from qgis.PyQt.QtXml import QDomDocument
|
||||
|
||||
|
||||
class PyServerCache(QgsServerCacheFilter):
|
||||
|
||||
""" Used to have restriction access """
|
||||
|
||||
# Be able to deactivate the access control to have a reference point
|
||||
_active = False
|
||||
|
||||
def __init__(self, server_iface):
|
||||
super(QgsServerCacheFilter, self).__init__(server_iface)
|
||||
|
||||
self._cache_dir = os.path.join(tempfile.gettempdir(), "qgs_server_cache")
|
||||
if not os.path.exists(self._cache_dir):
|
||||
os.mkdir(self._cache_dir)
|
||||
|
||||
self._tile_cache_dir = os.path.join(self._cache_dir, 'tiles')
|
||||
if not os.path.exists(self._tile_cache_dir):
|
||||
os.mkdir(self._tile_cache_dir)
|
||||
|
||||
def getCachedDocument(self, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
|
||||
if not os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")):
|
||||
return QByteArray()
|
||||
|
||||
doc = QDomDocument(m.hexdigest() + ".xml")
|
||||
with open(os.path.join(self._cache_dir, m.hexdigest() + ".xml"), "r") as f:
|
||||
statusOK, errorStr, errorLine, errorColumn = doc.setContent(f.read(), True)
|
||||
if not statusOK:
|
||||
print("Could not read or find the contents document. Error at line %d, column %d:\n%s" % (errorLine, errorColumn, errorStr))
|
||||
return QByteArray()
|
||||
|
||||
return doc.toByteArray()
|
||||
|
||||
def setCachedDocument(self, doc, project, request, key):
|
||||
if not doc:
|
||||
print("Could not cache None document")
|
||||
return False
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
with open(os.path.join(self._cache_dir, m.hexdigest() + ".xml"), "w") as f:
|
||||
f.write(doc.toString())
|
||||
return os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml"))
|
||||
|
||||
def deleteCachedDocument(self, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
if os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml")):
|
||||
os.remove(os.path.join(self._cache_dir, m.hexdigest() + ".xml"))
|
||||
return not os.path.exists(os.path.join(self._cache_dir, m.hexdigest() + ".xml"))
|
||||
|
||||
def deleteCachedDocuments(self, project):
|
||||
filelist = [f for f in os.listdir(self._cache_dir) if f.endswith(".xml")]
|
||||
for f in filelist:
|
||||
os.remove(os.path.join(self._cache_dir, f))
|
||||
filelist = [f for f in os.listdir(self._cache_dir) if f.endswith(".xml")]
|
||||
return len(filelist) == 0
|
||||
|
||||
def getCachedImage(self, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
|
||||
if not os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")):
|
||||
return QByteArray()
|
||||
|
||||
img = QImage(m.hexdigest() + ".png")
|
||||
with open(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "rb") as f:
|
||||
statusOK = img.loadFromData(f.read())
|
||||
if not statusOK:
|
||||
print("Could not read or find the contents document. Error at line %d, column %d:\n%s" % (errorLine, errorColumn, errorStr))
|
||||
return QByteArray()
|
||||
|
||||
ba = QByteArray()
|
||||
buff = QBuffer(ba)
|
||||
buff.open(QIODevice.WriteOnly)
|
||||
img.save(buff, 'PNG')
|
||||
return ba
|
||||
|
||||
def setCachedImage(self, img, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
with open(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"), "wb") as f:
|
||||
f.write(img)
|
||||
return os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"))
|
||||
|
||||
def deleteCachedImage(self, project, request, key):
|
||||
m = hashlib.md5()
|
||||
paramMap = request.parameters()
|
||||
urlParam = "&".join(["%s=%s" % (k, paramMap[k]) for k in paramMap.keys()])
|
||||
m.update(urlParam.encode('utf8'))
|
||||
if os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png")):
|
||||
os.remove(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"))
|
||||
return not os.path.exists(os.path.join(self._tile_cache_dir, m.hexdigest() + ".png"))
|
||||
|
||||
def deleteCachedImages(self, project):
|
||||
filelist = [f for f in os.listdir(self._tile_cache_dir) if f.endswith(".png")]
|
||||
for f in filelist:
|
||||
os.remove(os.path.join(self._tile_cache_dir, f))
|
||||
filelist = [f for f in os.listdir(self._tile_cache_dir) if f.endswith(".png")]
|
||||
return len(filelist) == 0
|
||||
|
||||
|
||||
class TestQgsServerCacheManager(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def _handle_request(cls, qs, requestMethod=QgsServerRequest.GetMethod, data=None):
|
||||
if data is not None:
|
||||
data = data.encode('utf-8')
|
||||
request = QgsBufferServerRequest(qs, requestMethod, {}, data)
|
||||
response = QgsBufferServerResponse()
|
||||
cls._server.handleRequest(request, response)
|
||||
headers = []
|
||||
rh = response.headers()
|
||||
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())
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Run before all tests"""
|
||||
cls._app = QgsApplication([], False)
|
||||
cls._server = QgsServer()
|
||||
cls._handle_request("")
|
||||
cls._server_iface = cls._server.serverInterface()
|
||||
cls._servercache = PyServerCache(cls._server_iface)
|
||||
cls._server_iface.registerServerCache(cls._servercache, 100)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Run after all tests"""
|
||||
#cls._servercache.deleteCachedDocuments(None)
|
||||
del cls._server
|
||||
cls._app.exitQgis
|
||||
|
||||
def _result(self, data):
|
||||
headers = {}
|
||||
for line in data[0].decode('UTF-8').split("\n"):
|
||||
if line != "":
|
||||
header = line.split(":")
|
||||
self.assertEqual(len(header), 2, line)
|
||||
headers[str(header[0])] = str(header[1]).strip()
|
||||
|
||||
return data[1], headers
|
||||
|
||||
def _execute_request(self, qs, requestMethod=QgsServerRequest.GetMethod, data=None):
|
||||
request = QgsBufferServerRequest(qs, requestMethod, {}, data)
|
||||
response = QgsBufferServerResponse()
|
||||
self._server.handleRequest(request, response)
|
||||
headers = []
|
||||
rh = response.headers()
|
||||
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())
|
||||
|
||||
def setUp(self):
|
||||
"""Create the server instance"""
|
||||
self.fontFamily = QgsFontUtils.standardTestFontFamily()
|
||||
QgsFontUtils.loadStandardTestFonts(['All'])
|
||||
|
||||
d = unitTestDataPath('qgis_server_accesscontrol') + '/'
|
||||
self._project_path = os.path.join(d, "project.qgs")
|
||||
|
||||
def test_getcapabilities(self):
|
||||
project = self._project_path
|
||||
assert os.path.exists(project), "Project file not found: " + project
|
||||
|
||||
# without cache
|
||||
query_string = '?MAP=%s&SERVICE=WMS&VERSION=1.3.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
doc = QDomDocument("wms_getcapabilities_130.xml")
|
||||
doc.setContent(body)
|
||||
# with cache
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
# without cache
|
||||
query_string = '?MAP=%s&SERVICE=WMS&VERSION=1.1.1&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
# with cache
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
# without cache
|
||||
query_string = '?MAP=%s&SERVICE=WFS&VERSION=1.1.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
# with cache
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
# without cache
|
||||
query_string = '?MAP=%s&SERVICE=WFS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
# with cache
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
# without cache
|
||||
query_string = '?MAP=%s&SERVICE=WCS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
# with cache
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
# without cache
|
||||
query_string = '?MAP=%s&SERVICE=WMTS&VERSION=1.0.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
header, body = self._execute_request(query_string)
|
||||
# with cache
|
||||
header, body = self._execute_request(query_string)
|
||||
|
||||
filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")]
|
||||
self.assertEqual(len(filelist), 6, 'Not enough file in cache')
|
||||
|
||||
cacheManager = self._server_iface.cacheManager()
|
||||
|
||||
self.assertTrue(cacheManager.deleteCachedDocuments(None), 'deleteCachedDocuments does not return True')
|
||||
|
||||
filelist = [f for f in os.listdir(self._servercache._cache_dir) if f.endswith(".xml")]
|
||||
self.assertEqual(len(filelist), 0, 'All files in cache are not deleted ')
|
||||
|
||||
prj = QgsProject()
|
||||
prj.read(project)
|
||||
|
||||
query_string = '?MAP=%s&SERVICE=WMS&VERSION=1.3.0&REQUEST=%s' % (urllib.parse.quote(project), 'GetCapabilities')
|
||||
request = QgsBufferServerRequest(query_string, QgsServerRequest.GetMethod, {}, None)
|
||||
|
||||
accessControls = self._server_iface.accessControls()
|
||||
|
||||
cDoc = QDomDocument("wms_getcapabilities_130.xml")
|
||||
self.assertFalse(cacheManager.getCachedDocument(cDoc, prj, request, accessControls), 'getCachedDocument is not None')
|
||||
|
||||
self.assertTrue(cacheManager.setCachedDocument(doc, prj, request, accessControls), 'setCachedDocument false')
|
||||
|
||||
self.assertTrue(cacheManager.getCachedDocument(cDoc, prj, request, accessControls), 'getCachedDocument is None')
|
||||
self.assertEqual(doc.documentElement().tagName(), cDoc.documentElement().tagName(), 'cachedDocument not equal to provide document')
|
||||
|
||||
self.assertTrue(cacheManager.deleteCachedDocuments(None), 'deleteCachedDocuments does not return True')
|
||||
|
||||
def test_gettile(self):
|
||||
project = self._project_path
|
||||
assert os.path.exists(project), "Project file not found: " + project
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(project),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Country",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
# without cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
# with cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(project),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Country",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:4326",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
# without cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
# with cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(project),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "QGIS Server Hello World",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
# without cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
# with cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(project),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "QGIS Server Hello World",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:4326",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
# without cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
# with cache
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self.assertEqual(
|
||||
h.get("Content-Type"), "image/png",
|
||||
"Content type is wrong: %s\n%s" % (h.get("Content-Type"), r))
|
||||
|
||||
filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")]
|
||||
self.assertEqual(len(filelist), 4, 'Not enough image in cache')
|
||||
|
||||
cacheManager = self._server_iface.cacheManager()
|
||||
|
||||
self.assertTrue(cacheManager.deleteCachedImages(None), 'deleteCachedImages does not return True')
|
||||
|
||||
filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")]
|
||||
self.assertEqual(len(filelist), 0, 'All images in cache are not deleted ')
|
||||
|
||||
def test_gettile_invalid_parameters(self):
|
||||
project = self._project_path
|
||||
assert os.path.exists(project), "Project file not found: " + project
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(project),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Country",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "FOO",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"TILECOL (\'FOO\') cannot be converted into int" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
filelist = [f for f in os.listdir(self._servercache._tile_cache_dir) if f.endswith(".png")]
|
||||
self.assertEqual(len(filelist), 0, 'Exception has been cached ')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
@ -123,7 +123,9 @@ class TestQgsServerWMS(TestQgsServerWMSTestBase):
|
||||
self.assertXMLEqual(response, expected, msg="request %s failed.\nQuery: %s\nExpected file: %s\nResponse:\n%s" % (query_string, request, reference_path, response.decode('utf-8')))
|
||||
|
||||
def test_wms_getcapabilities_project(self):
|
||||
"""WMS GetCapabilities without map parameter"""
|
||||
self.wms_request_compare_project('GetCapabilities')
|
||||
# reference_file='getcapabilities_without_map_param' could be the right response
|
||||
|
||||
def wms_inspire_request_compare(self, request):
|
||||
"""WMS INSPIRE tests"""
|
||||
|
286
tests/src/python/test_qgsserver_wmts.py
Normal file
@ -0,0 +1,286 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""QGIS Unit tests for QgsServer WFS.
|
||||
|
||||
From build dir, run: ctest -R PyQgsServerWFS -V
|
||||
|
||||
|
||||
.. note:: 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.
|
||||
|
||||
"""
|
||||
__author__ = 'René-Luc Dhont'
|
||||
__date__ = '19/09/2017'
|
||||
__copyright__ = 'Copyright 2017, The QGIS Project'
|
||||
# This will get replaced with a git SHA1 when you do a git archive
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import os
|
||||
|
||||
# Needed on Qt 5 so that the serialization of XML is consistent among all executions
|
||||
os.environ['QT_HASH_SEED'] = '1'
|
||||
|
||||
import re
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
|
||||
from qgis.server import QgsServerRequest
|
||||
|
||||
from qgis.testing import unittest
|
||||
from qgis.PyQt.QtCore import QSize
|
||||
|
||||
import osgeo.gdal # NOQA
|
||||
|
||||
from test_qgsserver import QgsServerTestBase
|
||||
|
||||
# Strip path and content length because path may vary
|
||||
RE_STRIP_UNCHECKABLE = b'MAP=[^"]+|Content-Length: \d+|timeStamp="[^"]+"'
|
||||
RE_ATTRIBUTES = b'[^>\s]+=[^>\s]+'
|
||||
|
||||
|
||||
class TestQgsServerWMTS(QgsServerTestBase):
|
||||
|
||||
"""QGIS Server WMTS Tests"""
|
||||
|
||||
def wmts_request_compare(self, request, version='', extra_query_string='', reference_base_name=None):
|
||||
#project = self.testdata_path + "test_project_wfs.qgs"
|
||||
project = self.projectGroupsPath
|
||||
assert os.path.exists(project), "Project file not found: " + project
|
||||
|
||||
query_string = '?MAP=%s&SERVICE=WMTS&REQUEST=%s' % (urllib.parse.quote(project), request)
|
||||
if version:
|
||||
query_string += '&VERSION=%s' % version
|
||||
|
||||
if extra_query_string:
|
||||
query_string += '&%s' % extra_query_string
|
||||
|
||||
header, body = self._execute_request(query_string)
|
||||
self.assert_headers(header, body)
|
||||
response = header + body
|
||||
|
||||
if reference_base_name is not None:
|
||||
reference_name = reference_base_name
|
||||
else:
|
||||
reference_name = 'wmts_' + request.lower()
|
||||
|
||||
reference_name += '.txt'
|
||||
|
||||
reference_path = self.testdata_path + reference_name
|
||||
|
||||
self.store_reference(reference_path, response)
|
||||
f = open(reference_path, 'rb')
|
||||
expected = f.read()
|
||||
f.close()
|
||||
response = re.sub(RE_STRIP_UNCHECKABLE, b'', response)
|
||||
expected = re.sub(RE_STRIP_UNCHECKABLE, b'', expected)
|
||||
|
||||
self.assertXMLEqual(response, expected, msg="request %s failed.\n Query: %s" % (query_string, request))
|
||||
|
||||
def test_project_wmts(self):
|
||||
"""Test some WMTS request"""
|
||||
for request in ('GetCapabilities',):
|
||||
self.wmts_request_compare(request)
|
||||
#self.wmts_request_compare(request, '1.0.0')
|
||||
|
||||
def test_wmts_gettile(self):
|
||||
# Testing project WMTS layer
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "QGIS Server Hello World",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMTS_GetTile_Project_3857_0", 20000)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "QGIS Server Hello World",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:4326",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMTS_GetTile_Project_4326_0", 20000)
|
||||
|
||||
# Testing group WMTS layer
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "CountryGroup",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMTS_GetTile_CountryGroup_3857_0", 20000)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "CountryGroup",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:4326",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMTS_GetTile_CountryGroup_4326_0", 20000)
|
||||
|
||||
# Testing QgsMapLayer WMTS layer
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Hello",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMTS_GetTile_Hello_3857_0", 20000)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Hello",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:4326",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
self._img_diff_error(r, h, "WMTS_GetTile_Hello_4326_0", 20000)
|
||||
|
||||
def test_wmts_gettile_invalid_parameters(self):
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Hello",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "FOO",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"TILECOL (\'FOO\') cannot be converted into int" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Hello",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "1",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"TileCol is unknown" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Hello",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "-1",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"TileCol is unknown" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "dem",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:3857",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"Layer \'dem\' not found" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
qs = "?" + "&".join(["%s=%s" % i for i in list({
|
||||
"MAP": urllib.parse.quote(self.projectGroupsPath),
|
||||
"SERVICE": "WMTS",
|
||||
"VERSION": "1.0.0",
|
||||
"REQUEST": "GetTile",
|
||||
"LAYER": "Hello",
|
||||
"STYLE": "",
|
||||
"TILEMATRIXSET": "EPSG:2154",
|
||||
"TILEMATRIX": "0",
|
||||
"TILEROW": "0",
|
||||
"TILECOL": "0",
|
||||
"FORMAT": "image/png"
|
||||
}.items())])
|
||||
|
||||
r, h = self._result(self._execute_request(qs))
|
||||
err = b"TileMatrixSet is unknown" in r
|
||||
self.assertTrue(err)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 94 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 19 KiB |
BIN
tests/testdata/control_images/qgis_server/WMTS_GetTile_Hello_3857_0/WMTS_GetTile_Hello_3857_0.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
tests/testdata/control_images/qgis_server/WMTS_GetTile_Hello_4326_0/WMTS_GetTile_Hello_4326_0.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 27 KiB |
246
tests/testdata/qgis_server/getcapabilities_without_map_param.txt
vendored
Normal file
@ -0,0 +1,246 @@
|
||||
Content-Length: 6575
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<WMS_Capabilities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:qgs="http://www.qgis.org/wms" xmlns="http://www.opengis.net/wms" xsi:schemaLocation="http://www.opengis.net/wms http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd http://www.opengis.net/sld http://schemas.opengis.net/sld/1.1.0/sld_capabilities.xsd http://www.qgis.org/wms https://www.qgis.org/?SERVICE=WMS&REQUEST=GetSchemaExtension" version="1.3.0" xmlns:sld="http://www.opengis.net/sld">
|
||||
<Service>
|
||||
<Name>WMS</Name>
|
||||
<Title>QGIS TestProject</Title>
|
||||
<Abstract><![CDATA[Some UTF8 text èòù]]></Abstract>
|
||||
<KeywordList>
|
||||
<Keyword vocabulary="ISO">infoMapAccessService</Keyword>
|
||||
</KeywordList>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
<ContactInformation>
|
||||
<ContactPersonPrimary>
|
||||
<ContactPerson>Alessandro Pasotti</ContactPerson>
|
||||
<ContactOrganization>QGIS dev team</ContactOrganization>
|
||||
</ContactPersonPrimary>
|
||||
<ContactElectronicMailAddress>elpaso@itopen.it</ContactElectronicMailAddress>
|
||||
</ContactInformation>
|
||||
<Fees>conditions unknown</Fees>
|
||||
<AccessConstraints>None</AccessConstraints>
|
||||
</Service>
|
||||
<Capability>
|
||||
<Request>
|
||||
<GetCapabilities>
|
||||
<Format>text/xml</Format>
|
||||
<DCPType>
|
||||
<HTTP>
|
||||
<Get>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</Get>
|
||||
</HTTP>
|
||||
</DCPType>
|
||||
</GetCapabilities>
|
||||
<GetMap>
|
||||
<Format>image/jpeg</Format>
|
||||
<Format>image/png</Format>
|
||||
<Format>image/png; mode=16bit</Format>
|
||||
<Format>image/png; mode=8bit</Format>
|
||||
<Format>image/png; mode=1bit</Format>
|
||||
<Format>application/dxf</Format>
|
||||
<DCPType>
|
||||
<HTTP>
|
||||
<Get>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</Get>
|
||||
</HTTP>
|
||||
</DCPType>
|
||||
</GetMap>
|
||||
<GetFeatureInfo>
|
||||
<Format>text/plain</Format>
|
||||
<Format>text/html</Format>
|
||||
<Format>text/xml</Format>
|
||||
<Format>application/vnd.ogc.gml</Format>
|
||||
<Format>application/vnd.ogc.gml/3.1.1</Format>
|
||||
<DCPType>
|
||||
<HTTP>
|
||||
<Get>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</Get>
|
||||
</HTTP>
|
||||
</DCPType>
|
||||
</GetFeatureInfo>
|
||||
<sld:GetLegendGraphic>
|
||||
<Format>image/jpeg</Format>
|
||||
<Format>image/png</Format>
|
||||
<DCPType>
|
||||
<HTTP>
|
||||
<Get>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</Get>
|
||||
</HTTP>
|
||||
</DCPType>
|
||||
</sld:GetLegendGraphic>
|
||||
<sld:DescribeLayer>
|
||||
<Format>text/xml</Format>
|
||||
<DCPType>
|
||||
<HTTP>
|
||||
<Get>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</Get>
|
||||
</HTTP>
|
||||
</DCPType>
|
||||
</sld:DescribeLayer>
|
||||
<qgs:GetStyles>
|
||||
<Format>text/xml</Format>
|
||||
<DCPType>
|
||||
<HTTP>
|
||||
<Get>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</Get>
|
||||
</HTTP>
|
||||
</DCPType>
|
||||
</qgs:GetStyles>
|
||||
</Request>
|
||||
<Exception>
|
||||
<Format>XML</Format>
|
||||
</Exception>
|
||||
<sld:UserDefinedSymbolization SupportSLD="1" RemoteWCS="0" UserLayer="0" InlineFeature="0" RemoteWFS="0" UserStyle="1"/>
|
||||
<Layer>
|
||||
<Title>QGIS Test Project</Title>
|
||||
<Abstract>QGIS Test Project</Abstract>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20315</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20416</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9012</southBoundLatitude>
|
||||
<northBoundLatitude>44.9016</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60604e+06" maxx="913283" miny="5.60599e+06" CRS="EPSG:3857" minx="913171"/>
|
||||
<BoundingBox maxy="8.20416" maxx="44.9016" miny="8.20315" CRS="EPSG:4326" minx="44.9012"/>
|
||||
<Name>QGIS Test Project</Name>
|
||||
<KeywordList>
|
||||
<Keyword vocabulary="ISO">infoMapAccessService</Keyword>
|
||||
</KeywordList>
|
||||
<Layer queryable="1">
|
||||
<Name>layer_with_short_name</Name>
|
||||
<Title>A Layer with a short name</Title>
|
||||
<Abstract>A Layer with an abstract</Abstract>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20346</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20355</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9014</southBoundLatitude>
|
||||
<northBoundLatitude>44.9015</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60603e+06" maxx="913215" miny="5.60601e+06" CRS="EPSG:3857" minx="913205"/>
|
||||
<BoundingBox maxy="8.20355" maxx="44.9015" miny="8.20346" CRS="EPSG:4326" minx="44.9014"/>
|
||||
<Style>
|
||||
<Name>default</Name>
|
||||
<Title>default</Title>
|
||||
<LegendURL>
|
||||
<Format>image/png</Format>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=layer_with_short_name&FORMAT=image/png&STYLE=default&SLD_VERSION=1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</LegendURL>
|
||||
</Style>
|
||||
</Layer>
|
||||
<Layer queryable="1">
|
||||
<Name>testlayer èé</Name>
|
||||
<Title>A test vector layer</Title>
|
||||
<Abstract>A test vector layer with unicode òà</Abstract>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20346</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20355</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9014</southBoundLatitude>
|
||||
<northBoundLatitude>44.9015</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60603e+06" maxx="913215" miny="5.60601e+06" CRS="EPSG:3857" minx="913205"/>
|
||||
<BoundingBox maxy="8.20355" maxx="44.9015" miny="8.20346" CRS="EPSG:4326" minx="44.9014"/>
|
||||
<Style>
|
||||
<Name>default</Name>
|
||||
<Title>default</Title>
|
||||
<LegendURL>
|
||||
<Format>image/png</Format>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=testlayer èé&FORMAT=image/png&STYLE=default&SLD_VERSION=1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</LegendURL>
|
||||
</Style>
|
||||
</Layer>
|
||||
<Layer>
|
||||
<Name>group_name</Name>
|
||||
<Title>Group title</Title>
|
||||
<Abstract>Group abstract</Abstract>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20346</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20355</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9014</southBoundLatitude>
|
||||
<northBoundLatitude>44.9015</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60603e+06" maxx="913215" miny="5.60601e+06" CRS="EPSG:3857" minx="913205"/>
|
||||
<BoundingBox maxy="8.20355" maxx="44.9015" miny="8.20346" CRS="EPSG:4326" minx="44.9014"/>
|
||||
<Layer queryable="1">
|
||||
<Name>testlayer2</Name>
|
||||
<Title>testlayer2</Title>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20346</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20355</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9014</southBoundLatitude>
|
||||
<northBoundLatitude>44.9015</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60603e+06" maxx="913215" miny="5.60601e+06" CRS="EPSG:3857" minx="913205"/>
|
||||
<BoundingBox maxy="8.20355" maxx="44.9015" miny="8.20346" CRS="EPSG:4326" minx="44.9014"/>
|
||||
<Style>
|
||||
<Name>default</Name>
|
||||
<Title>default</Title>
|
||||
<LegendURL>
|
||||
<Format>image/png</Format>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=testlayer2&FORMAT=image/png&STYLE=default&SLD_VERSION=1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</LegendURL>
|
||||
</Style>
|
||||
</Layer>
|
||||
</Layer>
|
||||
<Layer>
|
||||
<Name>groupwithoutshortname</Name>
|
||||
<Title>groupwithoutshortname</Title>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20346</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20355</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9014</southBoundLatitude>
|
||||
<northBoundLatitude>44.9015</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60603e+06" maxx="913215" miny="5.60601e+06" CRS="EPSG:3857" minx="913205"/>
|
||||
<BoundingBox maxy="8.20355" maxx="44.9015" miny="8.20346" CRS="EPSG:4326" minx="44.9014"/>
|
||||
<Layer queryable="0">
|
||||
<Name>testlayer3</Name>
|
||||
<Title>testlayer3</Title>
|
||||
<CRS>CRS:84</CRS>
|
||||
<CRS>EPSG:4326</CRS>
|
||||
<CRS>EPSG:3857</CRS>
|
||||
<EX_GeographicBoundingBox>
|
||||
<westBoundLongitude>8.20346</westBoundLongitude>
|
||||
<eastBoundLongitude>8.20355</eastBoundLongitude>
|
||||
<southBoundLatitude>44.9014</southBoundLatitude>
|
||||
<northBoundLatitude>44.9015</northBoundLatitude>
|
||||
</EX_GeographicBoundingBox>
|
||||
<BoundingBox maxy="5.60603e+06" maxx="913215" miny="5.60601e+06" CRS="EPSG:3857" minx="913205"/>
|
||||
<BoundingBox maxy="8.20355" maxx="44.9015" miny="8.20346" CRS="EPSG:4326" minx="44.9014"/>
|
||||
<Style>
|
||||
<Name>default</Name>
|
||||
<Title>default</Title>
|
||||
<LegendURL>
|
||||
<Format>image/png</Format>
|
||||
<OnlineResource xlink:type="simple" xlink:href="https://www.qgis.org/?&SERVICE=WMS&VERSION=1.3.0&REQUEST=GetLegendGraphic&LAYER=testlayer3&FORMAT=image/png&STYLE=default&SLD_VERSION=1.1.0" xmlns:xlink="http://www.w3.org/1999/xlink"/>
|
||||
</LegendURL>
|
||||
</Style>
|
||||
</Layer>
|
||||
</Layer>
|
||||
</Layer>
|
||||
</Capability>
|
||||
</WMS_Capabilities>
|
869
tests/testdata/qgis_server/wmts_getcapabilities.txt
vendored
Normal file
@ -0,0 +1,869 @@
|
||||
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
|
||||
<Capabilities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wmts/1.0 http://schemas.opengis.net/wmts/1.0/wmtsGetCapabilities_response.xsd" xmlns="http://www.opengis.net/wmts/1.0" version="1.0.0" xmlns:gml="http://www.opengis.net/gml" xmlns:ows="http://www.opengis.net/ows/1.1" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<ows:ServiceIdentification>
|
||||
<ows:ServiceType>OGC WMTS</ows:ServiceType>
|
||||
<ows:ServiceTypeVersion>1.0.0</ows:ServiceTypeVersion>
|
||||
<ows:Title>QGIS Server test</ows:Title>
|
||||
<ows:Abstract><![CDATA[Simple test app.]]></ows:Abstract>
|
||||
<ows:Fees>conditions unknown</ows:Fees>
|
||||
<ows:AccessConstraints>None</ows:AccessConstraints>
|
||||
</ows:ServiceIdentification>
|
||||
<ows:ServiceProvider>
|
||||
<ows:ProviderName>QGIS</ows:ProviderName>
|
||||
<ows:ServiceContact>
|
||||
<ows:IndividualName>Stéphane Brunner</ows:IndividualName>
|
||||
</ows:ServiceContact>
|
||||
</ows:ServiceProvider>
|
||||
<ows:OperationsMetadata>
|
||||
<ows:Operation name="GetCapabilities">
|
||||
<ows:DCP>
|
||||
<ows:HTTP>
|
||||
<ows:Get xlink:href="?"/>
|
||||
</ows:HTTP>
|
||||
</ows:DCP>
|
||||
</ows:Operation>
|
||||
<ows:Operation name="GetTile">
|
||||
<ows:DCP>
|
||||
<ows:HTTP>
|
||||
<ows:Get xlink:href="?"/>
|
||||
</ows:HTTP>
|
||||
</ows:DCP>
|
||||
</ows:Operation>
|
||||
<ows:Operation name="GetFeatureInfo">
|
||||
<ows:DCP>
|
||||
<ows:HTTP>
|
||||
<ows:Get xlink:href="?"/>
|
||||
</ows:HTTP>
|
||||
</ows:DCP>
|
||||
</ows:Operation>
|
||||
</ows:OperationsMetadata>
|
||||
<Contents>
|
||||
<Layer>
|
||||
<ows:Identifier>QGIS Server Hello World</ows:Identifier>
|
||||
<ows:Title>QGIS Server Hello World</ows:Title>
|
||||
<ows:Abstract>QGIS Server Hello World</ows:Abstract>
|
||||
<ows:WGS84BoundingBox>
|
||||
<LowerCorner>-174.766573 -69.957838</LowerCorner>
|
||||
<UpperCorner>177.930819 84.307876</UpperCorner>
|
||||
</ows:WGS84BoundingBox>
|
||||
<ows:BoundingBox crs="EPSG:3857">
|
||||
<LowerCorner>-19454925.898459 -11055006.822989</LowerCorner>
|
||||
<UpperCorner>19807168.136881 19143772.793601</UpperCorner>
|
||||
</ows:BoundingBox>
|
||||
<Style isDefault="true">
|
||||
<ows:Identifier>default</ows:Identifier>
|
||||
<ows:Title>default</ows:Title>
|
||||
</Style>
|
||||
<Format>image/png</Format>
|
||||
<TileMatrixSetLink>
|
||||
<TileMatrixSet>EPSG:3857</TileMatrixSet>
|
||||
<TileMatrixSetLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>0</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>0</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>0</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>1</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>1</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>1</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>2</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>3</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>3</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>3</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>7</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>6</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>4</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>15</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>12</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>5</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>31</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>24</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>6</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>63</MaxTileCol>
|
||||
<MinTileRow>1</MinTileRow>
|
||||
<MaxTileRow>49</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>7</TileMatrix>
|
||||
<MinTileCol>1</MinTileCol>
|
||||
<MaxTileCol>127</MaxTileCol>
|
||||
<MinTileRow>2</MinTileRow>
|
||||
<MaxTileRow>99</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>8</TileMatrix>
|
||||
<MinTileCol>3</MinTileCol>
|
||||
<MaxTileCol>254</MaxTileCol>
|
||||
<MinTileRow>5</MinTileRow>
|
||||
<MaxTileRow>198</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>9</TileMatrix>
|
||||
<MinTileCol>7</MinTileCol>
|
||||
<MaxTileCol>509</MaxTileCol>
|
||||
<MinTileRow>11</MinTileRow>
|
||||
<MaxTileRow>397</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>10</TileMatrix>
|
||||
<MinTileCol>14</MinTileCol>
|
||||
<MaxTileCol>1018</MaxTileCol>
|
||||
<MinTileRow>22</MinTileRow>
|
||||
<MaxTileRow>794</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>11</TileMatrix>
|
||||
<MinTileCol>29</MinTileCol>
|
||||
<MaxTileCol>2036</MaxTileCol>
|
||||
<MinTileRow>45</MinTileRow>
|
||||
<MaxTileRow>1588</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>12</TileMatrix>
|
||||
<MinTileCol>59</MinTileCol>
|
||||
<MaxTileCol>4072</MaxTileCol>
|
||||
<MinTileRow>91</MinTileRow>
|
||||
<MaxTileRow>3177</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>13</TileMatrix>
|
||||
<MinTileCol>119</MinTileCol>
|
||||
<MaxTileCol>8144</MaxTileCol>
|
||||
<MinTileRow>182</MinTileRow>
|
||||
<MaxTileRow>6355</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>14</TileMatrix>
|
||||
<MinTileCol>238</MinTileCol>
|
||||
<MaxTileCol>16289</MaxTileCol>
|
||||
<MinTileRow>365</MinTileRow>
|
||||
<MaxTileRow>12711</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>15</TileMatrix>
|
||||
<MinTileCol>476</MinTileCol>
|
||||
<MaxTileCol>32579</MaxTileCol>
|
||||
<MinTileRow>730</MinTileRow>
|
||||
<MaxTileRow>25423</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>16</TileMatrix>
|
||||
<MinTileCol>952</MinTileCol>
|
||||
<MaxTileCol>65159</MaxTileCol>
|
||||
<MinTileRow>1461</MinTileRow>
|
||||
<MaxTileRow>50846</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>17</TileMatrix>
|
||||
<MinTileCol>1905</MinTileCol>
|
||||
<MaxTileCol>130318</MaxTileCol>
|
||||
<MinTileRow>2923</MinTileRow>
|
||||
<MaxTileRow>101693</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>18</TileMatrix>
|
||||
<MinTileCol>3810</MinTileCol>
|
||||
<MaxTileCol>260637</MaxTileCol>
|
||||
<MinTileRow>5846</MinTileRow>
|
||||
<MaxTileRow>203386</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>19</TileMatrix>
|
||||
<MinTileCol>7621</MinTileCol>
|
||||
<MaxTileCol>521274</MaxTileCol>
|
||||
<MinTileRow>11692</MinTileRow>
|
||||
<MaxTileRow>406772</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>20</TileMatrix>
|
||||
<MinTileCol>15243</MinTileCol>
|
||||
<MaxTileCol>1042549</MaxTileCol>
|
||||
<MinTileRow>23384</MinTileRow>
|
||||
<MaxTileRow>813545</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
</TileMatrixSetLimits>
|
||||
</TileMatrixSetLink>
|
||||
<TileMatrixSetLink>
|
||||
<TileMatrixSet>EPSG:4326</TileMatrixSet>
|
||||
<TileMatrixSetLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>0</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>1</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>0</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>1</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>3</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>1</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>2</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>7</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>3</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>3</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>15</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>7</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>4</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>31</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>14</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>5</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>63</MaxTileCol>
|
||||
<MinTileRow>1</MinTileRow>
|
||||
<MaxTileRow>28</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>6</TileMatrix>
|
||||
<MinTileCol>1</MinTileCol>
|
||||
<MaxTileCol>127</MaxTileCol>
|
||||
<MinTileRow>2</MinTileRow>
|
||||
<MaxTileRow>56</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>7</TileMatrix>
|
||||
<MinTileCol>3</MinTileCol>
|
||||
<MaxTileCol>254</MaxTileCol>
|
||||
<MinTileRow>4</MinTileRow>
|
||||
<MaxTileRow>113</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>8</TileMatrix>
|
||||
<MinTileCol>7</MinTileCol>
|
||||
<MaxTileCol>508</MaxTileCol>
|
||||
<MinTileRow>8</MinTileRow>
|
||||
<MaxTileRow>227</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>9</TileMatrix>
|
||||
<MinTileCol>14</MinTileCol>
|
||||
<MaxTileCol>1016</MaxTileCol>
|
||||
<MinTileRow>16</MinTileRow>
|
||||
<MaxTileRow>454</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>10</TileMatrix>
|
||||
<MinTileCol>29</MinTileCol>
|
||||
<MaxTileCol>2032</MaxTileCol>
|
||||
<MinTileRow>32</MinTileRow>
|
||||
<MaxTileRow>908</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>11</TileMatrix>
|
||||
<MinTileCol>59</MinTileCol>
|
||||
<MaxTileCol>4065</MaxTileCol>
|
||||
<MinTileRow>64</MinTileRow>
|
||||
<MaxTileRow>1816</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>12</TileMatrix>
|
||||
<MinTileCol>118</MinTileCol>
|
||||
<MaxTileCol>8130</MaxTileCol>
|
||||
<MinTileRow>129</MinTileRow>
|
||||
<MaxTileRow>3633</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>13</TileMatrix>
|
||||
<MinTileCol>237</MinTileCol>
|
||||
<MaxTileCol>16260</MaxTileCol>
|
||||
<MinTileRow>258</MinTileRow>
|
||||
<MaxTileRow>7266</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>14</TileMatrix>
|
||||
<MinTileCol>475</MinTileCol>
|
||||
<MaxTileCol>32520</MaxTileCol>
|
||||
<MinTileRow>517</MinTileRow>
|
||||
<MaxTileRow>14533</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>15</TileMatrix>
|
||||
<MinTileCol>951</MinTileCol>
|
||||
<MaxTileCol>65041</MaxTileCol>
|
||||
<MinTileRow>1034</MinTileRow>
|
||||
<MaxTileRow>29066</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>16</TileMatrix>
|
||||
<MinTileCol>1902</MinTileCol>
|
||||
<MaxTileCol>130083</MaxTileCol>
|
||||
<MinTileRow>2068</MinTileRow>
|
||||
<MaxTileRow>58133</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>17</TileMatrix>
|
||||
<MinTileCol>3804</MinTileCol>
|
||||
<MaxTileCol>260167</MaxTileCol>
|
||||
<MinTileRow>4137</MinTileRow>
|
||||
<MaxTileRow>116267</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>18</TileMatrix>
|
||||
<MinTileCol>7608</MinTileCol>
|
||||
<MaxTileCol>520335</MaxTileCol>
|
||||
<MinTileRow>8274</MinTileRow>
|
||||
<MaxTileRow>232535</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>19</TileMatrix>
|
||||
<MinTileCol>15216</MinTileCol>
|
||||
<MaxTileCol>1040671</MaxTileCol>
|
||||
<MinTileRow>16549</MinTileRow>
|
||||
<MaxTileRow>465071</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
</TileMatrixSetLimits>
|
||||
</TileMatrixSetLink>
|
||||
</Layer>
|
||||
<Layer>
|
||||
<ows:Identifier>CountryGroup</ows:Identifier>
|
||||
<ows:Title>CountryGroup</ows:Title>
|
||||
<ows:WGS84BoundingBox>
|
||||
<LowerCorner>-176.248495 -67.592996</LowerCorner>
|
||||
<UpperCorner>179.412741 83.621086</UpperCorner>
|
||||
</ows:WGS84BoundingBox>
|
||||
<ows:BoundingBox crs="EPSG:3857">
|
||||
<LowerCorner>-19619892.68012 -10327100.342322</LowerCorner>
|
||||
<UpperCorner>19972134.918542 18415866.312934</UpperCorner>
|
||||
</ows:BoundingBox>
|
||||
<Style isDefault="true">
|
||||
<ows:Identifier>default</ows:Identifier>
|
||||
<ows:Title>default</ows:Title>
|
||||
</Style>
|
||||
<Format>image/png</Format>
|
||||
<InfoFormat>text/plain</InfoFormat>
|
||||
<InfoFormat>text/html</InfoFormat>
|
||||
<InfoFormat>text/xml</InfoFormat>
|
||||
<InfoFormat>application/vnd.ogc.gml</InfoFormat>
|
||||
<InfoFormat>application/vnd.ogc.gml/3.1.1</InfoFormat>
|
||||
<TileMatrixSetLink>
|
||||
<TileMatrixSet>EPSG:3857</TileMatrixSet>
|
||||
<TileMatrixSetLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>0</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>0</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>0</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>1</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>1</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>1</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>2</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>3</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>3</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
</TileMatrixSetLimits>
|
||||
</TileMatrixSetLink>
|
||||
<TileMatrixSetLink>
|
||||
<TileMatrixSet>EPSG:4326</TileMatrixSet>
|
||||
<TileMatrixSetLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>0</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>1</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>0</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>1</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>3</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>1</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
</TileMatrixSetLimits>
|
||||
</TileMatrixSetLink>
|
||||
</Layer>
|
||||
<Layer>
|
||||
<ows:Identifier>Hello</ows:Identifier>
|
||||
<ows:WGS84BoundingBox>
|
||||
<LowerCorner>-132.467818 -1.006739</LowerCorner>
|
||||
<UpperCorner>101.888717 69.520496</UpperCorner>
|
||||
</ows:WGS84BoundingBox>
|
||||
<ows:BoundingBox crs="EPSG:3857">
|
||||
<LowerCorner>-14746250.075131 -112075.428077</LowerCorner>
|
||||
<UpperCorner>11342200.077197 10914413.714128</UpperCorner>
|
||||
</ows:BoundingBox>
|
||||
<Style isDefault="true">
|
||||
<ows:Identifier>default</ows:Identifier>
|
||||
<ows:Title>default</ows:Title>
|
||||
</Style>
|
||||
<Format>image/png</Format>
|
||||
<InfoFormat>text/plain</InfoFormat>
|
||||
<InfoFormat>text/html</InfoFormat>
|
||||
<InfoFormat>text/xml</InfoFormat>
|
||||
<InfoFormat>application/vnd.ogc.gml</InfoFormat>
|
||||
<InfoFormat>application/vnd.ogc.gml/3.1.1</InfoFormat>
|
||||
<TileMatrixSetLink>
|
||||
<TileMatrixSet>EPSG:3857</TileMatrixSet>
|
||||
<TileMatrixSetLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>0</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>0</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>0</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>1</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>1</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>1</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>2</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>3</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>2</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
</TileMatrixSetLimits>
|
||||
</TileMatrixSetLink>
|
||||
<TileMatrixSetLink>
|
||||
<TileMatrixSet>EPSG:4326</TileMatrixSet>
|
||||
<TileMatrixSetLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>0</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>1</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>0</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
<TileMatrixLimits>
|
||||
<TileMatrix>1</TileMatrix>
|
||||
<MinTileCol>0</MinTileCol>
|
||||
<MaxTileCol>3</MaxTileCol>
|
||||
<MinTileRow>0</MinTileRow>
|
||||
<MaxTileRow>1</MaxTileRow>
|
||||
</TileMatrixLimits>
|
||||
</TileMatrixSetLimits>
|
||||
</TileMatrixSetLink>
|
||||
</Layer>
|
||||
<TileMatrixSet>
|
||||
<ows:Identifier>EPSG:3857</ows:Identifier>
|
||||
<ows:SupportedCRS>EPSG:3857</ows:SupportedCRS>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>0</ows:Identifier>
|
||||
<ScaleDenominator>559082264.028718</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>1</MatrixWidth>
|
||||
<MatrixHeight>1</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>1</ows:Identifier>
|
||||
<ScaleDenominator>279541132.014359</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>2</MatrixWidth>
|
||||
<MatrixHeight>2</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>2</ows:Identifier>
|
||||
<ScaleDenominator>139770566.007179</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>4</MatrixWidth>
|
||||
<MatrixHeight>4</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>3</ows:Identifier>
|
||||
<ScaleDenominator>69885283.00359</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>8</MatrixWidth>
|
||||
<MatrixHeight>8</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>4</ows:Identifier>
|
||||
<ScaleDenominator>34942641.501795</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>16</MatrixWidth>
|
||||
<MatrixHeight>16</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>5</ows:Identifier>
|
||||
<ScaleDenominator>17471320.750897</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>32</MatrixWidth>
|
||||
<MatrixHeight>32</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>6</ows:Identifier>
|
||||
<ScaleDenominator>8735660.375449</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>64</MatrixWidth>
|
||||
<MatrixHeight>64</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>7</ows:Identifier>
|
||||
<ScaleDenominator>4367830.187724</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>128</MatrixWidth>
|
||||
<MatrixHeight>128</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>8</ows:Identifier>
|
||||
<ScaleDenominator>2183915.093862</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>256</MatrixWidth>
|
||||
<MatrixHeight>256</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>9</ows:Identifier>
|
||||
<ScaleDenominator>1091957.546931</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>512</MatrixWidth>
|
||||
<MatrixHeight>512</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>10</ows:Identifier>
|
||||
<ScaleDenominator>545978.773466</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>1024</MatrixWidth>
|
||||
<MatrixHeight>1024</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>11</ows:Identifier>
|
||||
<ScaleDenominator>272989.386733</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>2048</MatrixWidth>
|
||||
<MatrixHeight>2048</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>12</ows:Identifier>
|
||||
<ScaleDenominator>136494.693366</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>4096</MatrixWidth>
|
||||
<MatrixHeight>4096</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>13</ows:Identifier>
|
||||
<ScaleDenominator>68247.346683</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>8192</MatrixWidth>
|
||||
<MatrixHeight>8192</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>14</ows:Identifier>
|
||||
<ScaleDenominator>34123.673342</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>16384</MatrixWidth>
|
||||
<MatrixHeight>16384</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>15</ows:Identifier>
|
||||
<ScaleDenominator>17061.836671</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>32768</MatrixWidth>
|
||||
<MatrixHeight>32768</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>16</ows:Identifier>
|
||||
<ScaleDenominator>8530.918335</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>65536</MatrixWidth>
|
||||
<MatrixHeight>65536</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>17</ows:Identifier>
|
||||
<ScaleDenominator>4265.459168</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>131072</MatrixWidth>
|
||||
<MatrixHeight>131072</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>18</ows:Identifier>
|
||||
<ScaleDenominator>2132.729584</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>262144</MatrixWidth>
|
||||
<MatrixHeight>262144</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>19</ows:Identifier>
|
||||
<ScaleDenominator>1066.364792</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>524288</MatrixWidth>
|
||||
<MatrixHeight>524288</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>20</ows:Identifier>
|
||||
<ScaleDenominator>533.182396</ScaleDenominator>
|
||||
<TopLeftCorner>-20037508.342789 20037508.342789</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>1048576</MatrixWidth>
|
||||
<MatrixHeight>1048576</MatrixHeight>
|
||||
</TileMatrix>
|
||||
</TileMatrixSet>
|
||||
<TileMatrixSet>
|
||||
<ows:Identifier>EPSG:4326</ows:Identifier>
|
||||
<ows:SupportedCRS>EPSG:4326</ows:SupportedCRS>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>0</ows:Identifier>
|
||||
<ScaleDenominator>279541132.014359</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>2</MatrixWidth>
|
||||
<MatrixHeight>1</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>1</ows:Identifier>
|
||||
<ScaleDenominator>139770566.007179</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>4</MatrixWidth>
|
||||
<MatrixHeight>2</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>2</ows:Identifier>
|
||||
<ScaleDenominator>69885283.00359</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>8</MatrixWidth>
|
||||
<MatrixHeight>4</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>3</ows:Identifier>
|
||||
<ScaleDenominator>34942641.501795</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>16</MatrixWidth>
|
||||
<MatrixHeight>8</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>4</ows:Identifier>
|
||||
<ScaleDenominator>17471320.750897</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>32</MatrixWidth>
|
||||
<MatrixHeight>16</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>5</ows:Identifier>
|
||||
<ScaleDenominator>8735660.375449</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>64</MatrixWidth>
|
||||
<MatrixHeight>32</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>6</ows:Identifier>
|
||||
<ScaleDenominator>4367830.187724</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>128</MatrixWidth>
|
||||
<MatrixHeight>64</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>7</ows:Identifier>
|
||||
<ScaleDenominator>2183915.093862</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>256</MatrixWidth>
|
||||
<MatrixHeight>128</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>8</ows:Identifier>
|
||||
<ScaleDenominator>1091957.546931</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>512</MatrixWidth>
|
||||
<MatrixHeight>256</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>9</ows:Identifier>
|
||||
<ScaleDenominator>545978.773466</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>1023</MatrixWidth>
|
||||
<MatrixHeight>512</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>10</ows:Identifier>
|
||||
<ScaleDenominator>272989.386733</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>2045</MatrixWidth>
|
||||
<MatrixHeight>1023</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>11</ows:Identifier>
|
||||
<ScaleDenominator>136494.693366</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>4089</MatrixWidth>
|
||||
<MatrixHeight>2045</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>12</ows:Identifier>
|
||||
<ScaleDenominator>68247.346683</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>8178</MatrixWidth>
|
||||
<MatrixHeight>4089</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>13</ows:Identifier>
|
||||
<ScaleDenominator>34123.673342</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>16355</MatrixWidth>
|
||||
<MatrixHeight>8178</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>14</ows:Identifier>
|
||||
<ScaleDenominator>17061.836671</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>32709</MatrixWidth>
|
||||
<MatrixHeight>16355</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>15</ows:Identifier>
|
||||
<ScaleDenominator>8530.918335</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>65418</MatrixWidth>
|
||||
<MatrixHeight>32709</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>16</ows:Identifier>
|
||||
<ScaleDenominator>4265.459168</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>130836</MatrixWidth>
|
||||
<MatrixHeight>65418</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>17</ows:Identifier>
|
||||
<ScaleDenominator>2132.729584</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>261672</MatrixWidth>
|
||||
<MatrixHeight>130836</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>18</ows:Identifier>
|
||||
<ScaleDenominator>1066.364792</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>523344</MatrixWidth>
|
||||
<MatrixHeight>261672</MatrixHeight>
|
||||
</TileMatrix>
|
||||
<TileMatrix>
|
||||
<ows:Identifier>19</ows:Identifier>
|
||||
<ScaleDenominator>533.182396</ScaleDenominator>
|
||||
<TopLeftCorner>-180 90</TopLeftCorner>
|
||||
<TileWidth>256</TileWidth>
|
||||
<TileHeight>256</TileHeight>
|
||||
<MatrixWidth>1046688</MatrixWidth>
|
||||
<MatrixHeight>523344</MatrixHeight>
|
||||
</TileMatrix>
|
||||
</TileMatrixSet>
|
||||
</Contents>
|
||||
</Capabilities>
|
2936
tests/testdata/qgis_server_accesscontrol/project.qgs
vendored
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
|
||||
<qgis projectname="QGIS Server Hello World" version="3.2.0-Bonn">
|
||||
<qgis projectname="QGIS Server Hello World" version="3.3.0-Master">
|
||||
<homePath path=""/>
|
||||
<title>QGIS Server Hello World</title>
|
||||
<autotransaction active="0"/>
|
||||
@ -4362,6 +4362,29 @@ def my_form_open(dialog, layer, feature):
|
||||
<ProjectionsEnabled type="int">1</ProjectionsEnabled>
|
||||
<ProjectCRSProj4String type="QString">+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs</ProjectCRSProj4String>
|
||||
</SpatialRefSys>
|
||||
<WMTSLayers>
|
||||
<Project type="bool">true</Project>
|
||||
<Group type="QStringList">
|
||||
<value>CountryGroup</value>
|
||||
</Group>
|
||||
<Layer type="QStringList">
|
||||
<value>hello20131022151106574</value>
|
||||
</Layer>
|
||||
</WMTSLayers>
|
||||
<WMTSPngLayers>
|
||||
<Project type="bool">true</Project>
|
||||
<Group type="QStringList">
|
||||
<value>CountryGroup</value>
|
||||
</Group>
|
||||
<Layer type="QStringList">
|
||||
<value>hello20131022151106574</value>
|
||||
</Layer>
|
||||
</WMTSPngLayers>
|
||||
<WMTSJpegLayers>
|
||||
<Project type="bool">false</Project>
|
||||
<Group type="QStringList"/>
|
||||
<Layer type="QStringList"/>
|
||||
</WMTSJpegLayers>
|
||||
</properties>
|
||||
<visibility-presets/>
|
||||
<transformContext/>
|
||||
|