77 #include <QStringList>
78 #include <QTemporaryFile>
81 #include <nlohmann/json.hpp>
106 : mContext( context )
108 mProject = mContext.project();
110 mWmsParameters = mContext.parameters();
111 mWmsParameters.dump();
116 removeTemporaryLayers();
122 std::unique_ptr<QgsWmsRestorer> restorer;
134 std::unique_ptr<QImage> image;
136 const QSizeF minSize = renderer.minimumSize();
137 const QSize size(
static_cast<int>( minSize.width() * dpmm ),
static_cast<int>( minSize.height() * dpmm ) );
142 image.reset( createImage( size ) );
145 QPainter painter( image.get() );
156 renderer.drawLegend( context );
159 return image.release();
165 std::unique_ptr<QgsWmsRestorer> restorer;
166 restorer.reset(
new QgsWmsRestorer( mContext ) );
179 std::unique_ptr<QImage> image( createImage( size ) );
183 std::unique_ptr<QPainter> painter;
184 painter.reset(
new QPainter( image.get() ) );
185 painter->setRenderHint( QPainter::Antialiasing,
true );
186 painter->scale( dpmm, dpmm );
192 nodeModel.
drawSymbol( settings, &ctx, size.height() / dpmm );
195 return image.release();
201 std::unique_ptr<QgsWmsRestorer> restorer;
202 restorer.reset(
new QgsWmsRestorer( mContext ) );
214 return renderer.exportLegendToJson( renderContext );
217 void QgsRenderer::runHitTest(
const QgsMapSettings &mapSettings, HitTest &hitTest )
const
221 for (
const QString &
id : mapSettings.
layerIds() )
238 runHitTestLayer( vl, usedSymbols, context );
244 std::unique_ptr< QgsFeatureRenderer > r( vl->
renderer()->
clone() );
246 r->startRender( context, vl->
fields() );
254 if ( moreSymbolsPerFeature )
256 for (
QgsSymbol *s : r->originalSymbolsForFeature( f, context ) )
262 r->stopRender( context );
271 QStringLiteral(
"The requested map size is too large" ) );
275 std::unique_ptr<QgsWmsRestorer> restorer;
276 restorer.reset(
new QgsWmsRestorer( mContext ) );
285 std::unique_ptr<QPainter> painter;
286 std::unique_ptr<QImage> image( createImage( mContext.
mapSize() ) );
289 configureMapSettings( image.get(), mapSettings );
296 runHitTest( mapSettings,
symbols );
304 std::unique_ptr<QgsWmsRestorer> restorer;
309 if ( templateName.isEmpty() )
330 if ( sourceLayout->pageCollection()->pageCount() < 1 )
333 QStringLiteral(
"The template has no pages" ) );
336 std::unique_ptr<QgsPrintLayout> layout( sourceLayout->clone() );
340 QStringList atlasPk = mWmsParameters.
atlasPk();
341 if ( !atlasPk.isEmpty() )
343 atlas = layout->atlas();
344 if ( !atlas || !atlas->
enabled() )
348 QStringLiteral(
"The template has no atlas enabled" ) );
355 QStringLiteral(
"The atlas has no coverage layer" ) );
359 if ( atlasPk.size() == 1 && atlasPk.at( 0 ) == QLatin1String(
"*" ) )
363 if ( atlas->
count() > maxAtlasFeatures )
366 QString(
"The project configuration allows printing maximum %1 atlas features at a time" ).arg( maxAtlasFeatures ) );
372 if ( pkIndexes.size() == 0 )
374 QgsDebugMsgLevel( QStringLiteral(
"Atlas print: layer %1 has no primary key attributes" ).arg( cLayer->
name() ), 2 );
378 const int pkIndexesSize {std::max( pkIndexes.size(), 1 )};
380 QStringList pkAttributeNames;
381 for (
int pkIndex : std::as_const( pkIndexes ) )
383 pkAttributeNames.append( cLayer->
fields().
at( pkIndex ).
name() );
386 const int nAtlasFeatures = atlasPk.size() / pkIndexesSize;
387 if ( nAtlasFeatures * pkIndexesSize != atlasPk.size() )
390 QStringLiteral(
"Wrong number of ATLAS_PK parameters" ) );
394 if ( nAtlasFeatures > maxAtlasFeatures )
397 QString(
"%1 atlas features have been requested, but the project configuration only allows printing %2 atlas features at a time" )
398 .arg( nAtlasFeatures ).arg( maxAtlasFeatures ) );
401 QString filterString;
402 int currentAtlasPk = 0;
404 for (
int i = 0; i < nAtlasFeatures; ++i )
408 filterString.append(
" OR " );
411 filterString.append(
"( " );
414 if ( pkAttributeNames.isEmpty() )
416 filterString.append( QStringLiteral(
"$id = %1" ).arg( atlasPk.at( currentAtlasPk ) ) );
421 for (
int j = 0; j < pkIndexes.size(); ++j )
425 filterString.append(
" AND " );
432 filterString.append(
" )" );
438 if ( !errorString.isEmpty() )
440 throw QgsException( QStringLiteral(
"An error occurred during the Atlas print: %1" ).arg( errorString ) );
452 std::unique_ptr<QImage> image(
new QImage() );
453 configureMapSettings( image.get(), mapSettings );
459 configurePrintLayout( layout.get(), mapSettings, atlas );
463 const QList<QgsMapLayer *> lyrs = mapSettings.
layers();
465 #ifdef HAVE_SERVER_PYTHON_PLUGINS
466 mContext.accessControl()->resolveFilterFeatures( lyrs );
470 QHash<const QgsVectorLayer *, QStringList> fltrs;
475 fltrs.insert( vl, dimensionFilter( vl ) );
487 QTemporaryFile tempOutputFile( QDir::tempPath() +
'/' + QStringLiteral(
"XXXXXX.%1" ).arg( extension ) );
488 if ( !tempOutputFile.open() )
490 throw QgsException( QStringLiteral(
"Could not open temporary file for the GetPrint request." ) );
499 if ( !mWmsParameters.
dpi().isEmpty() )
502 double dpi( mWmsParameters.
dpi().toDouble( &ok ) );
504 exportSettings.
dpi = dpi;
515 atlasSvgExport.exportToSvg( tempOutputFile.fileName(), exportSettings );
521 exporter.exportToSvg( tempOutputFile.fileName(), exportSettings );
530 double dpi( layout->renderContext().dpi( ) );
531 if ( !mWmsParameters.
dpi().isEmpty() )
534 double _dpi = mWmsParameters.
dpi().toDouble( &ok );
538 exportSettings.
dpi = dpi;
542 QgsLayoutSize layoutSize( layout->pageCollection()->page( 0 )->sizeWithUnits() );
544 QgsLayoutMeasurement width( layout->convertFromLayoutUnits( layoutSize.width(), QgsUnitTypes::LayoutUnit::LayoutMillimeters ) );
545 QgsLayoutMeasurement height( layout->convertFromLayoutUnits( layoutSize.height(), QgsUnitTypes::LayoutUnit::LayoutMillimeters ) );
547 const QSize imageSize = QSize(
static_cast<int>( width.length() * dpi / 25.4 ),
static_cast<int>( height.length() * dpi / 25.4 ) );
549 const QString paramWidth = mWmsParameters.
width();
550 const QString paramHeight = mWmsParameters.
height();
555 if ( !paramWidth.isEmpty() && !paramHeight.isEmpty() )
557 exportSettings.
imageSize = QSize( paramWidth.toInt(), paramHeight.toInt() );
559 else if ( !paramWidth.isEmpty() && paramHeight.isEmpty() )
561 exportSettings.
imageSize = QSize( paramWidth.toInt(),
static_cast<double>( paramWidth.toInt() ) / imageSize.width() * imageSize.height() );
563 else if ( paramWidth.isEmpty() && !paramHeight.isEmpty() )
565 exportSettings.
imageSize = QSize(
static_cast<double>( paramHeight.toInt() ) / imageSize.height() * imageSize.width(), paramHeight.toInt() );
573 exportSettings.
pages.append( 0 );
581 atlasPngExport.exportToImage( tempOutputFile.fileName(), exportSettings );
585 throw QgsServiceException( QStringLiteral(
"Bad request" ), QStringLiteral(
"Atlas error: empty atlas." ), QString(), 400 );
591 exporter.exportToImage( tempOutputFile.fileName(), exportSettings );
599 if ( !mWmsParameters.
dpi().isEmpty() )
602 double dpi( mWmsParameters.
dpi().toDouble( &ok ) );
604 exportSettings.
dpi = dpi;
609 exportSettings.
rasterizeWholeImage = layout->customProperty( QStringLiteral(
"rasterize" ),
false ).toBool();
619 exporter.exportToPdf( tempOutputFile.fileName(), exportSettings );
630 handlePrintErrors( atlas->
layout() );
634 handlePrintErrors( layout.get() );
637 return tempOutputFile.readAll();
645 QList<QgsLayoutItemMap *> maps;
651 for (
const auto &map : std::as_const( maps ) )
657 if ( cMapParams.mLayers.isEmpty() )
662 if ( !atlasPrint || !map->atlasDriven() )
665 if ( !cMapParams.mHasExtent )
668 c->removeLayoutItem( map );
686 if ( cMapParams.mScale > 0 )
688 map->setScale(
static_cast<double>( cMapParams.mScale ) );
692 if ( cMapParams.mRotation )
694 map->setMapRotation( cMapParams.mRotation );
698 if ( !map->keepLayerSet() )
700 QList<QgsMapLayer *> layerSet;
702 for (
const auto &layer : std::as_const( cMapParams.mLayers ) )
706 QList<QgsMapLayer *> layersFromGroup;
708 const QList<QgsMapLayer *> cLayersFromGroup = mContext.
layersFromGroup( layer.mNickname );
709 for (
QgsMapLayer *layerFromGroup : cLayersFromGroup )
712 if ( ! layerFromGroup )
717 layersFromGroup.push_front( layerFromGroup );
720 if ( !layersFromGroup.isEmpty() )
722 layerSet.append( layersFromGroup );
734 setLayerStyle( mlayer, layer.mStyle );
739 std::reverse( layerSet.begin(), layerSet.end() );
744 QMap<QString, QString> layersStyle;
745 if ( map->followVisibilityPreset() )
747 const QString presetName = map->followVisibilityPresetName();
748 if ( layerSet.isEmpty() )
752 layerSet = map->layersToRender( &ex );
755 map->setFollowVisibilityPreset(
false );
759 for (
const auto &layerMapThemeRecord : std::as_const( mapThemeRecords ) )
761 if ( layerSet.contains( layerMapThemeRecord.layer() ) )
763 layersStyle.insert( layerMapThemeRecord.layer()->id(),
764 layerMapThemeRecord.layer()->styleManager()->style( layerMapThemeRecord.currentStyle ).xmlData() );
770 const QList< QgsMapLayer *> highlights = highlightLayers( cMapParams.mHighlightLayers );
771 for (
const auto &hl : std::as_const( highlights ) )
773 layerSet.prepend( hl );
776 map->setLayers( layerSet );
777 map->setKeepLayerSet(
true );
781 if ( !layersStyle.isEmpty() )
783 map->setLayerStyleOverrides( layersStyle );
784 map->setKeepLayerStyles(
true );
789 if ( cMapParams.mGridX > 0 && cMapParams.mGridY > 0 )
791 map->grid()->setIntervalX(
static_cast<double>( cMapParams.mGridX ) );
792 map->grid()->setIntervalY(
static_cast<double>( cMapParams.mGridY ) );
797 QList<QgsLayoutItemLabel *> labels;
799 for (
const auto &label : std::as_const( labels ) )
802 const QString labelId = label->
id();
803 const QString labelParam = mWmsParameters.
layoutParameter( labelId, ok );
808 if ( labelParam.isEmpty() )
812 c->removeItem( label );
817 label->setText( labelParam );
821 QList<QgsLayoutItemHtml *> htmls;
823 for (
const auto &html : std::as_const( htmls ) )
825 if ( html->frameCount() == 0 )
830 const QString htmlId = htmlFrame->
id();
843 c->removeMultiFrame( html );
849 html->setUrl( newUrl );
855 QList<QgsLayoutItemLegend *> legends;
857 for (
const auto &legend : std::as_const( legends ) )
859 if ( legend->autoUpdateModel() )
869 legend->setAutoUpdateModel(
false );
873 QStringList layerSet;
874 QList<QgsMapLayer *> mapLayers;
875 if ( map->
layers().isEmpty() )
879 mapLayers = mProject->
mapLayers(
true ).values();
883 mapLayers = map->
layers();
885 const QList<QgsMapLayer *> layerList = mapLayers;
886 for (
const auto &layer : layerList )
887 layerSet << layer->id();
899 for (
const auto &layerId : layerIds )
906 if ( !layerSet.contains( layerId ) )
908 qobject_cast<QgsLayerTreeGroup *>( nodeLayer->
parent() )->removeChildNode( nodeLayer );
915 qobject_cast<QgsLayerTreeGroup *>( nodeLayer->
parent() )->removeChildNode( nodeLayer );
931 QStringLiteral(
"The requested map size is too large" ) );
935 std::unique_ptr<QgsWmsRestorer> restorer;
936 restorer.reset(
new QgsWmsRestorer( mContext ) );
946 std::unique_ptr<QPainter> painter;
947 std::unique_ptr<QImage> image( createImage( mContext.
mapSize() ) );
950 configureMapSettings( image.get(), mapSettings );
956 painter.reset( layersRendering( mapSettings, *image ) );
959 annotationsRendering( painter.get(), mapSettings );
965 QImage *scaledImage = scaleImage( image.get() );
967 image.reset( scaledImage );
970 return image.release();
976 std::unique_ptr<QgsWmsRestorer> restorer;
985 QList< QgsDxfExport::DxfLayer > dxfLayers;
997 int layerAttribute = -1;
998 if ( attributes.size() > layerIdx )
1009 QString
crs = mWmsParameters.
crs();
1010 if (
crs.compare( QStringLiteral(
"CRS:84" ), Qt::CaseInsensitive ) == 0 )
1012 crs = QStringLiteral(
"EPSG:4326" );
1015 else if (
crs.isEmpty() )
1017 crs = QStringLiteral(
"EPSG:4326" );
1025 QgsWmsParameter parameter;
1051 std::unique_ptr<QgsDxfExport> dxf = std::make_unique<QgsDxfExport>();
1052 dxf->setExtent( mapExtent );
1053 dxf->setDestinationCrs( outputCRS );
1054 dxf->addLayers( dxfLayers );
1056 dxf->setSymbologyExport( mWmsParameters.
dxfMode() );
1057 if ( mWmsParameters.
dxfFormatOptions().contains( QgsWmsParameters::DxfFormatOption::SCALE ) )
1059 dxf->setSymbologyScale( mWmsParameters.
dxfScale() );
1062 dxf->setForce2d( mWmsParameters.
isForce2D() );
1063 QgsDxfExport::Flags flags;
1064 if ( mWmsParameters.
noMText() )
1065 flags.setFlag( QgsDxfExport::Flag::FlagNoMText );
1067 dxf->setFlags( flags );
1075 if ( i < 0 || i > mapSettings.
outputSize().width() )
1083 if ( j < 0 || j > mapSettings.
outputSize().height() )
1108 const bool ijDefined = !mWmsParameters.
i().isEmpty() && !mWmsParameters.
j().isEmpty();
1109 const bool xyDefined = !mWmsParameters.
x().isEmpty() && !mWmsParameters.
y().isEmpty();
1110 const bool filtersDefined = !mWmsParameters.
filters().isEmpty();
1111 const bool filterGeomDefined = !mWmsParameters.
filterGeom().isEmpty();
1113 if ( !ijDefined && !xyDefined && !filtersDefined && !filterGeomDefined )
1117 if ( mWmsParameters.
j().isEmpty() )
1124 if ( infoFormat == QgsWmsParameters::Format::NONE )
1131 std::unique_ptr<QImage> outputImage( createImage( mContext.
mapSize() ) );
1134 std::unique_ptr<QgsWmsRestorer> restorer;
1135 restorer.reset(
new QgsWmsRestorer( mContext ) );
1139 bool mandatoryCrsParam =
true;
1140 if ( filtersDefined && !ijDefined && !xyDefined && mWmsParameters.
crs().isEmpty() )
1142 mandatoryCrsParam =
false;
1148 configureMapSettings( outputImage.get(), mapSettings, mandatoryCrsParam );
1152 const double scaleDenominator = scaleCalc.calculate( mWmsParameters.
bboxAsRectangle(), outputImage->
width() );
1155 QgsWmsRenderContext context = mContext;
1158 QList<QgsMapLayer *> layers = context.layersToRender();
1164 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1165 mContext.accessControl()->resolveFilterFeatures( mapSettings.
layers() );
1168 QDomDocument result = featureInfoDocument( layers, mapSettings, outputImage.get(), version );
1172 if ( infoFormat == QgsWmsParameters::Format::TEXT )
1173 ba = convertFeatureInfoToText( result );
1174 else if ( infoFormat == QgsWmsParameters::Format::HTML )
1175 ba = convertFeatureInfoToHtml( result );
1176 else if ( infoFormat == QgsWmsParameters::Format::JSON )
1177 ba = convertFeatureInfoToJson( layers, result );
1179 ba = result.toByteArray();
1184 QImage *QgsRenderer::createImage(
const QSize &size )
const
1186 std::unique_ptr<QImage> image;
1194 image = std::make_unique<QImage>( size, QImage::Format_ARGB32_Premultiplied );
1199 image = std::make_unique<QImage>( size, QImage::Format_RGB32 );
1204 if ( image->isNull() )
1206 throw QgsException( QStringLiteral(
"createImage: image could not be created, check for out of memory conditions" ) );
1209 const int dpm =
static_cast<int>( mContext.
dotsPerMm() * 1000.0 );
1210 image->setDotsPerMeterX( dpm );
1211 image->setDotsPerMeterY( dpm );
1213 return image.release();
1216 void QgsRenderer::configureMapSettings(
const QPaintDevice *paintDevice,
QgsMapSettings &mapSettings,
bool mandatoryCrsParam )
1220 throw QgsException( QStringLiteral(
"configureMapSettings: no paint device" ) );
1223 mapSettings.
setOutputSize( QSize( paintDevice->width(), paintDevice->height() ) );
1230 if ( !mWmsParameters.
bbox().isEmpty() && mapExtent.
isEmpty() )
1236 QString
crs = mWmsParameters.
crs();
1237 if (
crs.compare(
"CRS:84", Qt::CaseInsensitive ) == 0 )
1239 crs = QString(
"EPSG:4326" );
1242 else if (
crs.isEmpty() && !mandatoryCrsParam )
1244 crs = QString(
"EPSG:4326" );
1254 QgsWmsParameter parameter;
1296 else if ( backgroundColor.isValid() )
1319 const QString timeString { mWmsParameters.
dimensionValues().value( QStringLiteral(
"TIME" ), QString() ) };
1320 if ( ! timeString.isEmpty() )
1322 bool isValidTemporalRange {
true };
1323 QgsDateTimeRange range;
1325 const QDateTime dt { QDateTime::fromString( timeString, Qt::DateFormat::ISODateWithMs ) };
1328 range = QgsDateTimeRange( dt, dt );
1338 isValidTemporalRange =
false;
1339 QgsMessageLog::logMessage( QStringLiteral(
"Could not parse TIME parameter into a temporal range" ),
"Server", Qgis::MessageLevel::Warning );
1343 if ( isValidTemporalRange )
1353 QDomDocument QgsRenderer::featureInfoDocument( QList<QgsMapLayer *> &layers,
const QgsMapSettings &mapSettings,
1354 const QImage *outputImage,
const QString &version )
const
1358 bool ijDefined = ( !mWmsParameters.
i().isEmpty() && !mWmsParameters.
j().isEmpty() );
1360 bool xyDefined = ( !mWmsParameters.
x().isEmpty() && !mWmsParameters.
y().isEmpty() );
1362 bool filtersDefined = !mWmsParameters.
filters().isEmpty();
1364 bool filterGeomDefined = !mWmsParameters.
filterGeom().isEmpty();
1367 if ( featureCount < 1 )
1372 int i = mWmsParameters.
iAsInt();
1373 int j = mWmsParameters.
jAsInt();
1374 if ( xyDefined && !ijDefined )
1376 i = mWmsParameters.
xAsInt();
1377 j = mWmsParameters.
yAsInt();
1381 if ( ( i != -1 && j != -1 && width != 0 && height != 0 ) && ( width != outputImage->width() || height != outputImage->height() ) )
1383 i *= ( outputImage->width() /
static_cast<double>( width ) );
1384 j *= ( outputImage->height() /
static_cast<double>( height ) );
1388 std::unique_ptr<QgsRectangle> featuresRect;
1389 std::unique_ptr<QgsGeometry> filterGeom;
1390 std::unique_ptr<QgsPointXY> infoPoint;
1392 if ( i != -1 && j != -1 )
1395 infoPointToMapCoordinates( i, j, infoPoint.get(), mapSettings );
1397 else if ( filtersDefined )
1401 else if ( filterGeomDefined )
1406 QDomDocument result;
1408 QDomElement getFeatureInfoElement;
1410 if ( infoFormat == QgsWmsParameters::Format::GML )
1412 getFeatureInfoElement = result.createElement( QStringLiteral(
"wfs:FeatureCollection" ) );
1413 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:wfs" ), QStringLiteral(
"http://www.opengis.net/wfs" ) );
1414 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:ogc" ), QStringLiteral(
"http://www.opengis.net/ogc" ) );
1415 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:gml" ), QStringLiteral(
"http://www.opengis.net/gml" ) );
1416 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:ows" ), QStringLiteral(
"http://www.opengis.net/ows" ) );
1417 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:xlink" ), QStringLiteral(
"http://www.w3.org/1999/xlink" ) );
1418 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:qgs" ), QStringLiteral(
"http://qgis.org/gml" ) );
1419 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:xsi" ), QStringLiteral(
"http://www.w3.org/2001/XMLSchema-instance" ) );
1420 getFeatureInfoElement.setAttribute( QStringLiteral(
"xsi:schemaLocation" ), QStringLiteral(
"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd http://qgis.org/gml" ) );
1425 if ( featureInfoElemName.isEmpty() )
1427 featureInfoElemName = QStringLiteral(
"GetFeatureInfoResponse" );
1430 if ( featureInfoElemNs.isEmpty() )
1432 getFeatureInfoElement = result.createElement( featureInfoElemName );
1436 getFeatureInfoElement = result.createElementNS( featureInfoElemNs, featureInfoElemName );
1440 if ( !featureInfoSchema.isEmpty() )
1442 getFeatureInfoElement.setAttribute( QStringLiteral(
"xmlns:xsi" ), QStringLiteral(
"http://www.w3.org/2001/XMLSchema-instance" ) );
1443 getFeatureInfoElement.setAttribute( QStringLiteral(
"xsi:schemaLocation" ), featureInfoSchema );
1446 result.appendChild( getFeatureInfoElement );
1456 for (
const QString &queryLayer : queryLayers )
1458 bool validLayer =
false;
1459 bool queryableLayer =
true;
1460 for (
QgsMapLayer *layer : std::as_const( layers ) )
1466 if ( !queryableLayer )
1471 QDomElement layerElement;
1472 if ( infoFormat == QgsWmsParameters::Format::GML )
1474 layerElement = getFeatureInfoElement;
1478 layerElement = result.createElement( QStringLiteral(
"Layer" ) );
1479 QString layerName = queryLayer;
1482 QHash<QString, QString>::const_iterator layerAliasIt = layerAliasMap.constFind( layerName );
1483 if ( layerAliasIt != layerAliasMap.constEnd() )
1485 layerName = layerAliasIt.value();
1488 layerElement.setAttribute( QStringLiteral(
"name" ), layerName );
1489 getFeatureInfoElement.appendChild( layerElement );
1492 layerElement.setAttribute( QStringLiteral(
"id" ), layer->id() );
1498 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
1501 ( void )featureInfoFromVectorLayer( vectorLayer, infoPoint.get(), featureCount, result, layerElement, mapSettings, renderContext, version, featuresRect.get(), filterGeom.get() );
1507 QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layer );
1516 QgsPointXY layerInfoPoint = mapSettings.mapToLayerCoordinates( layer, *( infoPoint.get() ) );
1521 if ( infoFormat == QgsWmsParameters::Format::GML )
1523 layerElement = result.createElement( QStringLiteral(
"gml:featureMember" ) );
1524 getFeatureInfoElement.appendChild( layerElement );
1527 ( void )featureInfoFromRasterLayer( rasterLayer, mapSettings, &layerInfoPoint, result, layerElement, version );
1535 param.mValue = queryLayer;
1539 else if ( ( validLayer && !queryableLayer ) || ( !validLayer && mContext.
isValidGroup( queryLayer ) ) )
1542 param.mValue = queryLayer;
1544 bool hasGroupAndQueryable {
false };
1549 for (
const QString &ql : constNicks )
1553 const QList<QgsMapLayer *> constLayers { mContext.
layerGroups()[ql] };
1556 if ( ( ! ml->shortName().isEmpty() && ml->shortName() == queryLayer ) || ( ml->name() == queryLayer ) )
1562 hasGroupAndQueryable =
true;
1571 if ( ! hasGroupAndQueryable )
1581 if ( infoFormat == QgsWmsParameters::Format::GML )
1583 QDomElement bBoxElem = result.createElement( QStringLiteral(
"gml:boundedBy" ) );
1584 QDomElement boxElem;
1586 if ( gmlVersion < 3 )
1598 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
1600 bBoxElem.appendChild( boxElem );
1601 getFeatureInfoElement.insertBefore( bBoxElem, QDomNode() );
1605 QDomElement bBoxElem = result.createElement( QStringLiteral(
"BoundingBox" ) );
1606 bBoxElem.setAttribute( QStringLiteral(
"CRS" ), mapSettings.destinationCrs().authid() );
1607 bBoxElem.setAttribute( QStringLiteral(
"minx" ),
qgsDoubleToString( featuresRect->xMinimum(), 8 ) );
1608 bBoxElem.setAttribute( QStringLiteral(
"maxx" ),
qgsDoubleToString( featuresRect->xMaximum(), 8 ) );
1609 bBoxElem.setAttribute( QStringLiteral(
"miny" ),
qgsDoubleToString( featuresRect->yMinimum(), 8 ) );
1610 bBoxElem.setAttribute( QStringLiteral(
"maxy" ),
qgsDoubleToString( featuresRect->yMaximum(), 8 ) );
1611 getFeatureInfoElement.insertBefore( bBoxElem, QDomNode() );
1615 if ( sia2045 && infoFormat == QgsWmsParameters::Format::XML )
1617 convertFeatureInfoToSia2045( result );
1623 bool QgsRenderer::featureInfoFromVectorLayer(
QgsVectorLayer *layer,
1626 QDomDocument &infoDocument,
1627 QDomElement &layerElement,
1630 const QString &version,
1642 std::unique_ptr<QgsGeometry> layerFilterGeom;
1645 layerFilterGeom.reset(
new QgsGeometry( *filterGeom ) );
1659 searchRect = featureInfoSearchRect( layer, mapSettings, renderContext, *infoPoint );
1661 else if ( layerFilterGeom )
1663 searchRect = layerFilterGeom->boundingBox();
1665 else if ( !mWmsParameters.
bbox().isEmpty() )
1667 searchRect = layerRect;
1674 int featureCounter = 0;
1693 if ( layerFilterGeom )
1695 fReq.
setFilterExpression( QString(
"intersects( $geometry, geom_from_wkt('%1') )" ).arg( layerFilterGeom->asWkt() ) );
1700 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1701 mContext.accessControl()->filterFeatures( layer, fReq );
1703 QStringList attributes;
1708 attributes = mContext.accessControl()->layerAttributes( layer, attributes );
1713 std::unique_ptr< QgsFeatureRenderer > r2( layer->
renderer() ? layer->
renderer()->
clone() :
nullptr );
1716 r2->startRender( renderContext, layer->
fields() );
1719 bool featureBBoxInitialized =
false;
1728 if ( featureCounter > nFeatures )
1743 bool render = r2->willRenderFeature( feature, renderContext );
1756 if ( !featureBBoxInitialized && featureBBox->
isEmpty() )
1759 featureBBoxInitialized =
true;
1774 if ( mWmsParameters.
infoFormat() == QgsWmsParameters::Format::GML )
1779 QDomElement elem = createFeatureGML(
1781 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1785 QDomElement featureMemberElem = infoDocument.createElement( QStringLiteral(
"gml:featureMember" ) );
1786 featureMemberElem.appendChild( elem );
1787 layerElement.appendChild( featureMemberElem );
1792 QDomElement featureElement = infoDocument.createElement( QStringLiteral(
"Feature" ) );
1794 layerElement.appendChild( featureElement );
1800 writeAttributesTabLayout( editConfig, layer, fields, featureAttributes, infoDocument, featureElement, renderContext
1801 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1808 for (
int i = 0; i < featureAttributes.count(); ++i )
1810 writeVectorLayerAttribute( i, layer, fields, featureAttributes, infoDocument, featureElement, renderContext
1811 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1820 if ( !mapTip.isEmpty() && mWmsParameters.
withMapTip() )
1822 QDomElement maptipElem = infoDocument.createElement( QStringLiteral(
"Attribute" ) );
1823 maptipElem.setAttribute( QStringLiteral(
"name" ), QStringLiteral(
"maptip" ) );
1825 featureElement.appendChild( maptipElem );
1832 QDomElement bBoxElem = infoDocument.createElement( QStringLiteral(
"BoundingBox" ) );
1833 bBoxElem.setAttribute( version == QLatin1String(
"1.1.1" ) ?
"SRS" :
"CRS",
outputCrs.
authid() );
1838 featureElement.appendChild( bBoxElem );
1854 if ( segmentizeWktGeometry )
1862 geom.
set( segmentizedGeom );
1866 QDomElement geometryElement = infoDocument.createElement( QStringLiteral(
"Attribute" ) );
1867 geometryElement.setAttribute( QStringLiteral(
"name" ), QStringLiteral(
"geometry" ) );
1868 geometryElement.setAttribute( QStringLiteral(
"value" ), geom.
asWkt( mContext.
precision() ) );
1869 geometryElement.setAttribute( QStringLiteral(
"type" ), QStringLiteral(
"derived" ) );
1870 featureElement.appendChild( geometryElement );
1877 r2->stopRender( renderContext );
1888 QString groupName = container->
name();
1889 QDomElement nameElem;
1891 if ( !groupName.isEmpty() )
1893 nameElem = doc.createElement( groupName );
1894 parentElem.appendChild( nameElem );
1897 const QList<QgsAttributeEditorElement *> children = container->
children();
1902 writeAttributesTabGroup( child, layer, fields, featureAttributes, doc, nameElem.isNull() ? parentElem : nameElem, renderContext );
1912 writeVectorLayerAttribute( idx, layer, fields, featureAttributes, doc, nameElem.isNull() ? parentElem : nameElem, renderContext, attributes );
1923 if ( !editorContainer )
1928 writeAttributesTabGroup( editorContainer, layer, fields, featureAttributes, doc, featureElem, renderContext, attributes );
1931 void QgsRenderer::writeVectorLayerAttribute(
int attributeIndex,
QgsVectorLayer *layer,
const QgsFields &fields,
QgsAttributes &featureAttributes, QDomDocument &doc, QDomElement &featureElem,
QgsRenderContext &renderContext, QStringList *attributes )
const
1933 #ifndef HAVE_SERVER_PYTHON_PLUGINS
1934 Q_UNUSED( attributes );
1947 #ifdef HAVE_SERVER_PYTHON_PLUGINS
1949 if ( attributes && !attributes->contains( fields.
at( attributeIndex ).
name() ) )
1956 QDomElement attributeElement = doc.createElement( QStringLiteral(
"Attribute" ) );
1957 attributeElement.setAttribute( QStringLiteral(
"name" ), attributeName );
1959 attributeElement.setAttribute( QStringLiteral(
"value" ),
1961 replaceValueMapAndRelation(
1962 layer, attributeIndex,
1963 featureAttributes[attributeIndex] ),
1966 featureElem.appendChild( attributeElement );
1969 bool QgsRenderer::featureInfoFromRasterLayer(
QgsRasterLayer *layer,
1972 QDomDocument &infoDocument,
1973 QDomElement &layerElement,
1974 const QString &version )
const
1993 ? QgsRaster::IdentifyFormat::IdentifyFormatFeature
1994 : QgsRaster::IdentifyFormat::IdentifyFormatValue );
2006 .arg( layer->
name() ) );
2015 if ( !identifyResult.
isValid() )
2018 QMap<int, QVariant> attributes = identifyResult.
results();
2020 if ( mWmsParameters.
infoFormat() == QgsWmsParameters::Format::GML )
2032 for (
auto it = attributes.constBegin(); it != attributes.constEnd(); ++it )
2035 feature.
setAttribute( index++, QString::number( it.value().toDouble() ) );
2038 QDomElement elem = createFeatureGML(
2039 &feature,
nullptr, infoDocument, layerCrs, mapSettings,
typeName,
false, gmlVersion,
nullptr );
2040 layerElement.appendChild( elem );
2044 const auto values = identifyResult.
results();
2045 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
2047 QVariant value = it.value();
2048 if ( value.type() == QVariant::Bool && !value.toBool() )
2054 if ( value.type() == QVariant::String )
2065 for (
const QgsFeature &feature : storeFeatures )
2067 QDomElement elem = createFeatureGML(
2068 &feature,
nullptr, infoDocument, layerCrs, mapSettings,
typeName,
false, gmlVersion,
nullptr );
2069 layerElement.appendChild( elem );
2079 for (
auto it = attributes.constBegin(); it != attributes.constEnd(); ++it )
2081 QDomElement attributeElement = infoDocument.createElement( QStringLiteral(
"Attribute" ) );
2082 attributeElement.setAttribute( QStringLiteral(
"name" ), layer->
bandName( it.key() ) );
2085 if ( ! it.value().isNull() )
2087 value = QString::number( it.value().toDouble() );
2090 attributeElement.setAttribute( QStringLiteral(
"value" ), value );
2091 layerElement.appendChild( attributeElement );
2096 const auto values = identifyResult.
results();
2097 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
2099 QVariant value = it.value();
2100 if ( value.type() == QVariant::Bool && !value.toBool() )
2106 if ( value.type() == QVariant::String )
2116 for (
const QgsFeature &feature : storeFeatures )
2118 for (
const auto &fld : feature.
fields() )
2120 const auto val { feature.
attribute( fld.name() )};
2121 if ( val.isValid() )
2123 QDomElement attributeElement = infoDocument.createElement( QStringLiteral(
"Attribute" ) );
2124 attributeElement.setAttribute( QStringLiteral(
"name" ), fld.name() );
2125 attributeElement.setAttribute( QStringLiteral(
"value" ), val.toString() );
2126 layerElement.appendChild( attributeElement );
2137 bool QgsRenderer::testFilterStringSafety(
const QString &filter )
const
2140 if ( filter.contains( QLatin1String(
";" ) ) )
2145 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
2146 QStringList tokens = filter.split(
' ', QString::SkipEmptyParts );
2148 QStringList tokens = filter.split(
' ', Qt::SkipEmptyParts );
2150 groupStringList( tokens, QStringLiteral(
"'" ) );
2151 groupStringList( tokens, QStringLiteral(
"\"" ) );
2153 for (
auto tokenIt = tokens.constBegin() ; tokenIt != tokens.constEnd(); ++tokenIt )
2156 if ( tokenIt->compare( QLatin1String(
"," ) ) == 0
2157 || tokenIt->compare( QLatin1String(
"(" ) ) == 0
2158 || tokenIt->compare( QLatin1String(
")" ) ) == 0
2159 || tokenIt->compare( QLatin1String(
"=" ) ) == 0
2160 || tokenIt->compare( QLatin1String(
"!=" ) ) == 0
2161 || tokenIt->compare( QLatin1String(
"<" ) ) == 0
2162 || tokenIt->compare( QLatin1String(
"<=" ) ) == 0
2163 || tokenIt->compare( QLatin1String(
">" ) ) == 0
2164 || tokenIt->compare( QLatin1String(
">=" ) ) == 0
2165 || tokenIt->compare( QLatin1String(
"%" ) ) == 0
2166 || tokenIt->compare( QLatin1String(
"IS" ), Qt::CaseInsensitive ) == 0
2167 || tokenIt->compare( QLatin1String(
"NOT" ), Qt::CaseInsensitive ) == 0
2168 || tokenIt->compare( QLatin1String(
"NULL" ), Qt::CaseInsensitive ) == 0
2169 || tokenIt->compare( QLatin1String(
"AND" ), Qt::CaseInsensitive ) == 0
2170 || tokenIt->compare( QLatin1String(
"OR" ), Qt::CaseInsensitive ) == 0
2171 || tokenIt->compare( QLatin1String(
"IN" ), Qt::CaseInsensitive ) == 0
2172 || tokenIt->compare( QLatin1String(
"LIKE" ), Qt::CaseInsensitive ) == 0
2173 || tokenIt->compare( QLatin1String(
"ILIKE" ), Qt::CaseInsensitive ) == 0
2174 || tokenIt->compare( QLatin1String(
"DMETAPHONE" ), Qt::CaseInsensitive ) == 0
2175 || tokenIt->compare( QLatin1String(
"SOUNDEX" ), Qt::CaseInsensitive ) == 0 )
2182 tokenIt->toDouble( &isNumeric );
2191 if ( *tokenIt == QLatin1String(
"''" ) )
2197 if ( tokenIt->size() > 2
2198 && ( *tokenIt )[0] == QChar(
'\'' )
2199 && ( *tokenIt )[tokenIt->size() - 1] == QChar(
'\'' )
2200 && ( *tokenIt )[1] != QChar(
'\'' )
2201 && ( *tokenIt )[tokenIt->size() - 2] != QChar(
'\'' ) )
2207 if ( tokenIt->size() > 2
2208 && ( *tokenIt )[0] == QChar(
'"' )
2209 && ( *tokenIt )[tokenIt->size() - 1] == QChar(
'"' )
2210 && ( *tokenIt )[1] != QChar(
'"' )
2211 && ( *tokenIt )[tokenIt->size() - 2] != QChar(
'"' ) )
2222 void QgsRenderer::groupStringList( QStringList &list,
const QString &groupString )
2225 bool groupActive =
false;
2226 int startGroup = -1;
2227 QString concatString;
2229 for (
int i = 0; i < list.size(); ++i )
2231 QString &
str = list[i];
2232 if (
str.startsWith( groupString ) )
2236 concatString.clear();
2241 if ( i != startGroup )
2243 concatString.append(
" " );
2245 concatString.append(
str );
2248 if (
str.endsWith( groupString ) )
2251 groupActive =
false;
2253 if ( startGroup != -1 )
2255 list[startGroup] = concatString;
2256 for (
int j = startGroup + 1; j <= endGroup; ++j )
2258 list.removeAt( startGroup + 1 );
2263 concatString.clear();
2269 void QgsRenderer::convertFeatureInfoToSia2045( QDomDocument &doc )
const
2271 QDomDocument SIAInfoDoc;
2272 QDomElement infoDocElement = doc.documentElement();
2273 QDomElement SIAInfoDocElement = SIAInfoDoc.importNode( infoDocElement,
false ).toElement();
2274 SIAInfoDoc.appendChild( SIAInfoDocElement );
2276 QString currentAttributeName;
2277 QString currentAttributeValue;
2278 QDomElement currentAttributeElem;
2279 QString currentLayerName;
2280 QDomElement currentLayerElem;
2281 QDomNodeList layerNodeList = infoDocElement.elementsByTagName( QStringLiteral(
"Layer" ) );
2282 for (
int i = 0; i < layerNodeList.size(); ++i )
2284 currentLayerElem = layerNodeList.at( i ).toElement();
2285 currentLayerName = currentLayerElem.attribute( QStringLiteral(
"name" ) );
2287 QDomElement currentFeatureElem;
2289 QDomNodeList featureList = currentLayerElem.elementsByTagName( QStringLiteral(
"Feature" ) );
2290 if ( featureList.isEmpty() )
2293 QDomNodeList attributeList = currentLayerElem.elementsByTagName( QStringLiteral(
"Attribute" ) );
2294 QDomElement rasterLayerElem;
2295 if ( !attributeList.isEmpty() )
2297 rasterLayerElem = SIAInfoDoc.createElement( currentLayerName );
2299 for (
int j = 0; j < attributeList.size(); ++j )
2301 currentAttributeElem = attributeList.at( j ).toElement();
2302 currentAttributeName = currentAttributeElem.attribute( QStringLiteral(
"name" ) );
2303 currentAttributeValue = currentAttributeElem.attribute( QStringLiteral(
"value" ) );
2304 QDomElement outAttributeElem = SIAInfoDoc.createElement( currentAttributeName );
2305 QDomText outAttributeText = SIAInfoDoc.createTextNode( currentAttributeValue );
2306 outAttributeElem.appendChild( outAttributeText );
2307 rasterLayerElem.appendChild( outAttributeElem );
2309 if ( !attributeList.isEmpty() )
2311 SIAInfoDocElement.appendChild( rasterLayerElem );
2317 QSet<QString> layerPropertyAttributes;
2318 QString currentLayerId = currentLayerElem.attribute( QStringLiteral(
"id" ) );
2319 if ( !currentLayerId.isEmpty() )
2324 QString WMSPropertyAttributesString = currentLayer->
customProperty( QStringLiteral(
"WMSPropertyAttributes" ) ).toString();
2325 if ( !WMSPropertyAttributesString.isEmpty() )
2327 QStringList propertyList = WMSPropertyAttributesString.split( QStringLiteral(
"//" ) );
2328 for (
auto propertyIt = propertyList.constBegin() ; propertyIt != propertyList.constEnd(); ++propertyIt )
2330 layerPropertyAttributes.insert( *propertyIt );
2336 QDomElement propertyRefChild;
2337 for (
int j = 0; j < featureList.size(); ++j )
2339 QDomElement SIAFeatureElem = SIAInfoDoc.createElement( currentLayerName );
2340 currentFeatureElem = featureList.at( j ).toElement();
2341 QDomNodeList attributeList = currentFeatureElem.elementsByTagName( QStringLiteral(
"Attribute" ) );
2343 for (
int k = 0; k < attributeList.size(); ++k )
2345 currentAttributeElem = attributeList.at( k ).toElement();
2346 currentAttributeName = currentAttributeElem.attribute( QStringLiteral(
"name" ) );
2347 currentAttributeValue = currentAttributeElem.attribute( QStringLiteral(
"value" ) );
2348 if ( layerPropertyAttributes.contains( currentAttributeName ) )
2350 QDomElement propertyElem = SIAInfoDoc.createElement( QStringLiteral(
"property" ) );
2351 QDomElement identifierElem = SIAInfoDoc.createElement( QStringLiteral(
"identifier" ) );
2352 QDomText identifierText = SIAInfoDoc.createTextNode( currentAttributeName );
2353 identifierElem.appendChild( identifierText );
2354 QDomElement valueElem = SIAInfoDoc.createElement( QStringLiteral(
"value" ) );
2355 QDomText valueText = SIAInfoDoc.createTextNode( currentAttributeValue );
2356 valueElem.appendChild( valueText );
2357 propertyElem.appendChild( identifierElem );
2358 propertyElem.appendChild( valueElem );
2359 if ( propertyRefChild.isNull() )
2361 SIAFeatureElem.insertBefore( propertyElem, QDomNode() );
2362 propertyRefChild = propertyElem;
2366 SIAFeatureElem.insertAfter( propertyElem, propertyRefChild );
2371 QDomElement SIAAttributeElem = SIAInfoDoc.createElement( currentAttributeName );
2372 QDomText SIAAttributeText = SIAInfoDoc.createTextNode( currentAttributeValue );
2373 SIAAttributeElem.appendChild( SIAAttributeText );
2374 SIAFeatureElem.appendChild( SIAAttributeElem );
2377 SIAInfoDocElement.appendChild( SIAFeatureElem );
2384 QByteArray QgsRenderer::convertFeatureInfoToHtml(
const QDomDocument &doc )
const
2386 QString featureInfoString;
2389 featureInfoString.append(
"<HEAD>\n" );
2390 featureInfoString.append(
"<TITLE> GetFeatureInfo results </TITLE>\n" );
2391 featureInfoString.append(
"<META http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\"/>\n" );
2392 featureInfoString.append(
"</HEAD>\n" );
2395 featureInfoString.append(
"<BODY>\n" );
2397 QDomNodeList layerList = doc.elementsByTagName( QStringLiteral(
"Layer" ) );
2400 for (
int i = 0; i < layerList.size(); ++i )
2402 QDomElement layerElem = layerList.at( i ).toElement();
2404 featureInfoString.append(
"<TABLE border=1 width=100%>\n" );
2405 featureInfoString.append(
"<TR><TH width=25%>Layer</TH><TD>" + layerElem.attribute( QStringLiteral(
"name" ) ) +
"</TD></TR>\n" );
2406 featureInfoString.append(
"</BR>" );
2409 QDomNodeList featureNodeList = layerElem.elementsByTagName( QStringLiteral(
"Feature" ) );
2410 QDomElement currentFeatureElement;
2412 if ( !featureNodeList.isEmpty() )
2414 for (
int j = 0; j < featureNodeList.size(); ++j )
2416 QDomElement featureElement = featureNodeList.at( j ).toElement();
2417 featureInfoString.append(
"<TABLE border=1 width=100%>\n" );
2418 featureInfoString.append(
"<TR><TH>Feature</TH><TD>" + featureElement.attribute( QStringLiteral(
"id" ) ) +
2422 QDomNodeList attributeNodeList = featureElement.elementsByTagName( QStringLiteral(
"Attribute" ) );
2423 for (
int k = 0; k < attributeNodeList.size(); ++k )
2425 QDomElement attributeElement = attributeNodeList.at( k ).toElement();
2426 featureInfoString.append(
"<TR><TH>" + attributeElement.attribute( QStringLiteral(
"name" ) ) +
2427 "</TH><TD>" + attributeElement.attribute( QStringLiteral(
"value" ) ) +
"</TD></TR>\n" );
2430 featureInfoString.append(
"</TABLE>\n</BR>\n" );
2435 QDomNodeList attributeNodeList = layerElem.elementsByTagName( QStringLiteral(
"Attribute" ) );
2436 for (
int j = 0; j < attributeNodeList.size(); ++j )
2438 QDomElement attributeElement = attributeNodeList.at( j ).toElement();
2439 QString value = attributeElement.attribute( QStringLiteral(
"value" ) );
2440 if ( value.isEmpty() )
2442 value = QStringLiteral(
"no data" );
2444 featureInfoString.append(
"<TR><TH>" + attributeElement.attribute( QStringLiteral(
"name" ) ) +
2445 "</TH><TD>" + value +
"</TD></TR>\n" );
2449 featureInfoString.append(
"</TABLE>\n<BR></BR>\n" );
2453 featureInfoString.append(
"</BODY>\n" );
2455 return featureInfoString.toUtf8();
2458 QByteArray QgsRenderer::convertFeatureInfoToText(
const QDomDocument &doc )
const
2460 QString featureInfoString;
2463 featureInfoString.append(
"GetFeatureInfo results\n" );
2464 featureInfoString.append(
"\n" );
2466 QDomNodeList layerList = doc.elementsByTagName( QStringLiteral(
"Layer" ) );
2469 for (
int i = 0; i < layerList.size(); ++i )
2471 QDomElement layerElem = layerList.at( i ).toElement();
2473 featureInfoString.append(
"Layer '" + layerElem.attribute( QStringLiteral(
"name" ) ) +
"'\n" );
2476 QDomNodeList featureNodeList = layerElem.elementsByTagName( QStringLiteral(
"Feature" ) );
2477 QDomElement currentFeatureElement;
2479 if ( !featureNodeList.isEmpty() )
2481 for (
int j = 0; j < featureNodeList.size(); ++j )
2483 QDomElement featureElement = featureNodeList.at( j ).toElement();
2484 featureInfoString.append(
"Feature " + featureElement.attribute( QStringLiteral(
"id" ) ) +
"\n" );
2487 QDomNodeList attributeNodeList = featureElement.elementsByTagName( QStringLiteral(
"Attribute" ) );
2488 for (
int k = 0; k < attributeNodeList.size(); ++k )
2490 QDomElement attributeElement = attributeNodeList.at( k ).toElement();
2491 featureInfoString.append( attributeElement.attribute( QStringLiteral(
"name" ) ) +
" = '" +
2492 attributeElement.attribute( QStringLiteral(
"value" ) ) +
"'\n" );
2498 QDomNodeList attributeNodeList = layerElem.elementsByTagName( QStringLiteral(
"Attribute" ) );
2499 for (
int j = 0; j < attributeNodeList.size(); ++j )
2501 QDomElement attributeElement = attributeNodeList.at( j ).toElement();
2502 QString value = attributeElement.attribute( QStringLiteral(
"value" ) );
2503 if ( value.isEmpty() )
2505 value = QStringLiteral(
"no data" );
2507 featureInfoString.append( attributeElement.attribute( QStringLiteral(
"name" ) ) +
" = '" +
2512 featureInfoString.append(
"\n" );
2515 return featureInfoString.toUtf8();
2518 QByteArray QgsRenderer::convertFeatureInfoToJson(
const QList<QgsMapLayer *> &layers,
const QDomDocument &doc )
const
2522 {
"type",
"FeatureCollection" },
2523 {
"features", json::array() },
2527 const QDomNodeList layerList = doc.elementsByTagName( QStringLiteral(
"Layer" ) );
2528 for (
int i = 0; i < layerList.size(); ++i )
2530 const QDomElement layerElem = layerList.at( i ).toElement();
2531 const QString layerName = layerElem.attribute( QStringLiteral(
"name" ) );
2536 if ( mContext.
layerNickname( *l ).compare( layerName ) == 0 )
2552 const QDomNodeList featuresNode = layerElem.elementsByTagName( QStringLiteral(
"Feature" ) );
2553 if ( featuresNode.isEmpty() )
2556 QMap<QgsFeatureId, QString> fidMap;
2558 for (
int j = 0; j < featuresNode.size(); ++j )
2560 const QDomElement featureNode = featuresNode.at( j ).toElement();
2561 const QString fid = featureNode.attribute( QStringLiteral(
"id" ) );
2564 if ( expression.isEmpty() )
2566 feature = vl->
getFeature( fid.toLongLong() );
2571 request.setFlags( QgsFeatureRequest::Flag::NoGeometry );
2575 fidMap.insert( feature.
id(), fid );
2580 const QDomNodeList attrs = featureNode.elementsByTagName(
"Attribute" );
2581 for (
int k = 0; k < attrs.count(); k++ )
2583 const QDomElement elm = attrs.at( k ).toElement();
2584 if ( elm.attribute( QStringLiteral(
"name" ) ).compare(
"geometry" ) == 0 )
2586 wkt = elm.attribute(
"value" );
2591 if ( ! wkt.isEmpty() )
2597 features << feature;
2600 if ( !attributes.isEmpty() )
2603 const QDomNodeList attributesNode = featureNode.elementsByTagName( QStringLiteral(
"Attribute" ) );
2604 for (
int k = 0; k < attributesNode.size(); ++k )
2606 const QDomElement attributeElement = attributesNode.at( k ).toElement();
2607 const QString fieldName = attributeElement.
attribute( QStringLiteral(
"name" ) );
2609 attributes << feature.fieldNameIndex( fieldName );
2615 exporter.setAttributeDisplayName(
true );
2616 exporter.setAttributes( attributes );
2617 exporter.setIncludeGeometry( withGeometry );
2618 exporter.setTransformGeometries(
false );
2620 for (
const auto &feature : std::as_const( features ) )
2622 const QString
id = QStringLiteral(
"%1.%2" ).arg( layerName ).arg( fidMap.value( feature.id() ) );
2623 json[
"features"].push_back( exporter.exportFeatureToJsonObject( feature, QVariantMap(),
id ) );
2628 auto properties = json::object();
2629 const QDomNodeList attributesNode = layerElem.elementsByTagName( QStringLiteral(
"Attribute" ) );
2630 for (
int j = 0; j < attributesNode.size(); ++j )
2632 const QDomElement attrElmt = attributesNode.at( j ).toElement();
2633 const QString name = attrElmt.attribute( QStringLiteral(
"name" ) );
2635 QString value = attrElmt.attribute( QStringLiteral(
"value" ) );
2636 if ( value.isEmpty() )
2638 value = QStringLiteral(
"null" );
2641 properties[name.toStdString()] = value.toStdString();
2644 json[
"features"].push_back(
2646 {
"type",
"Feature" },
2647 {
"id", layerName.toStdString() },
2648 {
"properties", properties }
2654 return QByteArray::fromStdString( json.dump( 2 ) );
2656 return QByteArray::fromStdString( json.dump() );
2660 QDomElement QgsRenderer::createFeatureGML(
2669 QStringList *attributes )
const
2672 QDomElement typeNameElement = doc.createElement(
"qgs:" +
typeName );
2679 typeNameElement.setAttribute( QStringLiteral(
"fid" ), QStringLiteral(
"%1.%2" ).arg(
typeName, fid ) );
2682 if ( layer && layer->
crs() !=
crs )
2715 QDomElement bbElem = doc.createElement( QStringLiteral(
"gml:boundedBy" ) );
2716 QDomElement boxElem;
2728 boxElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
2730 bbElem.appendChild( boxElem );
2731 typeNameElement.appendChild( bbElem );
2743 QDomElement geomElem = doc.createElement( QStringLiteral(
"qgs:geometry" ) );
2744 QDomElement gmlElem;
2754 if ( !gmlElem.isNull() )
2758 gmlElem.setAttribute( QStringLiteral(
"srsName" ),
crs.
authid() );
2760 geomElem.appendChild( gmlElem );
2761 typeNameElement.appendChild( geomElem );
2768 for (
int i = 0; i < fields.
count(); ++i )
2770 QString attributeName = fields.
at( i ).
name();
2777 if ( attributes && !attributes->contains( attributeName ) )
2782 QDomElement fieldElem = doc.createElement(
"qgs:" + attributeName.replace(
' ',
'_' ) );
2783 QString fieldTextString = featureAttributes.at( i ).toString();
2788 QDomText fieldText = doc.createTextNode( fieldTextString );
2789 fieldElem.appendChild( fieldText );
2790 typeNameElement.appendChild( fieldElem );
2798 if ( !mapTip.isEmpty() && mWmsParameters.
withMapTip() )
2801 QDomElement fieldElem = doc.createElement( QStringLiteral(
"qgs:maptip" ) );
2802 QDomText maptipText = doc.createTextNode( fieldTextString );
2803 fieldElem.appendChild( maptipText );
2804 typeNameElement.appendChild( fieldElem );
2808 return typeNameElement;
2811 QString QgsRenderer::replaceValueMapAndRelation(
QgsVectorLayer *vl,
int idx,
const QVariant &attributeVal )
2815 QString value( fieldFormatter->
representValue( vl, idx, setup.
config(), QVariant(), attributeVal ) );
2817 if ( setup.
config().value( QStringLiteral(
"AllowMulti" ) ).toBool() && value.startsWith( QLatin1Char(
'{' ) ) && value.endsWith( QLatin1Char(
'}' ) ) )
2819 value = value.mid( 1, value.size() - 2 );
2831 double mapUnitTolerance = 0.0;
2841 mapUnitTolerance = mapSettings.
extent().
width() / 400.0;
2853 mapUnitTolerance = mapSettings.
extent().
width() / 200.0;
2865 mapUnitTolerance = mapSettings.
extent().
width() / 100.0;
2869 QgsRectangle mapRectangle( infoPoint.
x() - mapUnitTolerance, infoPoint.
y() - mapUnitTolerance,
2870 infoPoint.
x() + mapUnitTolerance, infoPoint.
y() + mapUnitTolerance );
2874 QList<QgsMapLayer *> QgsRenderer::highlightLayers( QList<QgsWmsParametersHighlightLayer> params )
2876 QList<QgsMapLayer *> highlightLayers;
2879 QString
crs = mWmsParameters.
crs();
2880 for (
const QgsWmsParametersHighlightLayer ¶m : params )
2883 QDomDocument sldDoc;
2887 if ( !sldDoc.setContent( param.mSld,
true, &errorMsg, &errorLine, &errorColumn ) )
2894 QStringLiteral(
"Server" ), Qgis::MessageLevel::Warning );
2899 std::unique_ptr<QgsFeatureRenderer> renderer;
2900 QDomElement el = sldDoc.documentElement();
2911 if ( ! param.mLabel.isEmpty() )
2913 url +=
"&field=label:string";
2918 std::unique_ptr<QgsVectorLayer> layer = std::make_unique<QgsVectorLayer>( url, param.mName, QLatin1String(
"memory" ), options );
2919 if ( !layer->isValid() )
2926 if ( ! param.mLabel.isEmpty() )
2928 fet.setAttribute( 0, param.mLabel );
2936 palSettings.
dist = param.mLabelDistance;
2945 switch ( param.mGeom.type() )
2958 QVariant x( pt.
x() );
2961 QVariant y( pt.
y() );
2978 QVariant x( pt.
x() );
2982 QVariant y( pt.
y() );
2986 QVariant hali(
"Center" );
2990 QVariant vali(
"Half" );
3005 if ( param.mColor.isValid() )
3007 textFormat.
setColor( param.mColor );
3010 if ( param.mSize > 0 )
3012 textFormat.
setSize( param.mSize );
3020 if ( ! param.mFont.isEmpty() )
3022 textFormat.
setFont( param.mFont );
3025 if ( param.mBufferColor.isValid() )
3027 bufferSettings.
setColor( param.mBufferColor );
3030 if ( param.mBufferSize > 0 )
3033 bufferSettings.
setSize(
static_cast<double>( param.mBufferSize ) );
3040 layer->setLabeling( simpleLabeling );
3041 layer->setLabelsEnabled(
true );
3043 fet.setGeometry( param.mGeom );
3047 layer->setRenderer( renderer.release() );
3050 if ( layer->isValid() )
3052 highlightLayers.append( layer.release() );
3056 mTemporaryLayers.append( highlightLayers );
3057 return highlightLayers;
3060 void QgsRenderer::removeTemporaryLayers()
3062 qDeleteAll( mTemporaryLayers );
3063 mTemporaryLayers.clear();
3066 QPainter *QgsRenderer::layersRendering(
const QgsMapSettings &mapSettings, QImage &image )
const
3068 QPainter *painter =
nullptr;
3072 #ifdef HAVE_SERVER_PYTHON_PLUGINS
3073 mContext.accessControl()->resolveFilterFeatures( mapSettings.
layers() );
3077 renderJob.render( mapSettings, &image );
3078 painter = renderJob.takePainter();
3080 if ( !renderJob.errors().isEmpty() )
3082 QString layerWMSName;
3083 QString firstErrorLayerId = renderJob.errors().at( 0 ).layerID;
3090 throw QgsException( QStringLiteral(
"Map rendering error in layer '%1'" ).arg( layerWMSName ) );
3096 void QgsRenderer::setLayerOpacity(
QgsMapLayer *layer,
int opacity )
const
3098 if ( opacity >= 0 && opacity <= 255 )
3100 switch ( layer->
type() )
3113 rasterRenderer->
setOpacity( opacity / 255. );
3128 void QgsRenderer::setLayerFilter(
QgsMapLayer *layer,
const QList<QgsWmsParametersFilter> &filters )
3132 QgsVectorLayer *filteredLayer = qobject_cast<QgsVectorLayer *>( layer );
3133 QStringList expList;
3134 for (
const QgsWmsParametersFilter &filter : filters )
3139 QDomDocument filterXml;
3141 if ( !filterXml.setContent( filter.mFilter,
true, &errorMsg ) )
3144 QStringLiteral(
"Filter string rejected. Error message: %1. The XML string was: %2" ).arg( errorMsg, filter.mFilter ) );
3146 QDomElement filterElem = filterXml.firstChildElement();
3151 expList << filterExp->dump();
3157 if ( !testFilterStringSafety( filter.mFilter ) )
3159 throw QgsSecurityException( QStringLiteral(
"The filter string %1"
3160 " has been rejected because of security reasons."
3161 " Note: Text strings have to be enclosed in single or double quotes."
3162 " A space between each word / special character is mandatory."
3163 " Allowed Keywords and special characters are "
3164 " IS,NOT,NULL,AND,OR,IN,=,<,>=,>,>=,!=,',',(,),DMETAPHONE,SOUNDEX."
3165 " Not allowed are semicolons in the filter expression." ).arg(
3169 QString newSubsetString = filter.mFilter;
3172 newSubsetString.prepend(
") AND (" );
3173 newSubsetString.append(
")" );
3174 newSubsetString.prepend( filteredLayer->
subsetString() );
3175 newSubsetString.prepend(
"(" );
3179 QgsMessageLog::logMessage( QStringLiteral(
"Error setting subset string from filter for layer %1, filter: %2" ).arg( layer->
name(), newSubsetString ),
3180 QStringLiteral(
"Server" ),
3181 Qgis::MessageLevel::Warning );
3183 QStringLiteral(
"Filter not valid for layer %1: check the filter syntax and the field names." ).arg( layer->
name() ) );
3189 expList.append( dimensionFilter( filteredLayer ) );
3193 if ( expList.size() == 1 )
3197 else if ( expList.size() > 1 )
3199 exp = QStringLiteral(
"( %1 )" ).arg( expList.join( QLatin1String(
" ) AND ( " ) ) );
3201 if ( !exp.isEmpty() )
3203 std::unique_ptr<QgsExpression> expression(
new QgsExpression( exp ) );
3206 mFeatureFilter.
setFilter( filteredLayer, *expression );
3212 QStringList QgsRenderer::dimensionFilter(
QgsVectorLayer *layer )
const
3214 QStringList expList;
3217 const QList<QgsMapLayerServerProperties::WmsDimensionInfo> wmsDims = serverProperties->
wmsDimensions();
3218 if ( wmsDims.isEmpty() )
3233 if ( fieldIndex == -1 )
3238 int endFieldIndex = -1;
3239 if ( !dim.endFieldName.isEmpty() )
3241 endFieldIndex = layer->
fields().
indexOf( dim.endFieldName );
3242 if ( endFieldIndex == -1 )
3248 if ( !dimParamValues.contains( dim.name.toUpper() ) )
3258 defValue = dim.referenceValue;
3263 QSet<QVariant> uniqueValues = layer->
uniqueValues( fieldIndex );
3264 if ( endFieldIndex != -1 )
3266 uniqueValues.unite( layer->
uniqueValues( endFieldIndex ) );
3269 QList<QVariant> values = qgis::setToList( uniqueValues );
3270 std::sort( values.begin(), values.end() );
3273 defValue = values.first();
3277 defValue = values.last();
3281 if ( endFieldIndex == -1 )
3287 QStringList expElems;
3292 expList << expElems.join(
' ' );
3300 QString dimParamValue = dimParamValues[dim.name.toUpper()];
3302 QStringList dimExplist;
3304 QStringList dimValues = dimParamValue.split(
',' );
3305 for (
int i = 0; i < dimValues.size(); ++i )
3307 QString dimValue = dimValues[i];
3309 if ( dimValue.size() > 1 )
3311 dimValue = dimValue.trimmed();
3314 if ( dimValue.contains(
'/' ) )
3316 QStringList rangeValues = dimValue.split(
'/' );
3318 if ( rangeValues.size() != 2 )
3323 QVariant rangeMin = QVariant( rangeValues[0] );
3324 QVariant rangeMax = QVariant( rangeValues[1] );
3335 QStringList expElems;
3336 if ( endFieldIndex == -1 )
3356 << QStringLiteral(
")" );
3358 dimExplist << expElems.join(
' ' );
3362 QVariant dimVariant = QVariant( dimValue );
3368 if ( endFieldIndex == -1 )
3377 QStringList expElems;
3382 dimExplist << expElems.join(
' ' );
3387 if ( dimExplist.size() == 1 )
3389 expList << dimExplist;
3391 else if ( dimExplist.size() > 1 )
3393 expList << QStringLiteral(
"( %1 )" ).arg( dimExplist.join( QLatin1String(
" ) OR ( " ) ) );
3400 void QgsRenderer::setLayerSelection(
QgsMapLayer *layer,
const QStringList &fids )
const
3410 if ( selectedIds.empty() )
3421 void QgsRenderer::setLayerAccessControlFilter(
QgsMapLayer *layer )
const
3423 #ifdef HAVE_SERVER_PYTHON_PLUGINS
3441 void QgsRenderer::annotationsRendering( QPainter *painter,
const QgsMapSettings &mapSettings )
const
3444 const QList< QgsAnnotation * > annotations = annotationManager->
annotations();
3450 if ( !annotation || !annotation->isVisible() )
3456 if ( annotation->hasFixedMapPosition() )
3458 QgsPointXY mapPos = annotation->mapPosition();
3459 if ( mapSettings.
destinationCrs() != annotation->mapPositionCrs() )
3464 mapPos = coordTransform.transform( mapPos );
3472 offsetX = devicePos.
x();
3473 offsetY = devicePos.
y();
3477 const QPointF relativePos = annotation->relativePosition();
3478 offsetX = mapSettings.
outputSize().width() * relativePos.x();
3479 offsetY = mapSettings.
outputSize().height() * relativePos.y();
3483 painter->translate( offsetX, offsetY );
3484 annotation->render( renderContext );
3489 QImage *QgsRenderer::scaleImage(
const QImage *image )
const
3494 QImage *scaledImage =
nullptr;
3495 const int width = mWmsParameters.
widthAsInt();
3497 if ( width != image->width() || height != image->height() )
3499 scaledImage =
new QImage( image->scaled( width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ) );
3505 void QgsRenderer::handlePrintErrors(
const QgsLayout *layout )
const
3511 QList< QgsLayoutItemMap * > mapList;
3514 QList< QgsLayoutItemMap * >::const_iterator mapIt = mapList.constBegin();
3515 for ( ; mapIt != mapList.constEnd(); ++mapIt )
3517 if ( !( *mapIt )->renderingErrors().isEmpty() )
3529 for (
auto layer : layers )
3531 const QgsWmsParametersLayer param = mContext.
parameters( *layer );
3542 setLayerOpacity( layer, param.mOpacity );
3549 setLayerSld( layer, mContext.
sld( *layer ) );
3553 setLayerStyle( layer, mContext.
style( *layer ) );
3558 setLayerOpacity( layer, param.mOpacity );
3563 setLayerFilter( layer, param.mFilter );
3568 setLayerAccessControlFilter( layer );
3573 setLayerSelection( layer, param.mSelection );
3578 updateExtent( layer, *settings );
3588 void QgsRenderer::setLayerStyle(
QgsMapLayer *layer,
const QString &style )
const
3590 if ( style.isEmpty() )
3599 QStringLiteral(
"Style '%1' does not exist for layer '%2'" ).arg( style, layer->
name() ) );
3603 void QgsRenderer::setLayerSld(
QgsMapLayer *layer,
const QDomElement &sld )
const
3608 QString sldStyleName =
"__sld_style";
3609 while ( styles.contains( sldStyleName ) )
3611 sldStyleName.append(
'@' );
3624 if ( !mWmsParameters.
bbox().isEmpty() )
3628 std::unique_ptr<QImage> tmp( createImage( mContext.
mapSize(
false ) ) );
3629 configureMapSettings( tmp.get(), mapSettings );