[mapguide-commits] r7519 - in trunk/MgDev: Common/MapGuideCommon/Controller Common/MapGuideCommon/Services Doc/viewerapi Server/src/Services/Rendering Server/src/UnitTesting Web/src/HttpHandler Web/src/localized Web/src/mapviewerjava Web/src/mapviewernet Web/src/mapviewerphp Web/src/viewerfiles

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri May 24 07:47:52 PDT 2013


Author: jng
Date: 2013-05-24 07:47:52 -0700 (Fri, 24 May 2013)
New Revision: 7519

Removed:
   trunk/MgDev/Web/src/mapviewerjava/getselectedfeatures.jsp
   trunk/MgDev/Web/src/mapviewernet/getselectedfeatures.aspx
   trunk/MgDev/Web/src/mapviewerphp/getselectedfeatures.php
Modified:
   trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.cpp
   trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.h
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h
   trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h
   trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp
   trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h
   trunk/MgDev/Doc/viewerapi/index.htm
   trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp
   trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h
   trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp
   trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp
   trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
   trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h
   trunk/MgDev/Server/src/UnitTesting/TestRenderingService.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.h
   trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp
   trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h
   trunk/MgDev/Web/src/localized/en
   trunk/MgDev/Web/src/mapviewerjava/mapframe.jsp
   trunk/MgDev/Web/src/mapviewernet/mapframe.aspx
   trunk/MgDev/Web/src/mapviewerphp/mapframe.php
   trunk/MgDev/Web/src/viewerfiles/ajaxmappane.templ
   trunk/MgDev/Web/src/viewerfiles/browserdetect.js
Log:
Merge in RFC 126 work. This completes the implementation.

Modified: trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -16,7 +16,15 @@
 //
 
 #include "MapGuideCommon.h"
+#include "Base64.h"
+#include "VectorLayerDefinition.h"
+#include "NameStringPair.h"
 
+#define REQUEST_ATTRIBUTES       1
+#define REQUEST_INLINE_SELECTION 2
+#define REQUEST_TOOLTIP          4
+#define REQUEST_HYPERLINK        8
+
 //////////////////////////////////////////////////////////////////
 // Construct a MgHtmlController object
 //
@@ -216,6 +224,420 @@
 }
 
 //////////////////////////////////////////////////////////////////
+// Processes a QueryMapFeatures request from the Viewer
+//
+MgByteReader* MgHtmlController::QueryMapFeatures(
+    CREFSTRING mapName,
+    MgStringCollection* layerNames,
+    MgGeometry* selectionGeometry,
+    INT32 selectionVariant,
+    CREFSTRING featureFilter,
+    INT32 maxFeatures,
+    bool persist,
+    INT32 layerAttributeFilter,
+    INT32 requestData,
+    CREFSTRING selectionColor,
+    CREFSTRING selectionFormat)
+{
+    Ptr<MgByteReader> result;
+    Ptr<MgFeatureInformation> featureInfo;
+    Ptr<MgBatchPropertyCollection> attributes;
+    Ptr<MgByteReader> inlineSelectionImg;
+    Ptr<MgSelection> newSelection;
+
+    // Create a Resource Service instance
+    Ptr<MgResourceService> resourceService = (MgResourceService*)GetService(MgServiceType::ResourceService);
+
+    // Create MgMap
+    Ptr<MgMap> map = new MgMap(m_siteConn);
+    map->Open(mapName);
+
+    // Make sure we clear any track changes - these are not applicable for AJAX.
+    Ptr<MgNamedCollection> changeLists = map->GetChangeLists();
+    if (changeLists->GetCount() > 0)
+    {
+        map->ClearChanges();
+        map->Save();
+    }
+
+    // Create Proxy Rendering Service instance
+    Ptr<MgRenderingService> service = (MgRenderingService*)(GetService(MgServiceType::RenderingService));
+
+    // Call the C++ API, regardless of bitmask as any part of the mask will require information from this API
+    featureInfo = service->QueryFeatures(map, layerNames, selectionGeometry, selectionVariant, featureFilter, maxFeatures, layerAttributeFilter);
+
+    if (persist)
+    {
+        //save the selection set in the session repository
+        Ptr<MgSelection> selection;
+        if (NULL != featureInfo.p)
+            selection = featureInfo->GetSelection();
+        if(!selection)
+            selection = new MgSelection(map);
+        selection->Save(resourceService, mapName);
+        newSelection = SAFE_ADDREF(selection.p);
+
+        //Needed for GetLayers() to work below
+        newSelection->SetMap(map);
+    }
+
+    // Render an image of this selection if requested
+    if (((requestData & REQUEST_INLINE_SELECTION) == REQUEST_INLINE_SELECTION) && NULL != newSelection.p)
+    {
+        Ptr<MgColor> selColor = new MgColor(selectionColor);
+        Ptr<MgRenderingOptions> renderOpts = new MgRenderingOptions(selectionFormat, MgRenderingOptions::RenderSelection | MgRenderingOptions::KeepSelection, selColor);
+        inlineSelectionImg = service->RenderDynamicOverlay(map, newSelection, renderOpts);
+    }
+
+    // Collect any attributes of selected features
+    if ((requestData & REQUEST_ATTRIBUTES) == REQUEST_ATTRIBUTES)
+    {
+        // This could be chunky for big selections, but client applications can control this via MAXFEATURES, so the onus is on them
+        attributes = service->QueryFeatureProperties(map, layerNames, selectionGeometry, selectionVariant, L"", maxFeatures, layerAttributeFilter, true);
+    }
+
+    result = CollectQueryMapFeaturesResult(resourceService, requestData, featureInfo, newSelection, attributes, inlineSelectionImg);
+
+    // Return XML
+    return result.Detach();
+}
+
+MgByteReader* MgHtmlController::CollectQueryMapFeaturesResult(MgResourceService* resourceService,
+                                                              INT32 requestData,
+                                                              MgFeatureInformation* featInfo,
+                                                              MgSelection* selectionSet,
+                                                              MgBatchPropertyCollection* attributes, 
+                                                              MgByteReader* inlineSelection)
+{
+    STRING xml;
+    STRING tooltip;
+    STRING hyperlink;
+    STRING xmlSelection = selectionSet? selectionSet->ToXml(false): L"";
+
+    if (NULL != featInfo)
+    {
+        tooltip = featInfo->GetTooltip();
+        hyperlink = featInfo->GetHyperlink();
+    }
+
+    // TODO: Stil haven't defined a schema for v2.6. Should we?
+    xml.append(L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FeatureInformation>\n");
+
+    size_t len = xmlSelection.length();
+    if(len > 0)
+    {
+        xml.reserve(len + 2048);
+        xml.append(xmlSelection);
+    }
+    else
+    {
+        xml.reserve(2048);
+        xml.append(L"<FeatureSet />\n");
+    }
+
+    if (((requestData & REQUEST_TOOLTIP) == REQUEST_TOOLTIP) && !tooltip.empty())
+    {
+        xml.append(L"<Tooltip>");
+        xml.append(MgUtil::ReplaceEscapeCharInXml(tooltip));
+        xml.append(L"</Tooltip>\n");
+    }
+    else
+        xml.append(L"<Tooltip />\n");
+
+    if (((requestData & REQUEST_HYPERLINK) == REQUEST_HYPERLINK) && !hyperlink.empty())
+    {
+        xml.append(L"<Hyperlink>");
+        xml.append(MgUtil::ReplaceEscapeCharInXml(hyperlink));
+        xml.append(L"</Hyperlink>\n");
+    }
+    else
+        xml.append(L"<Hyperlink />\n");
+
+    if (((requestData & REQUEST_INLINE_SELECTION) == REQUEST_INLINE_SELECTION) && NULL != inlineSelection)
+    {
+        xml.append(L"<InlineSelectionImage>\n");
+        xml.append(L"<MimeType>");
+        xml.append(inlineSelection->GetMimeType());
+        xml.append(L"</MimeType>\n");
+        xml.append(L"<Content>");
+        MgByteSink sink(inlineSelection);
+        Ptr<MgByte> bytes = sink.ToBuffer();
+        Ptr<MgMemoryStreamHelper> streamHelper = new MgMemoryStreamHelper((INT8*) bytes->Bytes(), bytes->GetLength(), false);
+        std::string b64 = streamHelper->ToBase64();
+        STRING wb64 = MgUtil::MultiByteToWideChar(b64);
+        xml.append(wb64);
+        xml.append(L"</Content>\n");
+        xml.append(L"</InlineSelectionImage>\n");
+    }
+    else
+        xml.append(L"<InlineSelectionImage />\n");
+
+    if (((requestData & REQUEST_ATTRIBUTES) == REQUEST_ATTRIBUTES) && NULL != attributes)
+    {
+        xml.append(L"<SelectedFeatures>\n");
+        WriteSelectedFeatureAttributes(resourceService, selectionSet, attributes, xml);
+        xml.append(L"</SelectedFeatures>\n");
+    }
+    else
+        xml.append(L"<SelectedFeatures />\n");
+
+    xml.append(L"</FeatureInformation>\n");
+
+    string xmlDoc = MgUtil::WideCharToMultiByte(xml);
+    STRING mimeType = L"text/xml";
+    return MgUtil::GetByteReader(xmlDoc, &mimeType);
+}
+
+void MgHtmlController::WriteSelectedFeatureAttributes(MgResourceService* resourceService,
+                                                      MgSelection* selectionSet,
+                                                      MgBatchPropertyCollection* attributes,
+                                                      REFSTRING xmlOut)
+{
+    //Rather than doing a verbatim xml dump of MgBatchPropertyCollection, let's output something
+    //that is more intuitive for client applications using this service operation to understand.
+
+    //We could assume sorted layers in the MgBatchPropertyCollection, but play safe
+    //and store our per-layer XML fragments in a bucket (keyed on layer name) and return 
+    //the merged bucket result at the end
+    std::map<STRING, STRING> bucket;
+
+    MgAgfReaderWriter agfRw;
+    MgWktReaderWriter wktRw;
+
+    Ptr<MgReadOnlyLayerCollection> selLayers = selectionSet->GetLayers();
+    if (NULL != selLayers.p)
+    {
+        // Our structure is as follows
+        //
+        // [0...n] <SelectedLayer> - A layer containing selected features
+        //   [1] <LayerMetadata> - Describing properties, its display name and its property type. Due to how QueryFeatureProperties works, display names
+        //                         are used for property names for each feature. This element provides a reverse lookup table to ascertain the FDO system 
+        //                         property name for each attribute for client applications that require such information
+        //     [0...n] <Feature> - Each selected feature in the layer
+        //       [1] <Bounds> - The feature's bounding box [minx miny maxx maxy]
+        //       [0...n] <Property> - Property value for current feature
+
+        for (INT32 i = 0; i < selLayers->GetCount(); i++)
+        {
+            Ptr<MgLayerBase> selLayer = selLayers->GetItem(i);
+            STRING layerName = selLayer->GetName();
+            if (bucket.find(layerName) == bucket.end())
+            {
+                STRING xml = L"<SelectedLayer id=\"";
+                xml.append(selLayer->GetObjectId());
+                xml.append(L"\" name=\"");
+                xml.append(selLayer->GetName());
+                xml.append(L"\">\n");
+                xml.append(L"<LayerMetadata>\n");
+                Ptr<MgClassDefinition> clsDef = selLayer->GetClassDefinition();
+                Ptr<MgPropertyDefinitionCollection> clsProps = clsDef->GetProperties();
+                Ptr<MgResourceIdentifier> layerId = selLayer->GetLayerDefinition();
+                //We need the property mappings of the source layer definition to compile our layer metadata
+                std::auto_ptr<MdfModel::LayerDefinition> ldf(MgLayerBase::GetLayerDefinition(resourceService, layerId));
+                if (ldf.get() != NULL)
+                {
+                    MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf.get());
+                    if(vl != NULL)
+                    {
+                        MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
+                        for (int j=0; j<pmappings->GetCount(); j++)
+                        {
+                            STRING pTypeStr;
+                            MdfModel::NameStringPair* m = pmappings->GetAt(j);
+                            INT32 pidx = clsProps->IndexOf(m->GetName());
+                            if (pidx >= 0)
+                            {
+                                Ptr<MgPropertyDefinition> propDef = clsProps->GetItem(pidx);
+                                INT32 pdType = propDef->GetPropertyType();
+                                INT32 pType = MgPropertyType::Null;
+                                if (pdType == MgFeaturePropertyType::DataProperty)
+                                {
+                                    pType = ((MgDataPropertyDefinition*)propDef.p)->GetDataType();
+                                }
+                                else if (pdType == MgFeaturePropertyType::GeometricProperty)
+                                {
+                                    pType = MgPropertyType::Geometry;
+                                }
+                                MgUtil::Int32ToString(pType, pTypeStr);
+                                xml.append(L"<Property>\n");
+                                xml.append(L"<Name>");
+                                xml.append(m->GetName());
+                                xml.append(L"</Name>\n");
+                                xml.append(L"<Type>");
+                                xml.append(pTypeStr);
+                                xml.append(L"</Type>\n");
+                                xml.append(L"<DisplayName>");
+                                xml.append(m->GetValue());
+                                xml.append(L"</DisplayName>\n");
+                                xml.append(L"</Property>\n");
+                            }
+                        }
+                    }
+                }
+                xml += L"</LayerMetadata>\n";
+                bucket[layerName] = xml;
+            }
+        }
+
+        for (INT32 i = 0; i < attributes->GetCount(); i++)
+        {
+            Ptr<MgPropertyCollection> featProps = attributes->GetItem(i);
+            INT32 lidx = featProps->IndexOf(L"_MgLayerName");
+            INT32 fidx = featProps->IndexOf(L"_MgFeatureBoundingBox");
+
+            //Must have both the _MgLayerName and _MgFeatureBoundingBox
+            if (lidx < 0 || fidx < 0)
+                continue;
+
+            Ptr<MgStringProperty> layerNameProp = (MgStringProperty*)featProps->GetItem(lidx);
+            Ptr<MgStringProperty> boundsProp = (MgStringProperty*)featProps->GetItem(fidx);
+
+            //Locate the matching bucketed fragment to append to
+            STRING layerName = layerNameProp->GetValue();
+            if (bucket.find(layerName) != bucket.end())
+            {
+                //Good to go, write our feature to this bucketed fragment
+                REFSTRING xml = bucket[layerName];
+                xml.append(L"<Feature>\n");
+                xml.append(L"<Bounds>");
+                xml.append(boundsProp->GetValue());
+                xml.append(L"</Bounds>\n");
+                for (INT32 p = 0; p < featProps->GetCount(); p++)
+                {
+                    //Skip special properties
+                    if (p == lidx || p == fidx)
+                        continue;
+                    Ptr<MgNullableProperty> prop = dynamic_cast<MgNullableProperty*>(featProps->GetItem(p));
+                    if (NULL != prop.p)
+                    {
+                        xml.append(L"<Property>\n");
+                        xml.append(L"<Name>");
+                        xml.append(prop->GetName());
+                        xml.append(L"</Name>\n");
+                        //We'll follow MgProperty spec. Null is represented by omission of <Value>
+                        if (!prop->IsNull())
+                        {
+                            INT32 ptype = prop->GetPropertyType();
+                            switch(ptype)
+                            {
+                            //case MgPropertyType::Blob:
+                            case MgPropertyType::Boolean:
+                                {
+                                    xml.append(L"<Value>");
+                                    xml.append(((MgBooleanProperty*)prop.p)->GetValue() ? L"true" : L"false");
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::Byte:
+                                {
+                                    STRING sVal;
+                                    MgUtil::Int32ToString((INT32)((MgByteProperty*)prop.p)->GetValue(), sVal);
+                                    xml.append(L"<Value>");
+                                    xml.append(sVal);
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            //case MgPropertyType::Clob:
+                            case MgPropertyType::DateTime:
+                                {
+                                    Ptr<MgDateTime> dt = ((MgDateTimeProperty*)prop.p)->GetValue();
+                                    xml.append(L"<Value>");
+                                    xml.append(dt->ToXmlString());
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::Decimal:
+                            case MgPropertyType::Double:
+                                {
+                                    STRING sVal;
+                                    MgUtil::DoubleToString(((MgDoubleProperty*)prop.p)->GetValue(), sVal);
+                                    xml.append(L"<Value>");
+                                    xml.append(sVal);
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::Geometry:
+                                {
+                                    try 
+                                    {
+                                        Ptr<MgByteReader> agf = ((MgGeometryProperty*)prop.p)->GetValue();
+                                        Ptr<MgGeometry> geom = agfRw.Read(agf);
+                                        STRING wkt = wktRw.Write(geom);
+                                        xml.append(L"<Value>");
+                                        xml.append(wkt);
+                                        xml.append(L"</Value>\n");
+                                    }
+                                    catch (MgException* ex) //Bad geom maybe
+                                    {
+                                        SAFE_RELEASE(ex);
+                                    }
+                                }
+                                break;
+                            case MgPropertyType::Int16:
+                                {
+                                    STRING sVal;
+                                    MgUtil::Int32ToString((INT32)((MgInt16Property*)prop.p)->GetValue(), sVal);
+                                    xml.append(L"<Value>");
+                                    xml.append(sVal);
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::Int32:
+                                {
+                                    STRING sVal;
+                                    MgUtil::Int32ToString(((MgInt32Property*)prop.p)->GetValue(), sVal);
+                                    xml.append(L"<Value>");
+                                    xml.append(sVal);
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::Int64:
+                                {
+                                    STRING sVal;
+                                    MgUtil::Int64ToString(((MgInt64Property*)prop.p)->GetValue(), sVal);
+                                    xml.append(L"<Value>");
+                                    xml.append(sVal);
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::Single:
+                                {
+                                    STRING sVal;
+                                    MgUtil::SingleToString(((MgSingleProperty*)prop.p)->GetValue(), sVal);
+                                    xml.append(L"<Value>");
+                                    xml.append(sVal);
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            case MgPropertyType::String:
+                                {
+                                    xml.append(L"<Value>");
+                                    xml.append(MgUtil::ReplaceEscapeCharInXml(((MgStringProperty*)prop.p)->GetValue()));
+                                    xml.append(L"</Value>\n");
+                                }
+                                break;
+                            }
+                        }
+                        xml.append(L"</Property>\n");
+                    }
+                }
+                xml.append(L"</Feature>\n");
+            }
+        }
+    
+        //Now merge the bucketed fragments
+        for (std::map<STRING, STRING>::iterator it = bucket.begin(); it != bucket.end(); it++)
+        {
+            //Close off the <SelectedLayer> elements
+            STRING xml = it->second;
+            xml.append(L"</SelectedLayer>");
+            //Good to append to the final result
+            xmlOut.append(xml);
+        }
+    }
+}
+
+//////////////////////////////////////////////////////////////////
 // Generates JavaScript code that can be embedded in an HTML response
 // to a non-viewer initiated web application request. The returned code
 // forces a synchronization of the client-side view with any changes made to the Map Model.

Modified: trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Controller/HtmlController.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -112,7 +112,7 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
-    /// Processes a DescribeMapFeatures request from the Viewer
+    /// Processes a QueryMapFeatures request from the Viewer
     ///
     /// \param mapName
     /// Name of the map
@@ -142,6 +142,39 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Processes a QueryMapFeatures request from the Viewer
+    ///
+    /// \param mapName
+    /// Name of the map
+    /// \param layer
+    /// Layer for which to provide feature descriptions
+    /// \param selectionGeometry
+    /// Geometry defining which features to select
+    /// \param selectionVariant
+    /// Specifies how features are selected
+    /// \param maxFeatures
+    /// Max number of feature descriptions to return
+    /// \param persist
+    /// Indicates if the returned selection set should be persisted in the session repository
+    ///
+    /// \return
+    /// A byte reader containing the feature info
+    ///
+    MgByteReader* QueryMapFeatures(
+        CREFSTRING mapName,
+        MgStringCollection* layerNames,
+        MgGeometry* selectionGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        bool persist,
+        INT32 layerAttributeFilter,
+        INT32 requestData,
+        CREFSTRING selectionColor,
+        CREFSTRING selectionFormat);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Processes a GetLayerImageMap request from the Viewer and returns an image map
     /// for the visible features on the specified map layer
     ///
@@ -236,6 +269,17 @@
 
     //////////////////////////////////////////////////////////////////
     /// \brief
+    /// Assembles the composite QueryMapFeatures result
+    ///
+    virtual MgByteReader* CollectQueryMapFeaturesResult(MgResourceService* resourceService,
+                                                        INT32 requestData, 
+                                                        MgFeatureInformation* featInfo,
+                                                        MgSelection* selectionSet,
+                                                        MgBatchPropertyCollection* attributes, 
+                                                        MgByteReader* inlineSelection);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
     /// Dispose this object.
     ///
     /// \return
@@ -246,6 +290,12 @@
         delete this;
     }
 
+private:
+    static void WriteSelectedFeatureAttributes(MgResourceService* resourceService,
+                                               MgSelection* selectionSet,
+                                               MgBatchPropertyCollection* attriubtes,
+                                               REFSTRING xmlOut);
+
 CLASS_ID:
     static const INT32 m_cls_id = MapGuide_MapLayer_ZcvController;
 

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -803,6 +803,72 @@
     return (MgBatchPropertyCollection*)cmd.GetReturnValue().val.m_obj;
 }
 
+/////////////////////////////////////////////////////////////////
+/// \brief
+/// The QueryFeatureProperties operation identifies those features that
+/// meet the specified spatial selection criteria. This operation
+/// is used to implement WMS feature info and returns property values
+/// for all features which match the spatial query
+///
+/// \param map
+/// Input
+/// map object containing current state of map.
+/// \param layerNames
+/// Input
+/// Active layer names for which to query features
+/// \param filterGeometry
+/// Input
+/// geometry object specifying the selection area
+/// \param selectionVariant
+/// Input
+/// selection criterion - integer value corresponding to one of
+/// the MgFeatureSpatialOperations values
+/// \param featureFilter
+/// Input
+/// an XML selection string containing the required feature IDs
+/// \param maxFeatures
+/// Input
+/// the maximum number of features to return
+/// \param layerAttributeFilter
+/// Input
+/// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+///
+/// \return
+/// An MgSelection instance identifying the features that meet the
+/// selection criteria. Returns null if no features are identified.
+///
+MgBatchPropertyCollection* MgProxyRenderingService::QueryFeatureProperties(
+    MgMap* map,
+    MgStringCollection* layerNames,
+    MgGeometry* filterGeometry,
+    INT32 selectionVariant,
+    CREFSTRING featureFilter,
+    INT32 maxFeatures,
+    INT32 layerAttributeFilter,
+    bool bIncludeFeatureBBOX)
+{
+    MgCommand cmd;
+    cmd.ExecuteCommand(m_connProp,                                      // Connection
+                        MgCommand::knObject,                            // Return type expected
+                        MgRenderingServiceOpId::QueryFeatureProperties2,// Command Code
+                        8,                                              // No of arguments
+                        Rendering_Service,                              // Service Id
+                        BUILD_VERSION(2,6,0),                           // Operation version
+                        MgCommand::knObject, map,                       // Argument#1
+                        MgCommand::knObject, layerNames,                // Argument#2
+                        MgCommand::knObject, filterGeometry,            // Argument#3
+                        MgCommand::knInt32,  selectionVariant,          // Argument#4
+                        MgCommand::knString, &featureFilter,            // Argument#5
+                        MgCommand::knInt32,  maxFeatures,               // Argument#6
+                        MgCommand::knInt32,  layerAttributeFilter,      // Argument#7
+                        MgCommand::knInt8,   (INT8)bIncludeFeatureBBOX, // Argument#8
+                        MgCommand::knNone);                             // End of arguments
+
+    SetWarning(cmd.GetWarningObject());
+
+    return (MgBatchPropertyCollection*)cmd.GetReturnValue().val.m_obj;
+}
+
 //////////////////////////////////////////////////////////////////
 /// \brief
 /// Sets the connection properties for the Proxy Service.  This
@@ -937,4 +1003,4 @@
     SetWarning(cmd.GetWarningObject());
 
     return (MgByteReader*)cmd.GetReturnValue().val.m_obj;
-}
+}
\ No newline at end of file

Modified: trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Services/ProxyRenderingService.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -669,6 +669,50 @@
         bool bKeepSelection,
         ProfileRenderMapResult* profileRenderMapResult);
 
+    /////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The QueryFeatureProperties operation identifies those features that
+    /// meet the specified spatial selection criteria. This operation
+    /// is used to implement WMS feature info and returns property values
+    /// for all features which match the spatial query
+    ///
+    /// \param map
+    /// Input
+    /// map object containing current state of map.
+    /// \param layerNames
+    /// Input
+    /// Active layer names for which to query features
+    /// \param filterGeometry
+    /// Input
+    /// geometry object specifying the selection area
+    /// \param selectionVariant
+    /// Input
+    /// selection criterion - integer value corresponding to one of
+    /// the MgFeatureSpatialOperations values
+    /// \param featureFilter
+    /// Input
+    /// an XML selection string containing the required feature IDs
+    /// \param maxFeatures
+    /// Input
+    /// the maximum number of features to return
+    /// \param layerAttributeFilter
+    /// Input
+    /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    ///
+    /// \return
+    /// An MgSelection instance identifying the features that meet the
+    /// selection criteria. Returns null if no features are identified.
+    ///
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+        MgMap* map,
+        MgStringCollection* layerNames,
+        MgGeometry* filterGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        INT32 layerAttributeFilter,
+        bool bIncludeFeatureBBOX);
+
 protected:
 
     //////////////////////////////////////////////////////////////////

Modified: trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Services/RenderingDefs.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -39,6 +39,7 @@
     static const int RenderMap4                 = 0x1111E90B;
     static const int RenderDynamicOverlay2      = 0x1111E90C;
     static const int RenderMap5                 = 0x1111E90D;
+    static const int QueryFeatureProperties2    = 0x1111E90E;
 };
 /// \endcond
 

Modified: trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -48,3 +48,16 @@
 {
     delete this;
 }
+
+MgBatchPropertyCollection* MgRenderingService::QueryFeatureProperties(
+    MgMap* map,
+    MgStringCollection* layerNames,
+    MgGeometry* filterGeometry,
+    INT32 selectionVariant,
+    CREFSTRING featureFilter,
+    INT32 maxFeatures,
+    INT32 layerAttributeFilter,
+    bool bIncludeFeatureBBOX)
+{
+    throw new MgNotImplementedException(L"MgRenderingService.QueryFeatureProperties", __LINE__, __WFILE__, NULL, L"", NULL);
+}
\ No newline at end of file

Modified: trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Common/MapGuideCommon/Services/RenderingService.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -671,6 +671,50 @@
         bool bKeepSelection,
         ProfileRenderMapResult* profileRenderMapResult) = 0;
 
+    /////////////////////////////////////////////////////////////////
+    /// \brief
+    /// The QueryFeatureProperties operation identifies those features that
+    /// meet the specified spatial selection criteria. This operation
+    /// is used to implement WMS feature info and returns property values
+    /// for all features which match the spatial query
+    ///
+    /// \param map
+    /// Input
+    /// map object containing current state of map.
+    /// \param layerNames
+    /// Input
+    /// Active layer names for which to query features
+    /// \param filterGeometry
+    /// Input
+    /// geometry object specifying the selection area
+    /// \param selectionVariant
+    /// Input
+    /// selection criterion - integer value corresponding to one of
+    /// the MgFeatureSpatialOperations values
+    /// \param featureFilter
+    /// Input
+    /// an XML selection string containing the required feature IDs
+    /// \param maxFeatures
+    /// Input
+    /// the maximum number of features to return
+    /// \param layerAttributeFilter
+    /// Input
+    /// bitmask values - 1=Visible, 2=Selectable, 4=HasTooltips
+    ///
+    /// \return
+    /// An MgSelection instance identifying the features that meet the
+    /// selection criteria. Returns null if no features are identified.
+    ///
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+        MgMap* map,
+        MgStringCollection* layerNames,
+        MgGeometry* filterGeometry,
+        INT32 selectionVariant,
+        CREFSTRING featureFilter,
+        INT32 maxFeatures,
+        INT32 layerAttributeFilter,
+        bool bIncludeFeatureBBOX);
+
 protected:
 
     /////////////////////////////////////////////////////////////////

Modified: trunk/MgDev/Doc/viewerapi/index.htm
===================================================================
--- trunk/MgDev/Doc/viewerapi/index.htm	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Doc/viewerapi/index.htm	2013-05-24 14:47:52 UTC (rev 7519)
@@ -69,7 +69,9 @@
       <LI><A href="#mapframe_getmapwidth">GetMapWidth</A></LI>
       <LI><A href="#mapframe_getmetersperunit">GetMetersPerUnit</A></LI>
       <LI><A href="#mapframe_getscale">GetScale</A></LI>
+      <LI><A href="#mapframe_getselectedbounds">GetSelectedBounds</A></LI>
       <LI><A href="#mapframe_getselectedcount">GetSelectedCount</A></LI>
+      <LI><A href="#mapframe_getselectedfeatures">GetSelectedFeatures</A></LI>
       <LI><A href="#mapframe_getselectedlayers">GetSelectedLayers</A></LI>
       <LI><A href="#mapframe_getselectionxml">GetSelectionXML</A></LI>
       <LI><A href="#mapframe_getsessionid">GetSessionId</A></LI>
@@ -842,11 +844,74 @@
   </DL>
 
   <DL>
+    <DT><STRONG><A name="mapframe_getselectedbounds">GetSelectedBounds()</A></STRONG></DT>
+      <DD>
+      Returns the bounding box of the selected features. Returns null if no features are selected. The box is a <CODE>Bounds</CODE> object:
+<PRE>Bounds {
+  minx; /* The min x coordinate of this bounding box */
+  miny; /* The min y coordinate of this bounding box */
+  maxx; /* The max x coordinate of this bounding box */
+  maxy; /* The max y coordinate of this bounding box */
+}
+</PRE>
+      </DD>
+  </DL>
+
+  <DL>
     <DT><STRONG><A name="mapframe_getselectedcount">GetSelectedCount()</A></STRONG></DT>
       <DD>
       Returns the number of features that are currently selected.
       </DD>
   </DL>
+  
+  <DL>
+    <DT><STRONG><A name="mapframe_getselectedfeatures">GetSelectedFeatures()</A></STRONG></DT>
+      <DD>
+      Returns the selection set including attributes of selected features. The selection set is structured like so:
+<PRE>{
+    layerName1 : [
+    { //feature 1 in layerName1
+        values: [
+            { name: "attribute1", value: "value1" },
+            { name: "attribute2", value: "value2" },
+            { name: "attribute3", value: "value3" },
+            ...
+            { name: "attributeN", value: "valueN" }
+        ]
+        zoom: { minx: <feature1_bbox_minx>, miny: <feature1_bbox_miny>, maxx: <feature1_bbox_maxx>, maxy: <feature1_bbox_maxy> }
+    },
+    { //feature 2 in layerName1
+        values: [
+            { name: "attribute1", value: "value1" },
+            { name: "attribute2", value: "value2" },
+            { name: "attribute3", value: "value3" },
+            ...
+            { name: "attributeN", value: "valueN" }
+        ]
+        zoom: { minx: <feature2_bbox_minx>, miny: <feature2_bbox_miny>, maxx: <feature2_bbox_maxx>, maxy: <feature2_bbox_maxy> }
+    },
+    ...,
+    { //feature N in layerName1
+        values: [
+            { name: "attribute1", value: "value1" },
+            { name: "attribute2", value: "value2" },
+            { name: "attribute3", value: "value3" },
+            ...
+            { name: "attributeN", value: "valueN" }
+        ]
+        zoom: { minx: <featureN_bbox_minx>, miny: <featureN_bbox_miny>, maxx: <featureN_bbox_maxx>, maxy: <featureN_bbox_maxy> }
+    }
+    ], layerName2 : [
+        ...
+    ], 
+    ..., 
+    layerNameN : [
+        ...
+    ]
+}
+</PRE>
+      </DD>
+  </DL>
 
   <DL>
     <DT><STRONG><A name="mapframe_isdigitizing">IsDigitizing()</A></STRONG></DT>

Modified: trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -21,17 +21,22 @@
 #include "FeaturePropRenderer.h"
 #include "RS_FeatureReader.h"
 
+#define SPECIAL_PROP_LAYER_NAME     L"_MgLayerName"
+#define SPECIAL_PROP_BOUNDING_BOX   L"_MgFeatureBoundingBox"
 
-FeaturePropRenderer::FeaturePropRenderer(MgSelection* selection, int maxFeatures, double mapScale)
+FeaturePropRenderer::FeaturePropRenderer(MgSelection* selection, int maxFeatures, double mapScale, bool bIncludeFeatureBBOX)
 : FeatureInfoRenderer(selection, maxFeatures, mapScale)
 {
     m_featprops = new MgBatchPropertyCollection();
+    m_currentFeature = NULL;
+    m_bIncludeFeatureBBOX = bIncludeFeatureBBOX;
 }
 
 
 FeaturePropRenderer::~FeaturePropRenderer()
 {
     SAFE_RELEASE(m_featprops);
+    SAFE_RELEASE(m_currentFeature);
 }
 
 
@@ -69,12 +74,21 @@
     }
     */
 
+    SAFE_RELEASE(m_currentFeature);
     Ptr<MgPropertyCollection> featureProps = new MgPropertyCollection(true, true);
+    m_currentFeature = SAFE_ADDREF(featureProps.p);
 
     //Add the layer name as a property with a special ID
-    Ptr<MgStringProperty> layerNameProperty = new MgStringProperty(L"_MgLayerName", m_layerInfo->name());
+    Ptr<MgStringProperty> layerNameProperty = new MgStringProperty(SPECIAL_PROP_LAYER_NAME, m_layerInfo->name());
     featureProps->Add(layerNameProperty);
 
+    //Add bounding box if we're instructed to
+    if (m_bIncludeFeatureBBOX)
+    {
+        Ptr<MgStringProperty> boundingBoxProperty = new MgStringProperty(SPECIAL_PROP_BOUNDING_BOX, L"");
+        featureProps->Add(boundingBoxProperty);
+    }
+
     //for each property in the property mapping, add to the
     //return property collection
 
@@ -109,3 +123,78 @@
     // set to false to disable processing of hyperlinks
     return false;
 }
+
+void FeaturePropRenderer::ProcessPolygon(LineBuffer*   lb,
+                                         RS_FillStyle& fill)
+{
+    if (!m_bIncludeFeatureBBOX)
+        return;
+
+    const RS_Bounds& featBounds = lb->bounds();
+    Ptr<MgStringProperty> bbox = dynamic_cast<MgStringProperty*>(m_currentFeature->GetItem(SPECIAL_PROP_BOUNDING_BOX));
+    STRING val;
+    STRING buf;
+    MgUtil::DoubleToString(featBounds.minx, buf);
+    val += buf;
+    MgUtil::DoubleToString(featBounds.miny, buf);
+    val += L" ";
+    val += buf;
+    MgUtil::DoubleToString(featBounds.maxx, buf);
+    val += L" ";
+    val += buf;
+    MgUtil::DoubleToString(featBounds.maxy, buf);
+    val += L" ";
+    val += buf;
+    bbox->SetValue(val);
+}
+
+void FeaturePropRenderer::ProcessPolyline(LineBuffer*    lb,
+                                          RS_LineStroke& lsym)
+{
+    if (!m_bIncludeFeatureBBOX)
+        return;
+
+    const RS_Bounds& featBounds = lb->bounds();
+    Ptr<MgStringProperty> bbox = dynamic_cast<MgStringProperty*>(m_currentFeature->GetItem(SPECIAL_PROP_BOUNDING_BOX));
+    STRING val;
+    STRING buf;
+    MgUtil::DoubleToString(featBounds.minx, buf);
+    val += buf;
+    MgUtil::DoubleToString(featBounds.miny, buf);
+    val += L" ";
+    val += buf;
+    MgUtil::DoubleToString(featBounds.maxx, buf);
+    val += L" ";
+    val += buf;
+    MgUtil::DoubleToString(featBounds.maxy, buf);
+    val += L" ";
+    val += buf;
+    bbox->SetValue(val);
+}
+
+void FeaturePropRenderer::ProcessMarker(LineBuffer*   lb,
+                                        RS_MarkerDef& mdef,
+                                        bool          allowOverpost,
+                                        RS_Bounds*    bounds)
+{
+    if (!m_bIncludeFeatureBBOX)
+        return;
+
+    //Should we inflate this a bit to represent an actual box?
+    const RS_Bounds& featBounds = lb->bounds();
+    Ptr<MgStringProperty> bbox = dynamic_cast<MgStringProperty*>(m_currentFeature->GetItem(SPECIAL_PROP_BOUNDING_BOX));
+    STRING val;
+    STRING buf;
+    MgUtil::DoubleToString(featBounds.minx, buf);
+    val += buf;
+    MgUtil::DoubleToString(featBounds.miny, buf);
+    val += L" ";
+    val += buf;
+    MgUtil::DoubleToString(featBounds.maxx, buf);
+    val += L" ";
+    val += buf;
+    MgUtil::DoubleToString(featBounds.maxy, buf);
+    val += L" ";
+    val += buf;
+    bbox->SetValue(val);
+}
\ No newline at end of file

Modified: trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/Services/Rendering/FeaturePropRenderer.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -31,7 +31,8 @@
 public:
     FeaturePropRenderer(MgSelection* selection,
                         int maxFeatures,
-                        double mapScale);
+                        double mapScale,
+                        bool bIncludeFeatureBBOX);
     virtual ~FeaturePropRenderer();
 
     ///////////////////////////////////
@@ -49,6 +50,17 @@
     virtual bool SupportsTooltips();
     virtual bool SupportsHyperlinks();
 
+    virtual void ProcessPolygon(LineBuffer*   lb,
+                                RS_FillStyle& fill);
+
+    virtual void ProcessPolyline(LineBuffer*    lb,
+                                 RS_LineStroke& lsym);
+
+    virtual void ProcessMarker(LineBuffer*   lb,
+                               RS_MarkerDef& mdef,
+                               bool          allowOverpost,
+                               RS_Bounds*    bounds = NULL);
+
     MgBatchPropertyCollection* GetProperties()
     {
         return SAFE_ADDREF(m_featprops);
@@ -56,6 +68,8 @@
 
 private:
     MgBatchPropertyCollection* m_featprops;
+    MgPropertyCollection* m_currentFeature;
+    bool m_bIncludeFeatureBBOX;
 };
 
 #endif

Modified: trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/Services/Rendering/OpQueryFeatureProperties.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -60,7 +60,7 @@
 
     ACE_ASSERT(m_stream != NULL);
 
-    if (7 == m_packet.m_NumArguments)
+    if (7 == m_packet.m_NumArguments || 8 == m_packet.m_NumArguments)
     {
         Ptr<MgMap> map = (MgMap*)m_stream->GetObject();
         Ptr<MgResourceIdentifier> resource = map->GetResourceId();
@@ -81,6 +81,11 @@
         INT32 layerAttributeFilter = 3;
         m_stream->GetInt32(layerAttributeFilter);
 
+        bool bIncludeFeatureBBOX = false;
+        if (8 == m_packet.m_NumArguments)
+        {
+            m_stream->GetBoolean(bIncludeFeatureBBOX);
+        }
         BeginExecution();
 
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
@@ -97,14 +102,26 @@
         MG_LOG_OPERATION_MESSAGE_ADD_INT32(maxFeatures);
         MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
         MG_LOG_OPERATION_MESSAGE_ADD_INT32(layerAttributeFilter);
+        if (8 == m_packet.m_NumArguments)
+        {
+            MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+            MG_LOG_OPERATION_MESSAGE_ADD_BOOL(bIncludeFeatureBBOX);
+        }
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
 
         Validate();
 
-        Ptr<MgBatchPropertyCollection> info =
-            m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
-            featureFilter, maxFeatures, layerAttributeFilter);
-
+        Ptr<MgBatchPropertyCollection> info;
+        if (8 == m_packet.m_NumArguments)
+        {
+            info = m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
+                featureFilter, maxFeatures, layerAttributeFilter, bIncludeFeatureBBOX);
+        }
+        else
+        {
+            info = m_service->QueryFeatureProperties(map, layerNames, geom, selectionVariant,
+                featureFilter, maxFeatures, layerAttributeFilter);
+        }
         EndExecution(info);
     }
     else

Modified: trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/Services/Rendering/RenderingOperationFactory.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -180,6 +180,17 @@
                 L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
         }
         break;
+    case MgRenderingServiceOpId::QueryFeatureProperties2:
+        switch (VERSION_NO_PHASE(operationVersion))
+        {
+        case VERSION_SUPPORTED(2,6):
+            handler.reset(new MgOpQueryFeatureProperties());
+            break;
+        default:
+            throw new MgInvalidOperationVersionException(
+                L"MgRenderingOperationFactory.GetOperation", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+        break;
     case MgRenderingServiceOpId::RenderMapLegend:
         switch (VERSION_NO_PHASE(operationVersion))
         {

Modified: trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -864,10 +864,9 @@
                                                                             INT32 maxFeatures)
 {
     // Call updated QueryFeatureProperties API
-    return QueryFeatureProperties(map, layerNames, filterGeometry, selectionVariant, L"", maxFeatures, 3 /*visible and selectable*/);
+    return QueryFeatureProperties(map, layerNames, filterGeometry, selectionVariant, L"", maxFeatures, 3 /*visible and selectable*/, false);
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////
 MgBatchPropertyCollection* MgServerRenderingService::QueryFeatureProperties(MgMap* map,
                                                                             MgStringCollection* layerNames,
@@ -877,6 +876,19 @@
                                                                             INT32 maxFeatures,
                                                                             INT32 layerAttributeFilter)
 {
+    return QueryFeatureProperties(map, layerNames, filterGeometry, selectionVariant, L"", maxFeatures, layerAttributeFilter, false);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+MgBatchPropertyCollection* MgServerRenderingService::QueryFeatureProperties(MgMap* map,
+                                                                            MgStringCollection* layerNames,
+                                                                            MgGeometry* filterGeometry,
+                                                                            INT32 selectionVariant, // Within, Touching, Topmost
+                                                                            CREFSTRING featureFilter,
+                                                                            INT32 maxFeatures,
+                                                                            INT32 layerAttributeFilter,
+                                                                            bool bIncludeFeatureBBOX)
+{
     Ptr<MgBatchPropertyCollection> ret;
 
     MG_TRY()
@@ -886,7 +898,7 @@
         maxFeatures = INT_MAX;
 
     Ptr<MgSelection> sel;   //TODO: do we need this for this API? new MgSelection(map);
-    FeaturePropRenderer fpr(sel, maxFeatures, map->GetViewScale());
+    FeaturePropRenderer fpr(sel, maxFeatures, map->GetViewScale(), bIncludeFeatureBBOX);
 
     RenderForSelection(map, layerNames, filterGeometry, selectionVariant, featureFilter, maxFeatures, layerAttributeFilter, &fpr);
 

Modified: trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h
===================================================================
--- trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/Services/Rendering/ServerRenderingService.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -173,6 +173,16 @@
                                         INT32 maxFeatures,
                                         INT32 layerAttributeFilter);
 
+    virtual MgBatchPropertyCollection* QueryFeatureProperties(
+                                        MgMap* map,
+                                        MgStringCollection* layerNames,
+                                        MgGeometry* filterGeometry,
+                                        INT32 selectionVariant,
+                                        CREFSTRING featureFilter,
+                                        INT32 maxFeatures,
+                                        INT32 layerAttributeFilter,
+                                        bool bIncludeFeatureBBOX);
+
 private:
     // used for tile generation
     MgByteReader* RenderTile(MgMap* map,

Modified: trunk/MgDev/Server/src/UnitTesting/TestRenderingService.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestRenderingService.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Server/src/UnitTesting/TestRenderingService.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -796,6 +796,10 @@
         Ptr<MgPolygon> poly1 = CreateSelectionPolygon(map, 0.3, 0.3);
         Ptr<MgFeatureInformation> fi1 = m_svcRendering->QueryFeatures(map, layerNames1, poly1, MgFeatureSpatialOperations::Within, -1);
 
+        Ptr<MgByteReader> br1 = fi1->ToXml();
+        Ptr<MgByteSink> sink1 = new MgByteSink(br1);
+        sink1->ToFile(L"../UnitTestFiles/QueryFeatures75k.xml");
+
         // call the API using a scale of 12000
         map->SetViewScale(12000.0);
 
@@ -804,6 +808,10 @@
         layerNames2->Add(L"Parcels");
         Ptr<MgPolygon> poly2 = CreateSelectionPolygon(map, 0.05, 0.05);
         Ptr<MgFeatureInformation> fi2 = m_svcRendering->QueryFeatures(map, layerNames2, poly2, MgFeatureSpatialOperations::Within, -1);
+
+        Ptr<MgByteReader> br2 = fi2->ToXml();
+        Ptr<MgByteSink> sink2 = new MgByteSink(br2);
+        sink2->ToFile(L"../UnitTestFiles/QueryFeatures12k.xml");
     }
     catch (MgException* e)
     {

Modified: trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -70,6 +70,17 @@
 
     // Get the feature filter
     m_featureFilter = params->GetParameterValue(MgHttpResourceStrings::reqRenderingFeatureFilter);
+
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version == MG_API_VERSION(2,6,0))
+    {
+        m_requestData = 0;
+        STRING strReqData = params->GetParameterValue(MgHttpResourceStrings::reqRenderingRequestData);
+        if (!strReqData.empty())
+            m_requestData = MgUtil::StringToInt32(strReqData);
+        m_selectionFormat = params->GetParameterValue(MgHttpResourceStrings::reqRenderingSelectionFormat);
+        m_selectionColor = params->GetParameterValue(MgHttpResourceStrings::reqRenderingSelectionColor);
+    }
 }
 
 /// <summary>
@@ -120,9 +131,17 @@
 
     // Call the HTML controller to process the request
     MgHtmlController controller(m_siteConn);
-    Ptr<MgByteReader> featureDescriptionInfo = controller.QueryMapFeatures(
-        m_mapName, layerNames, filterGeometry, selectionVariant, m_featureFilter, m_maxFeatures, m_persist, m_layerAttributeFilter);
-
+    Ptr<MgByteReader> featureDescriptionInfo;
+    
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version == MG_API_VERSION(1, 0, 0))
+    {
+        featureDescriptionInfo = controller.QueryMapFeatures(m_mapName, layerNames, filterGeometry, selectionVariant, m_featureFilter, m_maxFeatures, m_persist, m_layerAttributeFilter);
+    }
+    else if (version == MG_API_VERSION(2, 6, 0))
+    {
+        featureDescriptionInfo = controller.QueryMapFeatures(m_mapName, layerNames, filterGeometry, selectionVariant, m_featureFilter, m_maxFeatures, m_persist, m_layerAttributeFilter, m_requestData, m_selectionColor, m_selectionFormat);
+    }
     //Convert to alternate response format, if necessary
     ProcessFormatConversion(featureDescriptionInfo);
 
@@ -131,3 +150,24 @@
 
     MG_HTTP_HANDLER_CATCH_AND_THROW_EX(L"MgHttpQueryMapFeatures.Execute")
 }
+
+/// <summary>
+/// This method is responsible for checking if
+/// a valid version was given
+/// </summary>
+/// <returns>Returns nothing</returns>
+void MgHttpQueryMapFeatures::ValidateOperationVersion()
+{
+    MG_HTTP_HANDLER_TRY()
+
+    // There are multiple supported versions
+    INT32 version = m_userInfo->GetApiVersion();
+    if (version != MG_API_VERSION(1,0,0) &&
+        version != MG_API_VERSION(2,6,0))
+    {
+        throw new MgInvalidOperationVersionException(
+        L"MgHttpQueryMapFeatures.ValidateOperationVersion", __LINE__, __WFILE__, NULL, L"", NULL);
+    }
+
+    MG_HTTP_HANDLER_CATCH_AND_THROW(L"MgHttpQueryMapFeatures.ValidateOperationVersion");
+}

Modified: trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/HttpHandler/HttpQueryMapFeatures.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -51,6 +51,9 @@
     /// </returns>
     MgRequestClassification GetRequestClassification() { return MgHttpRequestResponseHandler::mrcViewer; }
 
+protected:
+    virtual void ValidateOperationVersion();
+
 private:
     STRING  m_mapName;
     STRING  m_layerNames;
@@ -60,6 +63,11 @@
     INT32   m_maxFeatures;
     INT32   m_layerAttributeFilter;
     bool    m_persist;
+
+    //New for 2.6
+    INT32   m_requestData;
+    STRING  m_selectionColor;
+    STRING  m_selectionFormat;
 };
 
 #endif  // _FS_DESCRIBE_MAP_FEATURES_H

Modified: trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.cpp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -230,6 +230,9 @@
 const STRING MgHttpResourceStrings::reqRenderingSelectionVariant = L"SELECTIONVARIANT";
 const STRING MgHttpResourceStrings::reqRenderingGeometry = L"GEOMETRY";
 const STRING MgHttpResourceStrings::reqRenderingFeatureFilter = L"FEATUREFILTER";
+const STRING MgHttpResourceStrings::reqRenderingRequestData = L"REQUESTDATA";
+const STRING MgHttpResourceStrings::reqRenderingSelectionFormat = L"SELECTIONFORMAT";
+
 const STRING MgHttpResourceStrings::reqRenderingBaseMapLayerGroupName = L"BASEMAPLAYERGROUPNAME";
 const STRING MgHttpResourceStrings::reqRenderingTileColumn = L"TILECOL";
 const STRING MgHttpResourceStrings::reqRenderingTileRow = L"TILEROW";

Modified: trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h
===================================================================
--- trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/HttpHandler/HttpResourceStrings.h	2013-05-24 14:47:52 UTC (rev 7519)
@@ -177,6 +177,8 @@
     static const STRING reqRenderingClip;
     static const STRING reqRenderingBehavior;
     static const STRING reqRenderingSelectionColor;
+    static const STRING reqRenderingRequestData;
+    static const STRING reqRenderingSelectionFormat;
 
     // PREDEFINED TILE REQUEST PARAMETERS
     static const STRING reqTileMapDefinition;

Modified: trunk/MgDev/Web/src/localized/en
===================================================================
--- trunk/MgDev/Web/src/localized/en	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/localized/en	2013-05-24 14:47:52 UTC (rev 7519)
@@ -254,11 +254,9 @@
 
 # Property Pane Toolbar
 ZOOMSELECTEDFEATUREDESC = Zoom to this feature
-NOFEATSELECTRESPONSE    = No response from feature selection request
 
 # Multiple Property Processing
 SERVERERROR             = Server Error
-ERRORSTACKTRACE         = Stack Trace
 
 # Quick Plot
 QUICKPLOT_HEADER        = Quick Plot

Deleted: trunk/MgDev/Web/src/mapviewerjava/getselectedfeatures.jsp
===================================================================
--- trunk/MgDev/Web/src/mapviewerjava/getselectedfeatures.jsp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/mapviewerjava/getselectedfeatures.jsp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -1,449 +0,0 @@
-<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
-<%@ page import="org.osgeo.mapguide.*" %>
-<%@ page import="java.util.*" %>
-<%@ page import="java.lang.*" %>
-<%@ page import="java.io.*" %>
-<%@ page import="java.text.*" %>
-<%@ page import="javax.xml.parsers.DocumentBuilder" %>
-<%@ page import="javax.xml.parsers.DocumentBuilderFactory" %>
-<%@ page import="org.w3c.dom.Document" %>
-<%@ page import="org.w3c.dom.Element" %>
-<%@ page import="org.w3c.dom.Node" %>
-<%@ page import="org.w3c.dom.NodeList" %>
-<%@ page import="javax.servlet.jsp.*" %>
-<%@ page import="javax.servlet.http.*" %>
-<%@ include file="common.jsp" %>
-<%@ page isThreadSafe="false" %>
-<%!
-
-    String mapName;
-    String sessionId;
-    String localeCode;
-    Locale locale;
-
-    class SelectionSet
-    {
-        private HashMap<String, Vector<Feature>> _layers;
-
-        public SelectionSet()
-        {
-            _layers = new HashMap<String, Vector<Feature>>();
-        }
-
-        public void addFeature(Feature feat)
-        {
-            if (!_layers.containsKey(feat.LayerName))
-                _layers.put(feat.LayerName, new Vector<Feature>());
-
-            _layers.get(feat.LayerName).add(feat);
-        }
-
-        public String[] getLayers()
-        {
-            String[] layers = new String[_layers.keySet().size()];
-            _layers.keySet().toArray(layers);
-
-            return layers;
-        }
-
-        public Feature[] getFeatures(String layerName)
-        {
-            if (_layers.containsKey(layerName))
-            {
-                Vector<Feature> layerFeatures = _layers.get(layerName);
-                Feature[] feats = new Feature[layerFeatures.size()];
-                layerFeatures.toArray(feats);
-                return feats;
-            }
-
-            return null;
-        }
-    }
-
-    class ZoomBox
-    {
-        public double MinX;
-        public double MinY;
-        public double MaxX;
-        public double MaxY;
-    }
-
-    class FeatureProperty
-    {
-        public String Name;
-        public String Value;
-    }
-
-    class Feature
-    {
-        public String LayerName;
-        public ZoomBox Zoom;
-
-        private HashMap<String, FeatureProperty> _properties;
-
-        public Feature(String layerName)
-        {
-            this.LayerName = layerName;
-            _properties = new HashMap<String, FeatureProperty>();
-        }
-
-        public void addProperty(FeatureProperty prop)
-        {
-            _properties.put(prop.Name, prop);
-        }
-
-        public FeatureProperty[] getProperties()
-        {
-            Collection<FeatureProperty> values = _properties.values();
-            FeatureProperty[] props = new FeatureProperty[values.size()];
-            values.toArray(props);
-            return props;
-        }
-    }
-
-    static String getTextValue(Element el, String tagName)
-    {
-        String textVal = null;
-        NodeList nl = el.getElementsByTagName(tagName);
-        if (nl != null && nl.getLength() > 0)
-        {
-            Element e = (Element)nl.item(0);
-            textVal = e.getFirstChild().getNodeValue();
-        }
-        return textVal;
-    }
-
-    static HashMap<String, String> GetLayerPropertyMappings(MgResourceService resSvc, MgLayerBase layer) throws Exception
-    {
-        HashMap<String, String> mappings = new HashMap<String, String>();
-
-        MgByteReader content = resSvc.GetResourceContent(layer.GetLayerDefinition());
-        ByteArrayInputStream contentReader = new ByteArrayInputStream(content.ToString().getBytes("UTF-8"));
-
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        DocumentBuilder db = dbf.newDocumentBuilder();
-        Document doc = db.parse(contentReader);
-
-        doc.getDocumentElement().normalize();
-        NodeList propNodes = doc.getElementsByTagName("PropertyMapping");
-
-        for (int i = 0; i < propNodes.getLength(); i++)
-        {
-            Element propEl = (Element)propNodes.item(i);
-            String name = getTextValue(propEl, "Name");
-            String value = getTextValue(propEl, "Value");
-
-            if (name != null && value != null)
-                mappings.put(name, value);
-        }
-
-        return mappings;
-    }
-
-    String GetPropertyValueFromFeatureReader(MgFeatureReader reader, MgAgfReaderWriter agfRw, int propType, String propName) throws Exception
-    {
-        String value = "";
-        switch(propType)
-        {
-            case MgPropertyType.Boolean:
-                value = String.format(locale, "%s", reader.GetBoolean(propName));
-                break;
-            case MgPropertyType.Byte:
-                value = String.format(locale, "%d", reader.GetByte(propName));
-                break;
-            case MgPropertyType.DateTime:
-                value = GetDateTimeString(reader.GetDateTime(propName)); // yyyy-mm-dd is enforced regardless of locale
-                break;
-            case MgPropertyType.Single:
-                value = String.format(locale, "%f", reader.GetSingle(propName));
-                break;
-            case MgPropertyType.Double:
-                value = String.format(locale, "%f", reader.GetDouble(propName));
-                break;
-            case MgPropertyType.Int16:
-                value = String.format(locale, "%d", reader.GetInt16(propName));
-                break;
-            case MgPropertyType.Int32:
-                value = String.format(locale, "%d", reader.GetInt32(propName));
-                break;
-            case MgPropertyType.Int64:
-                value = String.format(locale, "%d", reader.GetInt64(propName));
-                break;
-            case MgPropertyType.String:
-                value = JsonEscape(reader.GetString(propName)); // string content is arbitrary
-                value = value.replaceAll("\\s+", " ").trim();
-                break;
-            default: //NOT PRESENTABLE IN PROPERTY GRID
-                value = "";
-                break;
-        }
-        return value;
-    }
-
-    static String GetDateTimeString(MgDateTime value) throws MgException
-    {
-        return value.GetYear() + "-" + value.GetMonth() + "-" + value.GetDay();
-    }
-
-    void GetParameters(HttpServletRequest request)
-    {
-        mapName = GetParameter(request, "MAPNAME");
-        sessionId = GetParameter(request, "SESSION");
-        localeCode = GetParameter(request, "LOCALE");
-    }
-
-    String JsonEscape(String str)
-    {
-        return EscapeForHtml(str).replace("\\", "\\\\");
-    }
-
-    String JsonifyError(Exception ex)
-    {
-        if (ex == null)
-            return "";
-        /*
-        {
-            "Error" : {
-                "Message" : <exception-message>,
-                "StackTrace" : <exception-stack-trace>
-            }
-        }
-        */
-
-        StringBuffer sb = new StringBuffer();
-        //Use exception message or type name if no message found
-        String msg = ex.getMessage();
-        if (msg == null || msg.length() == 0)
-        {
-            msg = MgLocalizer.GetString("SERVERERROR", localeCode);
-        }
-        //Begin response
-        sb.append("{\"Error\":{");
-        //Exception message
-        sb.append("\"Message\":\"" + JsonEscape(msg) + "\",");
-        StringBuffer strace = new StringBuffer();
-        StackTraceElement[] st = ex.getStackTrace();
-        for (int i = 0; i < st.length; i++)
-        {
-            strace.append(st[i].getClassName() + "." + st[i].getMethodName() + "(" + st[i].getLineNumber() + ")\\n");
-        }
-        sb.append("\"StackTrace\":\"" + JsonEscape(strace.toString()) + "\"");
-        //End response
-        sb.append("}}");
-        return sb.toString();
-    }
-
-    static String GetJson(SelectionSet set)
-    {
-        /*
-        A sample of the JSON output this method will produce:
-
-
-        {
-            "Layer1" : [
-                {
-                    'values' { "name" : "name1" , "value" : "value1" },
-                    'zoom' : { x: num1, y: num2 }
-                } ,
-                ..,
-                ..,
-                ..,
-            ],
-            "Layer2" : [
-                {
-                    'values' { "name" : "name2" , "value" : "value2" },
-                    'zoom' : { x: num1, y: num2 }
-                } ,
-                ..,
-                ..,
-                ..,
-            ]
-        }
-        */
-
-        if (set == null)
-            return "";
-
-        StringBuffer sb = new StringBuffer();
-        //Begin selection set
-        sb.append("{");
-        String[] layers = set.getLayers();
-        for (int i = 0; i < layers.length; i++)
-        {
-            //Begin layer
-            sb.append("\"" + layers[i] + "\" : [");
-            Feature[] features = set.getFeatures(layers[i]);
-            for (int j = 0; j < features.length; j++)
-            {
-                Feature feat = features[j];
-                //begin feature
-                //begin feature properties
-                sb.append("{\"values\" : [");
-                FeatureProperty[] properties = feat.getProperties();
-                for(int k = 0; k < properties.length; k++)
-                {
-                    FeatureProperty fp = properties[k];
-                    sb.append("{\"name\" : \"" + fp.Name + "\", \"value\" : \"" + fp.Value + "\" }");
-                    if (k != properties.length - 1)
-                        sb.append(",");
-                }
-                //end feature properties
-                //begin zoom
-                sb.append("], \"zoom\" : ");
-                if (feat.Zoom == null)
-                    sb.append("null");
-                else
-                    sb.append(String.format(Locale.ROOT, "{\"minx\" : %f, \"miny\" : %f, \"maxx\" : %f, \"maxy\" : %f }", feat.Zoom.MinX, feat.Zoom.MinY, feat.Zoom.MaxX, feat.Zoom.MaxY));
-                //end zoom
-                //end feature
-                sb.append("}");
-                if (j != features.length - 1)
-                    sb.append(",");
-            }
-            //End Layer
-            sb.append("]");
-            if (i != layers.length - 1)
-                sb.append(",");
-        }
-        //End selection set
-        sb.append("}");
-        return sb.toString();
-    }
-%>
-<%
-    mapName = "";
-    sessionId = "";
-    localeCode = "";
-
-    GetParameters(request);
-
-    if (null == localeCode || localeCode.length() == 0)
-        localeCode = GetDefaultLocale();
-
-    locale = new Locale(localeCode);
-
-    try
-    {
-        MgUserInformation cred = new MgUserInformation(sessionId);
-        cred.SetClientIp(GetClientIp(request));
-        cred.SetClientAgent(GetClientAgent());
-
-        MgSiteConnection site = new MgSiteConnection();
-        site.Open(cred);
-
-        MgResourceService resSvc = (MgResourceService)site.CreateService(MgServiceType.ResourceService);
-
-        MgMap map = new MgMap(site);
-        map.Open(mapName);
-
-        MgSelection selection = new MgSelection(map);
-        selection.Open(resSvc, mapName);
-
-        MgReadOnlyLayerCollection layers = selection.GetLayers();
-        if (layers != null && layers.GetCount() > 0)
-        {
-            int layerCount = layers.GetCount();
-            MgAgfReaderWriter agfRW = new MgAgfReaderWriter();
-            SelectionSet selectionSet = new SelectionSet();
-
-            for (int i = 0; i < layerCount; i++)
-            {
-                MgLayerBase layer = layers.GetItem(i);
-                String layerName = layer.GetName();
-
-                MgResourceIdentifier fsId = new MgResourceIdentifier(layer.GetFeatureSourceId());
-                String className = layer.GetFeatureClassName();
-                String geomName = layer.GetFeatureGeometryName();
-
-                MgFeatureQueryOptions query = new MgFeatureQueryOptions();
-                HashMap<String, String> mappings = GetLayerPropertyMappings(resSvc, layer);
-                Set<String> propNames = mappings.keySet();
-
-                for (String name : propNames)
-                {
-                    query.AddFeatureProperty(name);
-                }
-
-                query.AddFeatureProperty(geomName);
-                String filter = selection.GenerateFilter(layer, className);
-                query.SetFilter(filter);
-
-                MgFeatureReader reader = layer.SelectFeatures(query);
-
-                MgClassDefinition clsDef = reader.GetClassDefinition();
-                MgPropertyDefinitionCollection props = clsDef.GetProperties();
-
-                while (reader.ReadNext())
-                {
-                    Feature feat = new Feature(layerName);
-                    ZoomBox zoom = null;
-
-                    for (int k = 0; k < props.GetCount(); k++)
-                    {
-                        MgPropertyDefinition propDef = props.GetItem(k);
-                        String propName = propDef.GetName();
-                        int propType = reader.GetPropertyType(propName);
-
-                        if (mappings.get(propName) != null || propType == MgPropertyType.Geometry)
-                        {
-                            String value = "";
-                            if (!reader.IsNull(propName))
-                            {
-                                if (propName.equals(geomName))
-                                {
-                                    MgByteReader agf = reader.GetGeometry(propName);
-                                    MgGeometry geom = agfRW.Read(agf);
-
-                                    MgEnvelope env = geom.Envelope();
-                                    MgCoordinate ll = env.GetLowerLeftCoordinate();
-                                    MgCoordinate ur = env.GetUpperRightCoordinate();
-
-                                    zoom = new ZoomBox();
-                                    zoom.MinX = ll.GetX();
-                                    zoom.MinY = ll.GetY();
-                                    zoom.MaxX = ur.GetX();
-                                    zoom.MaxY = ur.GetY();
-
-                                    feat.Zoom = zoom;
-                                }
-                                else
-                                {
-                                    value = GetPropertyValueFromFeatureReader(reader, agfRW, propType, propName);
-                                }
-
-                                if (mappings.get(propName) != null)
-                                {
-                                    FeatureProperty fp = new FeatureProperty();
-                                    fp.Name = mappings.get(propName);
-                                    fp.Value = value;
-
-                                    feat.addProperty(fp);
-                                }
-                            }
-                        }
-                    }
-                    selectionSet.addFeature(feat);
-                }
-                reader.Close();
-            }
-
-            //Now output the selection set
-            response.addHeader("Content-Type", "application/json");
-            response.addHeader("X-JSON", "true");
-
-            response.getWriter().write(GetJson(selectionSet));
-        }
-    }
-    catch (MgException ex)
-    {
-        response.addHeader("Content-Type", "application/json");
-        response.addHeader("X-JSON", "true");
-        response.getWriter().write(JsonifyError(ex));
-    }
-    catch (Exception ex)
-    {
-        response.addHeader("Content-Type", "application/json");
-        response.addHeader("X-JSON", "true");
-        response.getWriter().write(JsonifyError(ex));
-    }
-%>

Modified: trunk/MgDev/Web/src/mapviewerjava/mapframe.jsp
===================================================================
--- trunk/MgDev/Web/src/mapviewerjava/mapframe.jsp	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/mapviewerjava/mapframe.jsp	2013-05-24 14:47:52 UTC (rev 7519)
@@ -180,7 +180,6 @@
                     vpath + "setselection.jsp",
                     showSlider != 0? "true": "false",
                     locale,
-                    vpath + "getselectedfeatures.jsp",
                     scaleCreationCode,
                     selectionColor,
                     mapImgFormat,

Deleted: trunk/MgDev/Web/src/mapviewernet/getselectedfeatures.aspx
===================================================================
--- trunk/MgDev/Web/src/mapviewernet/getselectedfeatures.aspx	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/mapviewernet/getselectedfeatures.aspx	2013-05-24 14:47:52 UTC (rev 7519)
@@ -1,397 +0,0 @@
-<%@ Page Language="C#" %>
-<%@ Import Namespace="System" %>
-<%@ Import Namespace="System.IO" %>
-<%@ Import Namespace="System.Collections.Generic" %>
-<%@ Import Namespace="System.Web" %>
-<%@ Import Namespace="System.Xml" %>
-<%@ Import Namespace="System.Globalization" %>
-<%@ Import Namespace="OSGeo.MapGuide" %>
-<!-- #include File="common.aspx" -->
-
-<script runat="server">
-
-    class SelectionSet
-    {
-        private Dictionary<string, List<Feature>> _layers;
-
-        public SelectionSet()
-        {
-            _layers = new Dictionary<String, List<Feature>>();
-        }
-
-        public void AddFeature(Feature feat)
-        {
-            if (!_layers.ContainsKey(feat.LayerName))
-                _layers[feat.LayerName] = new List<Feature>();
-
-            _layers[feat.LayerName].Add(feat);
-        }
-
-        public String[] GetLayers()
-        {
-            return new List<String>(_layers.Keys).ToArray();
-        }
-
-        public Feature[] GetFeatures(String layerName)
-        {
-            if (_layers.ContainsKey(layerName))
-                return _layers[layerName].ToArray();
-
-            return null;
-        }
-    }
-
-    class ZoomBox
-    {
-        public double MinX;
-        public double MinY;
-        public double MaxX;
-        public double MaxY;
-    }
-
-    class FeatureProperty
-    {
-        public String Name;
-        public String Value;
-    }
-
-    class Feature
-    {
-        public String LayerName;
-        public ZoomBox Zoom;
-
-        private Dictionary<string, FeatureProperty> _properties;
-
-        public Feature(string layerName)
-        {
-            this.LayerName = layerName;
-            _properties = new Dictionary<string, FeatureProperty>();
-        }
-
-        public void AddProperty(FeatureProperty prop)
-        {
-            _properties[prop.Name] = prop;
-        }
-
-        public FeatureProperty[] GetProperties()
-        {
-            return new List<FeatureProperty>(_properties.Values).ToArray();
-        }
-    }
-
-    String mapName;
-    String sessionId;
-    String locale;
-    CultureInfo culture;
-    System.Text.RegularExpressions.Regex regex;
-
-    static NameValueCollection GetLayerPropertyMappings(MgResourceService resSvc, MgLayerBase layer)
-    {
-        NameValueCollection mappings = new NameValueCollection();
-        MgByteReader content = resSvc.GetResourceContent(layer.GetLayerDefinition());
-        XmlDocument doc = new XmlDocument();
-        doc.LoadXml(content.ToString());
-        XmlNodeList propNodes = doc.SelectNodes("//LayerDefinition/VectorLayerDefinition/PropertyMapping");
-        foreach (XmlNode propNode in propNodes)
-        {
-            String name = propNode["Name"].InnerText;
-            String value = propNode["Value"].InnerText;
-
-            mappings[name] = value;
-        }
-        return mappings;
-    }
-
-    String GetPropertyValueFromFeatureReader(MgFeatureReader reader, MgAgfReaderWriter agfRw, int propType, String propName)
-    {
-        String value = "";
-        switch(propType)
-        {
-            case MgPropertyType.Boolean:
-                value = String.Format(culture, "{0}", reader.GetBoolean(propName));
-                break;
-            case MgPropertyType.Byte:
-                value = String.Format(culture, "{0:d}", reader.GetByte(propName));
-                break;
-            case MgPropertyType.DateTime:
-                value = GetDateTimeString(reader.GetDateTime(propName)); // yyyy-mm-dd is enforced regardless of locale
-                break;
-            case MgPropertyType.Single:
-                value = String.Format(culture, "{0:f}", reader.GetSingle(propName));
-                break;
-            case MgPropertyType.Double:
-                value = String.Format(culture, "{0:f}", reader.GetDouble(propName));
-                break;
-            case MgPropertyType.Int16:
-                value = String.Format(culture, "{0:d}", reader.GetInt16(propName));
-                break;
-            case MgPropertyType.Int32:
-                value = String.Format(culture, "{0:d}", reader.GetInt32(propName));
-                break;
-            case MgPropertyType.Int64:
-                value = String.Format(culture, "{0:d}", reader.GetInt64(propName));
-                break;
-            case MgPropertyType.String:
-                value = JsonEscape(reader.GetString(propName)); //String content is arbitrary
-                value = regex.Replace(value, " ").Trim();
-                break;
-            default: //NOT PRESENTABLE IN PROPERTY GRID
-                value = "";
-                break;
-        }
-        return value;
-    }
-
-    static String GetDateTimeString(MgDateTime value)
-    {
-        return String.Format("{0}-{1}-{2}", value.Year, value.Month, value.Day);
-    }
-
-    void GetParameters(NameValueCollection param)
-    {
-        mapName = param["MAPNAME"];
-        sessionId = param["SESSION"];
-        locale = param["LOCALE"];
-    }
-
-    void GetRequestParameters()
-    {
-        if (Request.RequestType == "POST")
-            GetParameters(Request.Form);
-        else
-            GetParameters(Request.QueryString);
-    }
-
-    String JsonEscape(String str)
-    {
-        return EscapeForHtml(str).Replace("\\", "\\\\");
-    }
-
-    String JsonifyError(Exception ex)
-    {
-        return "{\"Error\":{\"Message\":\"" + JsonEscape(ex.Message) + "\",\"StackTrace\":\"" + JsonEscape(ex.StackTrace) + "\"}}";
-    }
-
-    static String GetJson(SelectionSet set)
-    {
-        /*
-        A sample of the JSON output this method will produce:
-
-
-        {
-            "Layer1" : [
-                {
-                    'values' { "name" : "name1" , "value" : "value1" },
-                    'zoom' : { x: num1, y: num2 }
-                } ,
-                ..,
-                ..,
-                ..,
-            ],
-            "Layer2" : [
-                {
-                    'values' { "name" : "name2" , "value" : "value2" },
-                    'zoom' : { x: num1, y: num2 }
-                } ,
-                ..,
-                ..,
-                ..,
-            ]
-        }
-        */
-
-        if (set == null)
-            return "";
-
-        StringBuilder sb = new StringBuilder();
-        //Begin selection set
-        sb.Append("{");
-        String[] layers = set.GetLayers();
-        for (int i = 0; i < layers.Length; i++)
-        {
-            //Begin layer
-            sb.Append("\"" + layers[i] + "\" : [");
-            Feature[] features = set.GetFeatures(layers[i]);
-            for (int j = 0; j < features.Length; j++)
-            {
-                Feature feat = features[j];
-                //begin feature
-                //begin feature properties
-                sb.Append("{\"values\" : [");
-                FeatureProperty[] properties = feat.GetProperties();
-                for(int k = 0; k < properties.Length; k++)
-                {
-                    FeatureProperty fp = properties[k];
-                    sb.Append("{\"name\" : \"" + fp.Name + "\", \"value\" : \"" + fp.Value + "\" }");
-                    if (k != properties.Length - 1)
-                        sb.Append(",");
-                }
-                //end feature properties
-                //begin zoom
-                sb.Append("], \"zoom\" : ");
-                if (feat.Zoom == null)
-                    sb.Append("null");
-                else
-                    sb.Append("{" + String.Format(CultureInfo.InvariantCulture, "\"minx\" : {0}, \"miny\" : {1}, \"maxx\": {2}, \"maxy\": {3}", feat.Zoom.MinX, feat.Zoom.MinY, feat.Zoom.MaxX, feat.Zoom.MaxY) + "}");
-                //end zoom
-                //end feature
-                sb.Append("}");
-                if (j != features.Length - 1)
-                    sb.Append(",");
-            }
-            //End Layer
-            sb.Append("]");
-            if (i != layers.Length - 1)
-                sb.Append(",");
-        }
-        //End selection set
-        sb.Append("}");
-        return sb.ToString();
-    }
-
-</script>
-<%
-
-    mapName = "";
-    sessionId = "";
-    locale = "";
-
-    GetRequestParameters();
-
-    if (String.IsNullOrEmpty(locale))
-        locale = GetDefaultLocale();
-
-    culture = CultureInfo.GetCultureInfo(locale);
-    regex = new System.Text.RegularExpressions.Regex("\\s+");
-
-    //HACK: The default locale (en) resolves to a neutral culture, .net forbids the use of
-    //neutral cultures for formatting purposes, so default to InvariantCulture if the resolved
-    //culture is not neutral.
-    if (culture.IsNeutralCulture)
-        culture = CultureInfo.InvariantCulture; //We need a non-neutral culture
-
-    try
-    {
-        MgUserInformation cred = new MgUserInformation(sessionId);
-        cred.SetClientIp(GetClientIp(Request));
-        cred.SetClientAgent(GetClientAgent());
-
-        MgSiteConnection site = new MgSiteConnection();
-        site.Open(cred);
-
-        MgResourceService resSvc = (MgResourceService)site.CreateService(MgServiceType.ResourceService);
-
-        MgMap map = new MgMap(site);
-        map.Open(mapName);
-
-        MgSelection selection = new MgSelection(map);
-        selection.Open(resSvc, mapName);
-
-        MgReadOnlyLayerCollection layers = selection.GetLayers();
-        if (layers != null && layers.Count > 0)
-        {
-            int layerCount = layers.Count;
-            MgAgfReaderWriter agfRW = new MgAgfReaderWriter();
-            SelectionSet selectionSet = new SelectionSet();
-
-            for (int i = 0; i < layerCount; i++)
-            {
-                MgLayerBase layer = layers[i];
-                String layerName = layer.Name;
-
-                MgResourceIdentifier fsId = new MgResourceIdentifier(layer.GetFeatureSourceId());
-                String className = layer.GetFeatureClassName();
-                String geomName = layer.GetFeatureGeometryName();
-
-                MgFeatureQueryOptions query = new MgFeatureQueryOptions();
-                NameValueCollection mappings = GetLayerPropertyMappings(resSvc, layer);
-
-                foreach (String key in mappings.Keys)
-                {
-                    query.AddFeatureProperty(key);
-                }
-
-                query.AddFeatureProperty(geomName);
-                String filter = selection.GenerateFilter(layer, className);
-                query.SetFilter(filter);
-
-                MgFeatureReader reader = layer.SelectFeatures(query);
-
-                MgClassDefinition clsDef = reader.GetClassDefinition();
-                MgPropertyDefinitionCollection props = clsDef.GetProperties();
-
-                while (reader.ReadNext())
-                {
-                    Feature feat = new Feature(layerName);
-                    ZoomBox zoom = null;
-
-                    for (int k = 0; k < props.Count; k++)
-                    {
-                        MgPropertyDefinition propDef = props[k];
-                        String propName = propDef.Name;
-                        int propType = reader.GetPropertyType(propName);
-
-                        if (mappings[propName] != null || propType == MgPropertyType.Geometry)
-                        {
-                            String value = "";
-                            if (!reader.IsNull(propName))
-                            {
-                                if (propName == geomName)
-                                {
-                                    MgByteReader agf = reader.GetGeometry(propName);
-                                    MgGeometry geom = agfRW.Read(agf);
-
-                                    MgEnvelope env = geom.Envelope();
-                                    MgCoordinate ll = env.GetLowerLeftCoordinate();
-                                    MgCoordinate ur = env.GetUpperRightCoordinate();
-
-                                    zoom = new ZoomBox();
-                                    zoom.MinX = ll.X;
-                                    zoom.MinY = ll.Y;
-                                    zoom.MaxX = ur.X;
-                                    zoom.MaxY = ur.Y;
-
-                                    feat.Zoom = zoom;
-                                }
-                                else
-                                {
-                                    value = GetPropertyValueFromFeatureReader(reader, agfRW, propType, propName);
-                                }
-
-                                if (mappings[propName] != null)
-                                {
-                                    FeatureProperty fp = new FeatureProperty();
-                                    fp.Name = mappings[propName];
-                                    fp.Value = value;
-
-                                    feat.AddProperty(fp);
-                                }
-                            }
-                        }
-                    }
-                    selectionSet.AddFeature(feat);
-                }
-                reader.Close();
-            }
-
-            //Now output the selection set
-            Response.AddHeader("Content-Type", "application/json");
-            Response.AddHeader("X-JSON", "true");
-
-            Response.Write(GetJson(selectionSet));
-        }
-    }
-    catch (MgException ex)
-    {
-        Response.AddHeader("Content-Type", "application/json");
-        Response.AddHeader("X-JSON", "true");
-        Response.Write(JsonifyError(ex));
-    }
-    catch (Exception ex)
-    {
-        Response.AddHeader("Content-Type", "application/json");
-        Response.AddHeader("X-JSON", "true");
-        Response.Write(JsonifyError(ex));
-    }
-
-%>

Modified: trunk/MgDev/Web/src/mapviewernet/mapframe.aspx
===================================================================
--- trunk/MgDev/Web/src/mapviewernet/mapframe.aspx	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/mapviewernet/mapframe.aspx	2013-05-24 14:47:52 UTC (rev 7519)
@@ -182,7 +182,6 @@
                         vpath + "setselection.aspx",
                         showSlider != 0? "true": "false",
                         locale,
-                        vpath + "getselectedfeatures.aspx",
                         scaleCreationCode,
                         selectionColor,
                         mapImgFormat,

Deleted: trunk/MgDev/Web/src/mapviewerphp/getselectedfeatures.php
===================================================================
--- trunk/MgDev/Web/src/mapviewerphp/getselectedfeatures.php	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/mapviewerphp/getselectedfeatures.php	2013-05-24 14:47:52 UTC (rev 7519)
@@ -1,499 +0,0 @@
-<?php
-
-/*
-
-TODO:
-
-- Use the property mapping. This will have to be old-fashioned parsing the <PropertyMapping> elements
-of the layer definition. I really wanted to use MgSelection::GetSelectedFeatures(layer, class, true) but realised
-that unless the geometry is mapped, you're not going to see it in the Feature Reader (ie. No zoom point). Right now
-it is returning all properties.
-
-- I know of a few features in the Sheboygan Dataset that trip up the JSON response. Need to find out of addslashes() fixes this.
-
-- General cleanup of the code
-
-
-*/
-
-//require_once('FirePHPCore/fb.php');
-
-//
-// Used to model the JSON response.
-//
-class SelectionSet
-{
-    private $layers;
-
-    public function __construct()
-    {
-        $this->layers = array();
-    }
-
-    public function AddFeature($feat)
-    {
-        $layerName = $feat->layerName;
-        if(!array_key_exists($layerName, $this->layers))
-            $this->layers[$layerName] = array();
-
-        array_push($this->layers[$layerName], $feat);
-    }
-
-    public function GetLayers()
-    {
-        return array_keys($this->layers);
-    }
-
-    public function GetFeatures($layerName)
-    {
-        if(array_key_exists($layerName, $this->layers))
-            return $this->layers[$layerName];
-
-        return null;
-    }
-}
-
-class ZoomBox
-{
-    public $minx;
-    public $miny;
-    public $maxx;
-    public $maxy;
-}
-
-//
-// Represents a selected feature property
-//
-class FeatureProperty
-{
-    public $name;
-    public $value;
-}
-
-//
-// Represents a selected feature
-//
-class Feature
-{
-    public $layerName;
-    public $zoom;
-
-    private $properties;
-
-    public function __construct($layerName)
-    {
-        $this->layerName = $layerName;
-        $this->properties = array();
-    }
-
-    public function AddProperty($prop)
-    {
-        $this->properties[$prop->name] = $prop;
-    }
-
-    public function GetProperties()
-    {
-        return $this->properties;
-    }
-}
-
-    include 'common.php';
-    include 'constants.php';
-
-    $mapName = "";
-    $sessionId = "";
-    $locale = "";
-
-    GetRequestParameters();
-
-    if (null == $locale || strlen($locale) == 0)
-        $locale = GetDefaultLocale();
-
-    setlocale(LC_ALL, $locale);
-
-    try
-    {
-        InitializeWebTier();
-
-        $cred = new MgUserInformation($sessionId);
-        $cred->SetClientIp(GetClientIp());
-        $cred->SetClientAgent(GetClientAgent());
-
-        //connect to the site and get an instance of the resource and feature service
-        //
-        $site = new MgSiteConnection();
-        $site->Open($cred);
-        $resourceSrvc = $site->CreateService(MgServiceType::ResourceService);
-
-        //load the map runtime state
-        //
-        $map = new MgMap($site);
-        $map->Open($mapName);
-
-        // Create the selection set
-        $selection = new MgSelection($map);
-        $selection->Open($resourceSrvc, $mapName);
-
-        $layers = $selection->GetLayers();
-        if($layers != null)
-        {
-            $nLayers = $layers->GetCount();
-            $agfRW = new MgAgfReaderWriter();
-
-            $selectionSet = new SelectionSet();
-
-            for ($i = 0; $i < $nLayers; $i++) {
-                $lyr = $layers->GetItem($i);
-                $layerName = $lyr->GetName();
-
-                //FB::log("Layer Name: " . $lyr->GetName());
-
-                $featResId = new MgResourceIdentifier($lyr->GetFeatureSourceId());
-                $class = $lyr->GetFeatureClassName();
-
-                $queryOptions = new MgFeatureQueryOptions();
-
-                $mappings = GetLayerPropertyMappings($resourceSrvc, $lyr);
-                //FB::log("Property Mappings for Layer: $layerName");
-                foreach($mappings as $name => $value) {
-                    $queryOptions->AddFeatureProperty($name);
-                    //FB::log("$name => $value");
-                }
-                $geomName = $lyr->GetFeatureGeometryName();
-                $queryOptions->AddFeatureProperty($geomName);
-
-                $filter = $selection->GenerateFilter($lyr, $class);
-                $queryOptions->SetFilter($filter);
-                $fr = $lyr->SelectFeatures($queryOptions);
-
-                $clsDef = $fr->GetClassDefinition();
-                $props = $clsDef->GetProperties();
-
-                //FB::log("Geometry: $geomName");
-
-                while($fr->ReadNext())
-                {
-                    $feat = new Feature($layerName);
-                    $zoom = null;
-
-                    for ($k = 0; $k < $props->GetCount(); $k++)
-                    {
-                        $prop = $props->GetItem($k);
-                        $propName = $prop->GetName();
-                        $propType = $fr->GetPropertyType($propName);
-
-                        //We only care about mapped properties or geometry properties
-                        if (array_key_exists($propName, $mappings) || $propType == MgPropertyType::Geometry)
-                        {
-                            $value = "";
-                            if (!$fr->IsNull($propName))
-                            {
-                                if(strcmp($propName,$geomName) == 0)
-                                {
-                                    //We want the centroid so we have a zoom-to point
-                                    $agf = $fr->GetGeometry($propName);
-                                    $geom = $agfRW->Read($agf);
-
-                                    $env = $geom->Envelope();
-                                    $ll = $env->GetLowerLeftCoordinate();
-                                    $ur = $env->GetUpperRightCoordinate();
-
-                                    $zoom = new ZoomBox();
-                                    $zoom->minx = $ll->GetX();
-                                    $zoom->miny = $ll->GetY();
-                                    $zoom->maxx = $ur->GetX();
-                                    $zoom->maxy = $ur->GetY();
-
-                                    $feat->zoom = $zoom;
-                                    //FB::log("zoom: (".$zoom->x.",".$zoom->y.")");
-                                }
-                                else
-                                {
-                                    $value = GetPropertyValueFromFeatureReader($fr, $agfRW, $propType, $propName);
-                                }
-                            }
-
-                            if (array_key_exists($propName, $mappings))
-                            {
-                                $fp = new FeatureProperty();
-                                $fp->name = $mappings[$propName];
-                                $fp->value = $value;
-
-                                $feat->AddProperty($fp);
-                            }
-                        }
-                    }
-
-                    $c = count($feat->GetProperties());
-                    //FB::log("Selected feature processed ($c)");
-
-                    $selectionSet->AddFeature($feat);
-                }
-                $fr->Close();
-            }
-
-            //Now output the selection set
-
-            header("Content-Type: application/json");
-            header("X-JSON: true");
-            echo GetJson($selectionSet);
-        }
-    }
-    catch(Exception $e)
-    {
-        header("Content-Type: application/json");
-        header("X-JSON: true");
-        echo JsonifyError($e->getMessage(), $e->getTraceAsString());
-    }
-    catch(MgException $e)
-    {
-        header("Content-Type: application/json");
-        header("X-JSON: true");
-        echo JsonifyError($e->GetDetails(), $e->GetStackTrace());
-    }
-
-function GetJson($selectionSet)
-{
-    if($selectionSet == null)
-        return "";
-
-    //FB::log("Processing JSON response");
-    /*
-    A sample of the JSON output this method will produce:
-
-
-    {
-        "Layer1" : [
-            {
-                'values' { "name" : "name1" , "value" : "value1" },
-                'zoom' : { x: num1, y: num2 }
-            } ,
-            ..,
-            ..,
-            ..,
-        ],
-        "Layer2" : [
-            {
-                'values' { "name" : "name2" , "value" : "value2" },
-                'zoom' : { x: num1, y: num2 }
-            } ,
-            ..,
-            ..,
-            ..,
-        ]
-    }
-    */
-
-    $layers = $selectionSet->GetLayers();
-    $totalLayers = array(); //The data portion of the JSON response
-
-    //FB::log("Layers in selection set: ".count($layers));
-
-    for ($i = 0; $i < count($layers); $i++)
-    {
-        $layerName = $layers[$i];
-
-        $features = $selectionSet->GetFeatures($layerName);
-
-        //FB::log("Features: ".$features);
-
-        if($features != null)
-        {
-            //FB::log("Processing layer: $layerName");
-
-            $totalFeaturesOnLayer = array();
-
-            if (count($features) > 0)
-            {
-                for ($j = 0; $j < count($features); $j++)
-                {
-                    $feat = $features[$j];
-                    $featureProperties = array();
-
-                    $fps = $feat->GetProperties();
-                    foreach($fps as $fp)
-                    {
-                        $name = $fp->name;
-                        $value = $fp->value;
-                        //Add JSONified feature property
-                        array_push($featureProperties, "{\"name\" : \"$name\", \"value\" : \"$value\" }");
-                    }
-                    //Add JSONified feature
-                    if($feat->zoom != null)
-                    {
-                        $minxstr = number_format($feat->zoom->minx, 8, '.','');
-                        $minystr = number_format($feat->zoom->miny, 8, '.','');
-                        $maxxstr = number_format($feat->zoom->maxx, 8, '.','');
-                        $maxystr = number_format($feat->zoom->maxy, 8, '.','');
-                        array_push($totalFeaturesOnLayer, "{\"values\" : [".join(",", $featureProperties)."], \"zoom\" : { \"minx\": $minxstr, \"miny\": $minystr,  \"maxx\": $maxxstr, \"maxy\": $maxystr } }");
-                    }
-                    else
-                        array_push($totalFeaturesOnLayer, "{\"values\" : [".join(",", $featureProperties)."], \"zoom\" : null }");
-
-                    //FB::log("Feature processed on layer: $layerName");
-                }
-            }
-
-            array_push($totalLayers, "\"$layerName\" : [" . join(", ", $totalFeaturesOnLayer) . "]");
-            //FB::log("Selected features on layer added to final JSON response");
-        }
-    }
-
-    //FB::log("Selection layer count: ".count($totalLayers));
-
-    $result = "{" . join(",",$totalLayers) . "}";
-    //return json_encode($result);
-    return $result;
-}
-
-function GetPropertyValueFromFeatureReader($fr, $agfRW, $propType, $propName)
-{
-    $val = "";
-    $tStr = "";
-    switch($propType)
-    {
-        case MgPropertyType::Null:
-            $tStr = "Null";
-            $val = "";
-            break;
-        case MgPropertyType::Boolean:
-            $tStr = "Boolean";
-            $val = sprintf("%s", $fr->GetBoolean($propName));
-            break;
-        case MgPropertyType::Byte:
-            $tStr = "Byte";
-            $val = sprintf("%d", $fr->GetByte($propName));
-            break;
-        case MgPropertyType::DateTime:
-            $tStr = "DateTime";
-            $val = printDateTime($fr->GetDateTime($propName)); // yyyy-mm-dd is enforced regardless of locale
-            break;
-        case MgPropertyType::Single:
-            $tStr = "Single";
-            $val = sprintf("%f", $fr->GetSingle($propName));
-            break;
-        case MgPropertyType::Double:
-            $tStr = "Double";
-            $val = sprintf("%f", $fr->GetDouble($propName));
-            break;
-        case MgPropertyType::Int16:
-            $tStr = "Int16";
-            $val = sprintf("%d", $fr->GetInt16($propName));
-            break;
-        case MgPropertyType::Int32:
-            $tStr = "Int32";
-            $val = sprintf("%d", $fr->GetInt32($propName));
-            break;
-        case MgPropertyType::Int64:
-            $tStr = "Int64";
-            $val = sprintf("%d", $fr->GetInt64($propName));
-            break;
-        case MgPropertyType::String:
-            $tStr = "String";
-            $val = JsonEscape($fr->GetString($propName)); //String content is arbitrary
-            $val = trim(preg_replace('/\s+/',' ',$val));
-            break;
-        case MgPropertyType::Blob: //NOT PRESENTABLE IN PROPERTY GRID
-            $tStr = "BLOB";
-            break;
-        case MgPropertyType::Clob: //NOT PRESENTABLE IN PROPERTY GRID
-            $tStr = "CLOB";
-            break;
-        case MgPropertyType::Feature: //NOT PRESENTABLE IN PROPERTY GRID
-            $tStr = "Feature";
-            break;
-        case MgPropertyType::Geometry: //NOT PRESENTABLE IN PROPERTY GRID
-            $tStr = "Geometry";
-            break;
-        case MgPropertyType::Raster: //NOT PRESENTABLE IN PROPERTY GRID
-            $tStr = "Raster";
-            break;
-    }
-    //FB::log("$propName ($tStr) = $val");
-    return $val;
-}
-
-/* retrieve the property mappings for a layer */
-function GetLayerPropertyMappings($resourceService, $layer) {
-    $mappings = array();
-    $byteReader = $resourceService->GetResourceContent($layer->GetLayerDefinition());
-    $xmldoc = DOMDocument::loadXML(ByteReaderToString($byteReader));
-    $mappingNodeList = $xmldoc->getElementsByTagName('PropertyMapping');
-    for ($i=0; $i<$mappingNodeList->length; $i++) {
-        $mapping = $mappingNodeList->item($i);
-        $nameElt = $mapping->getElementsByTagName('Name');
-        $name = $nameElt->item(0)->nodeValue;
-        $valueElt = $mapping->getElementsByTagName('Value');
-        $value = $valueElt->item(0)->nodeValue;
-        $mappings[$name] = $value;
-    }
-    return $mappings;
-}
-
-function ByteReaderToString($byteReader)
-{
-    return $byteReader->ToString();
-}
-
-function printDateTime($mgDateTime)
-{
-   $dayToday = $mgDateTime->GetDay();
-   $month = $mgDateTime->GetMonth();
-   $year = $mgDateTime->GetYear();
-   return $dayToday.".".$month.".".$year;
-}
-
-function GetParameters($params)
-{
-    global $mapName, $sessionId, $locale;
-
-    $mapName = $params['MAPNAME'];
-    $sessionId = $params['SESSION'];
-    $locale = $params['LOCALE'];
-}
-
-function JsonEscape($str)
-{
-    return str_replace("\\", "\\\\", EscapeForHtml($str));
-}
-
-function JsonifyError($msg, $st)
-{
-    /*
-    {
-        "Error" : {
-            "Message" : <exception-message>,
-            "StackTrace" : <exception-stack-trace>
-        }
-    }
-    */
-    $emsg = JsonEscape($msg);
-    $est = JsonEscape($st);
-    $json = "{\"Error\":{\"Message\":\"$emsg\",\"StackTrace\":\"$est\"}}";
-    return $json;
-}
-
-function UnescapeMagicQuotes($str)
-{
-    if(ini_get("magic_quotes_sybase") == "1")
-        return str_replace("''", "'", $str);
-    else if(get_magic_quotes_gpc() == "1")
-    {
-        //Unescape double quotes
-        $str = str_replace('\\"', '"', $str);
-
-        //remove additional backslash
-        return str_replace("\\", "", $str);
-    }
-    return $str;
-}
-
-function GetRequestParameters()
-{
-    if($_SERVER['REQUEST_METHOD'] == "POST")
-        GetParameters($_POST);
-    else
-        GetParameters($_GET);
-}
-
-?>

Modified: trunk/MgDev/Web/src/mapviewerphp/mapframe.php
===================================================================
--- trunk/MgDev/Web/src/mapviewerphp/mapframe.php	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/mapviewerphp/mapframe.php	2013-05-24 14:47:52 UTC (rev 7519)
@@ -146,7 +146,6 @@
                     $vpath . "setselection.php",
                     $showSlider? "true": "false",
                     $locale,
-                    $vpath . "getselectedfeatures.php",
                     $scaleCreationCode,
                     $selectionColor,
                     $mapImgFormat,

Modified: trunk/MgDev/Web/src/viewerfiles/ajaxmappane.templ
===================================================================
--- trunk/MgDev/Web/src/viewerfiles/ajaxmappane.templ	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/viewerfiles/ajaxmappane.templ	2013-05-24 14:47:52 UTC (rev 7519)
@@ -340,7 +340,6 @@
 var locale = '%s';
 var openHlinkText = macOS ? "__#OPENHYPERLINKMAC#__" : "__#OPENHYPERLINK#__";
 var lastLegendScaleUpdate = curScale;
-var featureRequestUrl = '%s';
 %s
 var isAlertShow = false;
 var selectionColor = '0x%s';
@@ -532,6 +531,16 @@
     return digitizing;
 }
 
+function GetSelectedFeatures()
+{
+    return selFeatures;
+}
+
+function GetSelectedBounds()
+{
+    return selBounds;
+}
+
 // private functions -----------------------------------------------
 //
 function InitDocument()
@@ -1885,10 +1894,8 @@
         document.getElementById("mapImage").src = document.getElementById("mapImage").src;
 }
 
-function RequestSelectionImage(reqId, viewParams)
+function PutSelectionImageUrl(reqId, url)
 {
-    url = webAgent + "?OPERATION=GETDYNAMICMAPOVERLAYIMAGE&FORMAT=" + selectionImgFormat + "&VERSION=2.1.0&SESSION=" + sessionId + "&MAPNAME=" + encodeComponent(mapName) + "&SEQ=" + Math.random() + "&CLIENTAGENT=" + encodeComponent(clientAgent) + "&BEHAVIOR=5&SELECTIONCOLOR=" + selectionColor;
-    url += viewParams;
     if(safari || chrome)
     {
         LoadAlternateSelectionImage(url, reqId);
@@ -1902,6 +1909,13 @@
         document.getElementById("selectionImage").src = document.getElementById("selectionImage").src;
 }
 
+function RequestSelectionImage(reqId, viewParams)
+{
+    url = webAgent + "?OPERATION=GETDYNAMICMAPOVERLAYIMAGE&FORMAT=" + selectionImgFormat + "&VERSION=2.1.0&SESSION=" + sessionId + "&MAPNAME=" + encodeComponent(mapName) + "&SEQ=" + Math.random() + "&CLIENTAGENT=" + encodeComponent(clientAgent) + "&BEHAVIOR=5&SELECTIONCOLOR=" + selectionColor;
+    url += viewParams;
+    PutSelectionImageUrl(reqId, url);
+}
+
 function OnMapOverlayImageLoaded(e)
 {
     ovimgloaded = true;
@@ -3018,8 +3032,14 @@
 {
     if(GetVisSelLayers() == "") return;
     if(moveType != NONE) return;
-    var reqParams = "OPERATION=QUERYMAPFEATURES&VERSION=1.0.0&PERSIST=1&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SEQ=" + Math.random();
+    if(geom.indexOf("NaN") >= 0) return;
+    
+    var reqData = 1; //attributes
+    if (msie8plus || !msie)
+        reqData |= 2; //inline selection
+    var reqParams = "OPERATION=QUERYMAPFEATURES&VERSION=2.6.0&PERSIST=1&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SEQ=" + Math.random();
     reqParams += "&LAYERNAMES=" + encodeURIComponent(GetVisSelLayers()) + "&GEOMETRY=" + geom + "&SELECTIONVARIANT=" + queryVariant + "&CLIENTAGENT=" + encodeURIComponent(clientAgent);
+    reqParams += "&REQUESTDATA=" + reqData + "&SELECTIONCOLOR=" + selectionColor + "&SELECTIONFORMAT=" + selectionImgFormat;
     if(maxfeatures != 0)
     {
         reqParams += "&MAXFEATURES=" + maxfeatures;
@@ -3129,7 +3149,17 @@
                 }
             }
             parent.OnSelectionChanged();
-            RequestSelectionImage(++ selMapId, "");
+            var mtEls = xmlIn.getElementsByTagName("MimeType");
+            var cntEls = xmlIn.getElementsByTagName("Content");
+            var bDataUriSupport = (msie8plus || !msie);
+            if (bDataUriSupport && mtEls.length == 1 && cntEls.length == 1) {
+                var mt = msie ? mtEls[0].text : mtEls[0].textContent;
+                var cnt = msie ? cntEls[0].text : cntEls[0].textContent;
+                var dataUri = "data:" + mt + ";base64," + cnt;
+                PutSelectionImageUrl(++ selMapId, dataUri);
+            } else {
+                RequestSelectionImage(++ selMapId, "");
+            }
         }
     }
     if(which & 2)
@@ -3138,7 +3168,10 @@
         {
             if (selection.count > 0)
             {
-                RequestSelectedFeatureProperties();
+                //Check if we have attributes inline
+                var props = xmlIn.getElementsByTagName("SelectedLayer");
+                var resp = ConvertToSelectedFeatureSet(props);
+                ProcessSelectedFeatureSet(resp);
             }
             else
             {
@@ -3203,13 +3236,15 @@
 
     SetSelection("", false);
 
+    selFeatures = {};
+    selBounds = null;
+
     selImg = document.getElementById(msie6minus ? "selImg1div": curSelImg);
     if(selImg)
     {
         selImg.style.visibility = "hidden";
     }
 
-
     parent.OnSelectionChanged();
 }
 
@@ -3226,32 +3261,15 @@
 
 function ZoomSelection()
 {
-    if(selection.count == 0)
+    if(selection.count == 0 || !selBounds)
         return;
-
-    var reqParams = "OPERATION=GETFEATURESETENVELOPE&VERSION=1.0.0&SESSION=" + sessionId + "&MAPNAME=" + encodeURIComponent(mapName) + "&SEQ=" + Math.random();
-    reqParams += "&FEATURESET=" + encodeURIComponent(selectionToXml()) + "&CLIENTAGENT=" + encodeURIComponent(clientAgent);
-
-    dr = CreateRequestHandler();
-    dr.open("POST", webAgent, false);
-    dr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-    dr.send(reqParams);
-   
-    if(dr.status == 200)
-    {
-        var env = ParseEnvelope(dr.responseXML.documentElement);
-        if(env != null)
-        {
-            var mcsW = env.upperRight.X - env.lowerLeft.X;
-            var mcsH = env.upperRight.Y - env.lowerLeft.Y;
-            var centerX = env.lowerLeft.X + mcsW / 2;
-            var centerY = env.lowerLeft.Y + mcsH / 2;
-            var scale = CalculateScale1(mcsW*2, mcsH*2, mapDevW, mapDevH);
-            GotoView(centerX, centerY, scale, true, true);
-        }
-    }
-    else
-        RequestFailed(dr.responseText);
+        
+    var mcsW = selBounds.maxx - selBounds.minx;
+    var mcsH = selBounds.maxy - selBounds.miny;
+    var centerX = selBounds.minx + mcsW / 2;
+    var centerY = selBounds.miny + mcsH / 2;
+    var scale = CalculateScale1(mcsW*2, mcsH*2, mapDevW, mapDevH);
+    GotoView(centerX, centerY, scale, true, true);
 }
 
 function ParseEnvelope(xmlRoot)
@@ -3761,7 +3779,8 @@
     pt1 = ScreenToMapUnits(x1,y1);
     pt2 = ScreenToMapUnits(x2,y2);
     geom = MakeWktPolygon(pt1.X, pt1.Y, pt2.X, pt2.Y);
-    reqParams = "OPERATION=QUERYMAPFEATURES&VERSION=1.0.0&PERSIST=0&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SEQ=" + Math.random() + "&LAYERNAMES=" + encodeURIComponent(GetVisLayers()) + "&GEOMETRY=" + geom + "&SELECTIONVARIANT=INTERSECTS&MAXFEATURES=1&LAYERATTRIBUTEFILTER=5" + "&CLIENTAGENT=" + encodeURIComponent(clientAgent);
+    var reqData = (4 | 8); //Tooltips + Hyperlinks
+    reqParams = "OPERATION=QUERYMAPFEATURES&VERSION=2.6.0&PERSIST=0&MAPNAME=" + encodeURIComponent(mapName) + "&SESSION=" + sessionId + "&SEQ=" + Math.random() + "&LAYERNAMES=" + encodeURIComponent(GetVisLayers()) + "&GEOMETRY=" + geom + "&SELECTIONVARIANT=INTERSECTS&MAXFEATURES=1&LAYERATTRIBUTEFILTER=5&REQUESTDATA=" + reqData + "&CLIENTAGENT=" + encodeURIComponent(clientAgent);
     obj = new HlRequest(id, x, y, req, exec);
     req.onreadystatechange = obj.OnHl;
     try { req.send(reqParams); } catch(ex) {}
@@ -4131,37 +4150,52 @@
 var hovered = "";
 var active = "";
 var selFeatures = {};
+var selBounds = null;
 
-function RequestSelectedFeatureProperties()
+function ConvertToSelectedFeatureSet(layerEls)
 {
-    var mapname = GetMapName();
-    var session = GetSessionId();
-    var selRequest = CreateRequestHandler();
-    var reqParams = "MAPNAME="+mapname+"&SESSION="+session+"&LOCALE="+locale+"&SEQ="+Math.random();
-    selRequest.open("POST", featureRequestUrl, false);
-    selRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
-    selRequest.send(reqParams);
- 
-    var respText = selRequest.responseText;
-    if (respText && respText.length > 0)
+    var featuresByLayer = {};
+    for (var i = 0; i < layerEls.length; i++)
     {
-        var resp = eval('(' + respText + ')');
-        //If an error occurred server-side, it is written as the error property of the JSON response
-        if (resp.Error)
-            RequestFailed(resp.Error.Message + "\n\n__#ERRORSTACKTRACE#__:\n\n" + resp.Error.StackTrace);
-        else
-            ProcessSelectedFeatureSet(resp);
+        var layerEl = layerEls[i];
+        var layerName = layerEl.getAttribute("name");
+        if (!featuresByLayer[layerName])
+            featuresByLayer[layerName] = [];
+            
+        var featEls = layerEl.getElementsByTagName("Feature");
+        for (var j = 0; j < featEls.length; j++)
+        {
+            var feat = { values: [] };
+            var featEl = featEls[j];
+            var bounds = featEl.getElementsByTagName("Bounds")[0];
+            var bbox = (msie ? bounds.text : bounds.textContent).split(" ");
+            feat.zoom = { minx: parseFloat(bbox[0]), miny: parseFloat(bbox[1]), maxx: parseFloat(bbox[2]), maxy: parseFloat(bbox[3]) };
+            
+            var propEls = featEl.getElementsByTagName("Property");
+            for (var k = 0; k < propEls.length; k++)
+            {
+                var nameEl = propEls[k].getElementsByTagName("Name")[0];
+                var valueEl = propEls[k].getElementsByTagName("Value");
+                //Name,Value
+                var name = msie ? nameEl.text : nameEl.textContent;
+                var value = null;
+                if (valueEl.length == 1)
+                    value = msie ? valueEl[0].text : valueEl[0].textContent;
+                feat.values.push({ name: name, value: value });
+            }
+            featuresByLayer[layerName].push(feat);
+        }
     }
-    else
-        RequestFailed("__#NOFEATSELECTRESPONSE#__");
+    return featuresByLayer;
 }
 
 function ProcessSelectedFeatureSet(resp)
 {
     selFeatures = {};
+    selBounds = null;
     if (!resp)
         return;
-        
+
     var selLayers = document.getElementById("selLayers");
     selLayers.length = 0;
     GetPropertyCtrl().Clear();
@@ -4180,6 +4214,26 @@
  
         //Associates the selected features on layer
         selFeatures[layerName] = resp[layerName];
+        
+        //Update selection bounding box
+        for (var i = 0; i < resp[layerName].length; i++)
+        {
+            var feat = resp[layerName][i];
+            if (feat.zoom) {
+                if (!selBounds) {
+                    selBounds = { minx: feat.zoom.minx, miny: feat.zoom.miny, maxx: feat.zoom.maxx, maxy: feat.zoom.maxy };
+                } else {
+                    if (feat.zoom.minx < selBounds.minx)
+                        selBounds.minx = feat.zoom.minx;
+                    if (feat.zoom.miny < selBounds.miny)
+                        selBounds.miny = feat.zoom.miny;
+                    if (feat.zoom.maxx > selBounds.maxx)
+                        selBounds.maxx = feat.zoom.maxx;
+                    if (feat.zoom.maxy > selBounds.maxy)
+                        selBounds.maxy = feat.zoom.maxy;
+                }
+            }
+        }
     }
     
     if (selLayers.length > 0)

Modified: trunk/MgDev/Web/src/viewerfiles/browserdetect.js
===================================================================
--- trunk/MgDev/Web/src/viewerfiles/browserdetect.js	2013-05-24 12:39:25 UTC (rev 7518)
+++ trunk/MgDev/Web/src/viewerfiles/browserdetect.js	2013-05-24 14:47:52 UTC (rev 7519)
@@ -27,16 +27,23 @@
 var msieIndex = agent.indexOf("msie");
 var msie = false;
 var msie7plus = false;
+var msie8plus = false;
 var msie6minus = false;
 if(msieIndex != -1)
 {
     msie = true;
     var msieVersion = agent.substr(msieIndex + 5, 2);
 
-    if(parseFloat(msieVersion) >= 7)
+    if(parseFloat(msieVersion) == 7)
     {
         msie7plus = true;
+        msie8plus = false;
     }
+    else if (parseFloat(msieVersion) >= 8)
+    {
+        msie7plus = true;
+        msie8plus = true;
+    }
     else
     {
         msie6minus = true;



More information about the mapguide-commits mailing list