@@ -121,21 +121,21 @@ QDomDocument QgsWMSServer::getCapabilities()
121121
122122 QList<QPair<QString, QString> > queryItems = mapUrl.queryItems ();
123123 QList<QPair<QString, QString> >::const_iterator queryIt = queryItems.constBegin ();
124- for ( ; queryIt != queryItems.constEnd (); ++queryIt )
124+ for ( ; queryIt != queryItems.constEnd (); ++queryIt )
125125 {
126- if ( queryIt->first .compare (" REQUEST" , Qt::CaseInsensitive ) == 0 )
126+ if ( queryIt->first .compare ( " REQUEST" , Qt::CaseInsensitive ) == 0 )
127127 {
128128 mapUrl.removeQueryItem ( queryIt->first );
129129 }
130- else if ( queryIt->first .compare (" VERSION" , Qt::CaseInsensitive ) == 0 )
130+ else if ( queryIt->first .compare ( " VERSION" , Qt::CaseInsensitive ) == 0 )
131131 {
132132 mapUrl.removeQueryItem ( queryIt->first );
133133 }
134- else if ( queryIt->first .compare (" SERVICE" , Qt::CaseInsensitive ) == 0 )
134+ else if ( queryIt->first .compare ( " SERVICE" , Qt::CaseInsensitive ) == 0 )
135135 {
136136 mapUrl.removeQueryItem ( queryIt->first );
137137 }
138- else if ( queryIt->first .compare (" _DC" , Qt::CaseInsensitive ) == 0 )
138+ else if ( queryIt->first .compare ( " _DC" , Qt::CaseInsensitive ) == 0 )
139139 {
140140 mapUrl.removeQueryItem ( queryIt->first );
141141 }
@@ -636,11 +636,10 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
636636 if ( i_it == mParameterMap .end () )
637637 {
638638 std::map<QString, QString>::const_iterator x_it = mParameterMap .find ( " X" );
639- if ( x_it = = mParameterMap .end () )
639+ if ( x_it ! = mParameterMap .end () )
640640 {
641- return 5 ;
641+ iString = x_it-> second ;
642642 }
643- iString = x_it->second ;
644643 }
645644 else
646645 {
@@ -649,18 +648,17 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
649648 i = iString.toInt ( &conversionSuccess );
650649 if ( !conversionSuccess )
651650 {
652- return 6 ;
651+ i = - 1 ;
653652 }
654653
655654 std::map<QString, QString>::const_iterator j_it = mParameterMap .find ( " J" );
656655 if ( j_it == mParameterMap .end () )
657656 {
658657 std::map<QString, QString>::const_iterator y_it = mParameterMap .find ( " Y" );
659- if ( y_it = = mParameterMap .end () )
658+ if ( y_it ! = mParameterMap .end () )
660659 {
661- return 7 ;
660+ jString = y_it-> second ;
662661 }
663- jString = y_it->second ;
664662 }
665663 else
666664 {
@@ -669,9 +667,34 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
669667 j = jString.toInt ( &conversionSuccess );
670668 if ( !conversionSuccess )
671669 {
672- return 8 ;
670+ j = -1 ;
671+ }
672+
673+ // Normally, I/J or X/Y are mandatory parameters.
674+ // However, in order to make attribute only queries via the FILTER parameter, it is allowed to skip them if the FILTER parameter is there
675+
676+ QgsRectangle* featuresRect = 0 ;
677+ QgsPoint* infoPoint = 0 ;
678+ if ( i == -1 || j == -1 )
679+ {
680+ if ( mParameterMap .find ( " FILTER" ) != mParameterMap .end () )
681+ {
682+ featuresRect = new QgsRectangle ();
683+ }
684+ else
685+ {
686+ throw QgsMapServiceException ( " ParameterMissing" , " I/J parameters are required for GetFeatureInfo" );
687+ }
688+ }
689+ else
690+ {
691+ infoPoint = new QgsPoint ();
673692 }
674693
694+ // get the layer registered in QgsMapLayerRegistry and apply possible filters
695+ QStringList layerIds = layerSet ( layersList, stylesList, mMapRenderer ->destinationCrs () );
696+ QMap<QString, QString> originalLayerFilters = applyRequestedLayerFilters ( layersList, layerIds );
697+
675698 QDomElement getFeatureInfoElement = result.createElement ( " GetFeatureInfoResponse" );
676699 result.appendChild ( getFeatureInfoElement );
677700
@@ -681,72 +704,86 @@ int QgsWMSServer::getFeatureInfo( QDomDocument& result )
681704
682705 QList<QgsMapLayer*> layerList;
683706 QgsMapLayer* currentLayer = 0 ;
684- QgsPoint infoPoint; // info point in coordinates of the layer
685707 QStringList::const_iterator layerIt;
686708 for ( layerIt = queryLayerList.constBegin (); layerIt != queryLayerList.constEnd (); ++layerIt )
687709 {
688710 // create maplayers from sld parser (several layers are possible in case of feature info on a group)
689711 layerList = mConfigParser ->mapLayerFromStyle ( *layerIt, " " );
690712 QList<QgsMapLayer*>::iterator layerListIt = layerList.begin ();
691- for ( ; layerListIt != layerList.end (); ++layerListIt )
713+ for ( ; layerListIt != layerList.end (); ++layerListIt )
692714 {
693- currentLayer = *layerListIt;
694- if ( !currentLayer || nonIdentifiableLayers.contains ( currentLayer->id () ) )
695- {
715+ currentLayer = *layerListIt;
716+ if ( !currentLayer || nonIdentifiableLayers.contains ( currentLayer->id () ) )
717+ {
696718 continue ;
697- }
698- if ( infoPointToLayerCoordinates ( i, j, infoPoint, mMapRenderer , currentLayer ) != 0 )
699- {
719+ }
720+
721+ if ( infoPoint && infoPointToLayerCoordinates ( i, j, infoPoint, mMapRenderer , currentLayer ) != 0 )
722+ {
700723 continue ;
724+ }
725+
726+ QDomElement layerElement = result.createElement ( " Layer" );
727+ layerElement.setAttribute ( " name" , currentLayer->name () );
728+ getFeatureInfoElement.appendChild ( layerElement );
729+
730+ // switch depending on vector or raster
731+ QgsVectorLayer* vectorLayer = dynamic_cast <QgsVectorLayer*>( currentLayer );
732+ if ( vectorLayer )
733+ {
734+ // is there alias info for this vector layer?
735+ QMap< int , QString > layerAliasInfo;
736+ QMap< QString, QMap< int , QString > >::const_iterator aliasIt = aliasInfo.find ( currentLayer->id () );
737+ if ( aliasIt != aliasInfo.constEnd () )
738+ {
739+ layerAliasInfo = aliasIt.value ();
701740 }
702- QgsDebugMsg ( " Info point in layer crs: " + QString::number ( infoPoint.x () ) + " //" + QString::number ( infoPoint.y () ) );
703741
704- QDomElement layerElement = result.createElement ( " Layer" );
705- layerElement.setAttribute ( " name" , currentLayer->name () );
706- getFeatureInfoElement.appendChild ( layerElement );
742+ // hidden attributes for this layer
743+ QSet<QString> layerHiddenAttributes;
744+ QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find ( currentLayer->id () );
745+ if ( hiddenIt != hiddenAttributes.constEnd () )
746+ {
747+ layerHiddenAttributes = hiddenIt.value ();
748+ }
707749
708- // switch depending on vector or raster
709- QgsVectorLayer* vectorLayer = dynamic_cast <QgsVectorLayer*>( currentLayer );
710- if ( vectorLayer )
750+ if ( featureInfoFromVectorLayer ( vectorLayer, infoPoint, featureCount, result, layerElement, mMapRenderer , layerAliasInfo, layerHiddenAttributes, featuresRect ) != 0 )
711751 {
712- // is there alias info for this vector layer?
713- QMap< int , QString > layerAliasInfo;
714- QMap< QString, QMap< int , QString > >::const_iterator aliasIt = aliasInfo.find ( currentLayer->id () );
715- if ( aliasIt != aliasInfo.constEnd () )
716- {
717- layerAliasInfo = aliasIt.value ();
718- }
719-
720- // hidden attributes for this layer
721- QSet<QString> layerHiddenAttributes;
722- QMap< QString, QSet<QString> >::const_iterator hiddenIt = hiddenAttributes.find ( currentLayer->id () );
723- if ( hiddenIt != hiddenAttributes.constEnd () )
724- {
725- layerHiddenAttributes = hiddenIt.value ();
726- }
727-
728- if ( featureInfoFromVectorLayer ( vectorLayer, infoPoint, featureCount, result, layerElement, mMapRenderer , layerAliasInfo, layerHiddenAttributes ) != 0 )
729- {
730- continue ;
731- }
752+ continue ;
732753 }
733- else // raster layer
754+ }
755+ else // raster layer
756+ {
757+ QgsRasterLayer* rasterLayer = dynamic_cast <QgsRasterLayer*>( currentLayer );
758+ if ( rasterLayer )
734759 {
735- QgsRasterLayer* rasterLayer = dynamic_cast <QgsRasterLayer*>( currentLayer );
736- if ( rasterLayer )
737- {
738- if ( featureInfoFromRasterLayer ( rasterLayer, infoPoint, result, layerElement ) != 0 )
739- {
740- continue ;
741- }
742- }
743- else
744- {
760+ if ( featureInfoFromRasterLayer ( rasterLayer, infoPoint, result, layerElement ) != 0 )
761+ {
745762 continue ;
746- }
763+ }
747764 }
765+ else
766+ {
767+ continue ;
768+ }
769+ }
748770 }
749771 }
772+
773+ if ( featuresRect )
774+ {
775+ QDomElement bBoxElem = result.createElement ( " BoundingBox" );
776+ bBoxElem.setAttribute ( " CRS" , mMapRenderer ->destinationCrs ().authid () );
777+ bBoxElem.setAttribute ( " minx" , featuresRect->xMinimum () );
778+ bBoxElem.setAttribute ( " maxx" , featuresRect->xMaximum () );
779+ bBoxElem.setAttribute ( " miny" , featuresRect->yMinimum () );
780+ bBoxElem.setAttribute ( " maxy" , featuresRect->yMaximum () );
781+ getFeatureInfoElement.insertBefore ( bBoxElem, QDomNode () ); // insert as first child
782+ }
783+
784+ restoreLayerFilters ( originalLayerFilters );
785+ delete featuresRect;
786+ delete infoPoint;
750787 return 0 ;
751788}
752789
@@ -1101,29 +1138,29 @@ int QgsWMSServer::initializeSLDParser( QStringList& layersList, QStringList& sty
11011138 return 0 ;
11021139}
11031140
1104- int QgsWMSServer::infoPointToLayerCoordinates ( int i, int j, QgsPoint& layerCoords, QgsMapRenderer* mapRender,
1141+ int QgsWMSServer::infoPointToLayerCoordinates ( int i, int j, QgsPoint* layerCoords, QgsMapRenderer* mapRender,
11051142 QgsMapLayer* layer ) const
11061143{
1107- if ( !mapRender || !layer || !mapRender->coordinateTransform () )
1144+ if ( !layerCoords || ! mapRender || !layer || !mapRender->coordinateTransform () )
11081145 {
11091146 return 1 ;
11101147 }
11111148
11121149 // first transform i,j to map output coordinates
11131150 QgsPoint mapPoint = mapRender->coordinateTransform ()->toMapCoordinates ( i, j );
11141151 // and then to layer coordinates
1115- layerCoords = mapRender->mapToLayerCoordinates ( layer, mapPoint );
1152+ * layerCoords = mapRender->mapToLayerCoordinates ( layer, mapPoint );
11161153 return 0 ;
11171154}
11181155
11191156int QgsWMSServer::featureInfoFromVectorLayer ( QgsVectorLayer* layer,
1120- const QgsPoint& infoPoint,
1157+ const QgsPoint* infoPoint,
11211158 int nFeatures,
11221159 QDomDocument& infoDocument,
11231160 QDomElement& layerElement,
11241161 QgsMapRenderer* mapRender,
11251162 QMap<int , QString>& aliasMap,
1126- QSet<QString>& hiddenAttributes ) const
1163+ QSet<QString>& hiddenAttributes, QgsRectangle* featureBBox ) const
11271164{
11281165 if ( !layer || !mapRender )
11291166 {
@@ -1133,9 +1170,16 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
11331170 // we need a selection rect (0.01 of map width)
11341171 QgsRectangle mapRect = mapRender->extent ();
11351172 QgsRectangle layerRect = mapRender->mapToLayerCoordinates ( layer, mapRect );
1136- double searchRadius = ( layerRect.xMaximum () - layerRect.xMinimum () ) / 200 ;
1137- QgsRectangle searchRect ( infoPoint.x () - searchRadius, infoPoint.y () - searchRadius,
1138- infoPoint.x () + searchRadius, infoPoint.y () + searchRadius );
1173+
1174+ QgsRectangle searchRect;
1175+
1176+ // info point could be 0 in case there is only an attribute filter
1177+ if ( infoPoint )
1178+ {
1179+ double searchRadius = ( layerRect.xMaximum () - layerRect.xMinimum () ) / 200 ;
1180+ searchRect.set ( infoPoint->x () - searchRadius, infoPoint->y () - searchRadius,
1181+ infoPoint->x () + searchRadius, infoPoint->y () + searchRadius );
1182+ }
11391183
11401184 // do a select with searchRect and go through all the features
11411185 QgsVectorDataProvider* provider = layer->dataProvider ();
@@ -1150,7 +1194,7 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
11501194 const QgsFieldMap& fields = provider->fields ();
11511195 bool addWktGeometry = mConfigParser && mConfigParser ->featureInfoWithWktGeometry ();
11521196
1153- provider->select ( provider->attributeIndexes (), searchRect, addWktGeometry, true );
1197+ provider->select ( provider->attributeIndexes (), searchRect, addWktGeometry || featureBBox , true );
11541198 while ( provider->nextFeature ( feature ) )
11551199 {
11561200 if ( featureCounter > nFeatures )
@@ -1188,16 +1232,25 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
11881232 }
11891233
11901234 // also append the wkt geometry as an attribute
1191- if ( addWktGeometry )
1235+ QgsGeometry* geom = feature.geometry ();
1236+ if ( addWktGeometry && geom )
11921237 {
1193- QgsGeometry* geom = feature.geometry ();
1194- if ( geom )
1238+ QDomElement geometryElement = infoDocument.createElement ( " Attribute" );
1239+ geometryElement.setAttribute ( " name" , " geometry" );
1240+ geometryElement.setAttribute ( " value" , geom->exportToWkt () );
1241+ geometryElement.setAttribute ( " type" , " derived" );
1242+ featureElement.appendChild ( geometryElement );
1243+ }
1244+ if ( featureBBox && geom && mapRender ) // extend feature info bounding box if requested
1245+ {
1246+ QgsRectangle box = mapRender->layerExtentToOutputExtent ( layer, geom->boundingBox () );
1247+ if ( featureBBox->isEmpty () )
1248+ {
1249+ *featureBBox = box;
1250+ }
1251+ else
11951252 {
1196- QDomElement geometryElement = infoDocument.createElement ( " Attribute" );
1197- geometryElement.setAttribute ( " name" , " geometry" );
1198- geometryElement.setAttribute ( " value" , geom->exportToWkt () );
1199- geometryElement.setAttribute ( " type" , " derived" );
1200- featureElement.appendChild ( geometryElement );
1253+ featureBBox->combineExtentWith ( &box );
12011254 }
12021255 }
12031256 }
@@ -1207,17 +1260,17 @@ int QgsWMSServer::featureInfoFromVectorLayer( QgsVectorLayer* layer,
12071260}
12081261
12091262int QgsWMSServer::featureInfoFromRasterLayer ( QgsRasterLayer* layer,
1210- const QgsPoint& infoPoint,
1263+ const QgsPoint* infoPoint,
12111264 QDomDocument& infoDocument,
12121265 QDomElement& layerElement ) const
12131266{
1214- if ( !layer )
1267+ if ( !infoPoint || ! layer )
12151268 {
12161269 return 1 ;
12171270 }
12181271
12191272 QMap<QString, QString> attributes;
1220- layer->identify ( infoPoint, attributes );
1273+ layer->identify ( * infoPoint, attributes );
12211274
12221275 for ( QMap<QString, QString>::const_iterator it = attributes.constBegin (); it != attributes.constEnd (); ++it )
12231276 {
0 commit comments