[mapguide-commits] r6819 - in branches/2.4/MgDev/Desktop: DesktopUnmanagedApi/DotNet MgDesktop MgDesktop/MapLayer MgDesktop/Services MgDesktop/Services/Rendering MgDesktop/System UnitTest

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Jun 26 08:31:55 PDT 2012


Author: jng
Date: 2012-06-26 08:31:55 -0700 (Tue, 26 Jun 2012)
New Revision: 6819

Added:
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.h
Modified:
   branches/2.4/MgDev/Desktop/DesktopUnmanagedApi/DotNet/MapGuideDesktopApiGen.xml
   branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.h
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj.filters
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.h
   branches/2.4/MgDev/Desktop/MgDesktop/System/ClassId.h
   branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.cpp
   branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.h
Log:
mg-desktop updates:
 - Implement the QueryFeatures() API for MgdRenderingService. We need this API for tooltip and selection support for #2020
 - Add extra helper APIs also for #2020

Modified: branches/2.4/MgDev/Desktop/DesktopUnmanagedApi/DotNet/MapGuideDesktopApiGen.xml
===================================================================
--- branches/2.4/MgDev/Desktop/DesktopUnmanagedApi/DotNet/MapGuideDesktopApiGen.xml	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/DesktopUnmanagedApi/DotNet/MapGuideDesktopApiGen.xml	2012-06-26 15:31:55 UTC (rev 6819)
@@ -122,6 +122,7 @@
     <Header path="../../MgDesktop/Services/Rendering/CustomLogoInfo.h" />
     <Header path="../../MgDesktop/Services/Rendering/CustomTextInfo.h" />
     <Header path="../../MgDesktop/Services/Rendering/DwfVersion.h" />
+    <Header path="../../MgDesktop/Services/Rendering/FeatureInformation.h" />
     <Header path="../../MgDesktop/Services/Rendering/Layout.h" />
     <Header path="../../MgDesktop/Services/Rendering/MapPlot.h" />
     <Header path="../../MgDesktop/Services/Rendering/DwfVersion.h" />

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.cpp	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.cpp	2012-06-26 15:31:55 UTC (rev 6819)
@@ -1161,4 +1161,10 @@
 {
     CHECKARGUMENTNULL(layer, L"MgdMap::SetGroupExpandInLegend");
     layer->SetExpandInLegend(bExpand);
+}
+
+void MgdMap::SetLayerGroupType(MgLayerGroup* group, INT32 type)
+{
+    CHECKARGUMENTNULL(group, L"MgdMap::SetLayerGroupType");
+    group->SetLayerGroupType(type);
 }
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.h	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MapLayer/Map.h	2012-06-26 15:31:55 UTC (rev 6819)
@@ -67,6 +67,8 @@
 
     static void SetLayerExpandInLegend(MgLayerBase* layer, bool bExpand);
 
+    static void SetLayerGroupType(MgLayerGroup* group, INT32 type);
+
 INTERNAL_API:
     MgdMap();
 

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.h	2012-06-26 15:31:55 UTC (rev 6819)
@@ -63,6 +63,7 @@
 #include "Services/Rendering/CustomLogoInfo.h"
 #include "Services/Rendering/CustomTextInfo.h"
 #include "Services/Rendering/DwfVersion.h"
+#include "Services/Rendering/FeatureInformation.h"
 #include "Services/Rendering/Layout.h"
 #include "Services/Rendering/MapPlot.h"
 #include "Services/Rendering/MapPlotCollection.h"

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj	2012-06-26 15:31:55 UTC (rev 6819)
@@ -1264,6 +1264,42 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Services\Rendering\FeatureInformation.cpp"
+				>
+				<FileConfiguration
+					Name="Debug|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Debug|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|Win32"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+				<FileConfiguration
+					Name="Release|x64"
+					ExcludedFromBuild="true"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+					/>
+				</FileConfiguration>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\FeatureNumericFunctions.cpp"
 				>
 				<FileConfiguration
@@ -4070,6 +4106,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Rendering\FeatureInformation.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\FeatureNumericFunctions.h"
 				>
 			</File>

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj	2012-06-26 15:31:55 UTC (rev 6819)
@@ -299,6 +299,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="Services\Rendering\FeatureInformation.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
     <ClCompile Include="Services\Resource\ByteSourceDwfInputStreamImpl.cpp">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -846,6 +852,7 @@
     <ClInclude Include="Services\Feature\UniqueFunction.h" />
     <ClInclude Include="Services\MappingService.h" />
     <ClInclude Include="Services\ProfilingService.h" />
+    <ClInclude Include="Services\Rendering\FeatureInformation.h" />
     <ClInclude Include="Services\Resource\ByteSourceDwfInputStreamImpl.h" />
     <ClInclude Include="Services\ByteSourceRasterStreamImpl.h" />
     <ClInclude Include="System\ClassId.h" />

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj.filters
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj.filters	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcxproj.filters	2012-06-26 15:31:55 UTC (rev 6819)
@@ -315,6 +315,9 @@
     <ClCompile Include="Services\MappingService.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Services\Rendering\FeatureInformation.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Exception\AliasNotFoundException.h">
@@ -686,6 +689,9 @@
     <ClInclude Include="Services\MappingService.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Services\Rendering\FeatureInformation.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\braindump.txt" />

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp	2012-06-26 15:31:55 UTC (rev 6819)
@@ -76,6 +76,7 @@
 #include "Services/Rendering/CustomTextInfo.cpp"
 #include "Services/Rendering/DwfVersion.cpp"
 #include "Services/Rendering/FeatureInfoRenderer.cpp"
+#include "Services/Rendering/FeatureInformation.cpp"
 #include "Services/Rendering/Layout.cpp"
 #include "Services/Rendering/LegendPlotUtil.cpp"
 #include "Services/Rendering/MappingUtil.cpp"

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.cpp	2012-06-26 15:31:55 UTC (rev 6819)
@@ -0,0 +1,179 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "MgDesktop.h"
+
+MG_IMPL_DYNCREATE(MgdFeatureInformation)
+
+/////////////////////////////////////////
+// Get the selection set the described features are part of.
+//
+MgdSelection* MgdFeatureInformation::GetSelection()
+{
+    return SAFE_ADDREF((MgdSelection*)m_selection);
+}
+
+/////////////////////////////////////////
+// Get the tooltip text
+//
+STRING MgdFeatureInformation::GetTooltip()
+{
+    return m_tooltip;
+}
+
+/////////////////////////////////////////
+// Get the hyperlink URL text
+//
+STRING MgdFeatureInformation::GetHyperlink()
+{
+    return m_hyperlink;
+}
+
+/////////////////////////////////////////
+// Get the collection of properties for the described feature.
+//
+MgPropertyCollection* MgdFeatureInformation::GetProperties()
+{
+    return SAFE_ADDREF((MgPropertyCollection*)m_properties);
+}
+
+/////////////////////////////////////////
+// Write feature information as XML document.
+//
+MgByteReader* MgdFeatureInformation::ToXml()
+{
+    STRING xml;
+    STRING xmlSelection = m_selection? m_selection->ToXml(false): L"";
+
+    // TODO: define a schema for this XML
+    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(m_tooltip.length() > 0)
+    {
+        xml.append(L"<Tooltip>");
+        xml.append(MgUtil::ReplaceEscapeCharInXml(m_tooltip));
+        xml.append(L"</Tooltip>\n");
+    }
+    else
+        xml.append(L"<Tooltip />\n");
+
+    if(m_hyperlink.length() > 0)
+    {
+        xml.append(L"<Hyperlink>");
+        xml.append(MgUtil::ReplaceEscapeCharInXml(m_hyperlink));
+        xml.append(L"</Hyperlink>\n");
+    }
+    else
+        xml.append(L"<Hyperlink />\n");
+
+    if(m_properties != NULL)
+    {
+        for(int i = 0; i < m_properties->GetCount(); i++)
+        {
+            Ptr<MgStringProperty> prop = (MgStringProperty*)m_properties->GetItem(i);
+            xml.append(L"<Property name=\"");
+            xml.append(MgUtil::ReplaceEscapeCharInXml(prop->GetName()));
+            xml.append(L"\" value=\"");
+            xml.append(MgUtil::ReplaceEscapeCharInXml(prop->GetValue()));
+            xml.append(L"\" />\n");
+        }
+    }
+    xml.append(L"</FeatureInformation>\n");
+
+    string xmlDoc = MgUtil::WideCharToMultiByte(xml);
+    STRING mimeType = L"text/xml";
+    return MgUtil::GetByteReader(xmlDoc, &mimeType);
+}
+
+/////////////////////////////////////////
+// Construct an empty MgFeatureInformation object
+//
+MgdFeatureInformation::MgdFeatureInformation()
+{
+}
+
+/////////////////////////////////////////
+// Set the selection
+//
+void MgdFeatureInformation::SetSelection(MgdSelection* selection)
+{
+    m_selection = SAFE_ADDREF((MgdSelection*)selection);
+}
+
+/////////////////////////////////////////
+// Set the properties
+//
+void MgdFeatureInformation::SetProperties(MgPropertyCollection* properties)
+{
+    m_properties = SAFE_ADDREF((MgPropertyCollection*)properties);
+}
+
+/////////////////////////////////////////
+// Set the tooltip text
+//
+void MgdFeatureInformation::SetTooltip(CREFSTRING tooltip)
+{
+    m_tooltip = tooltip;
+}
+
+/////////////////////////////////////////
+// Set the hyperlink URL
+//
+void MgdFeatureInformation::SetHyperlink(CREFSTRING hyperlink)
+{
+    m_hyperlink = hyperlink;
+}
+
+/////////////////////////////////////////
+// Serialize to a stream
+//
+void MgdFeatureInformation::Serialize(MgStream* stream)
+{
+    stream->WriteString(m_selection->ToXml());
+    stream->WriteString(m_tooltip);
+    stream->WriteString(m_hyperlink);
+    stream->WriteObject(m_properties);
+}
+
+/////////////////////////////////////////
+// Deserialize from a stream
+//
+void MgdFeatureInformation::Deserialize(MgStream* stream)
+{
+    STRING xml;
+    stream->GetString(xml);
+    if(xml.length() > 0)
+    {
+        m_selection = new MgdSelection();
+        m_selection->FromXml(xml);
+    }
+    stream->GetString(m_tooltip);
+    stream->GetString(m_hyperlink);
+    m_properties = (MgPropertyCollection*)stream->GetObject();
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Rendering/FeatureInformation.h	2012-06-26 15:31:55 UTC (rev 6819)
@@ -0,0 +1,194 @@
+//
+//  Copyright (C) 2004-2011 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _MG_FEATUREINFORMATION_H_
+#define _MG_FEATUREINFORMATION_H_
+
+/// \defgroup MgFeatureInformation MgFeatureInformation
+/// \ingroup Common_Module
+/// \{
+
+class MgdFeatureInformation;
+template class MG_DESKTOP_API Ptr<MgdFeatureInformation>;
+
+class MgSelection;
+
+///////////////////////////////////////////////////////////
+/// \brief
+/// Information about features.
+///
+class MG_DESKTOP_API MgdFeatureInformation : public MgSerializable
+{
+    MG_DECL_DYNCREATE();
+    DECLARE_CLASSNAME(MgdFeatureInformation)
+
+PUBLISHED_API:
+
+    /////////////////////////////////////////
+    /// \brief
+    /// Get the selection set the described features are part of.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// MgSelection GetSelection();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// MgSelection GetSelection();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// MgSelection GetSelection();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    MgdSelection* GetSelection();
+
+    /////////////////////////////////////////
+    /// \brief
+    /// Get the tooltip text.
+    ///
+    /// \remarks
+    /// Valid only when there is only one feature described in this object
+    ////
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// string GetTooltip();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// String GetTooltip();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// string GetTooltip();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    ///
+    STRING GetTooltip();
+
+    /////////////////////////////////////////
+    /// \brief
+    /// Get the hyperlink URL text
+    ///
+    /// \remarks
+    /// Valid only when there is only one feature described in this object.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// string GetHyperlink();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// String GetHyperlink();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// string GetHyperlink();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+
+    STRING GetHyperlink();
+
+    /////////////////////////////////////////
+    /// \brief
+    /// Get the collection of properties for the described feature.
+    ///
+    /// \remarks
+    /// Valid only when there is only one feature described in this object.
+    ///
+    /// <!-- Syntax in .Net, Java, and PHP -->
+    /// \htmlinclude DotNetSyntaxTop.html
+    /// MgPropertyCollection GetProperties();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude JavaSyntaxTop.html
+    /// MgPropertyCollection GetProperties();
+    /// \htmlinclude SyntaxBottom.html
+    /// \htmlinclude PHPSyntaxTop.html
+    /// MgPropertyCollection GetHyperlink();
+    /// \htmlinclude SyntaxBottom.html
+    ///
+    MgPropertyCollection* GetProperties();
+
+EXTERNAL_API:
+
+    //////////////////////////////////////////////////////////
+    /// \brief
+    /// Creates an XML document containing the feature information.
+    ///
+    /// \return
+    /// A pointer to an MgByteReader object.
+    ///
+    MgByteReader* ToXml();
+
+INTERNAL_API:
+
+    /////////////////////////////////////////
+    /// Construct an empty MgFeatureInformation object
+    ///
+    MgdFeatureInformation();
+
+    /////////////////////////////////////////
+    /// Set the selection
+    ///
+    void SetSelection(MgdSelection* selection);
+
+    /////////////////////////////////////////
+    /// Set the properties
+    ///
+    void SetProperties(MgPropertyCollection* properties);
+
+    /////////////////////////////////////////
+    /// Set the tooltip text
+    ///
+    void SetTooltip(CREFSTRING tooltip);
+
+    /////////////////////////////////////////
+    /// Set the hyperlink URL
+    ///
+    void SetHyperlink(CREFSTRING hyperlink);
+
+    /////////////////////////////////////////
+    /// Serialize to a stream
+    ///
+    virtual void Serialize(MgStream* stream);
+
+    /////////////////////////////////////////
+    /// Deserialize from a stream
+    ///
+    virtual void Deserialize(MgStream* stream);
+
+    /////////////////////////////////////////
+    /// Get the class ID
+    ///
+    virtual INT32 GetClassId() { return m_cls_id; }
+
+CLASS_ID:
+    static const INT32 m_cls_id = MapGuide_Desktop_RenderingService_FeatureInformation;
+
+protected:
+
+    /////////////////////////////////////////
+    /// Dispose the object
+    ///
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+private:
+    Ptr<MgdSelection>            m_selection;
+    Ptr<MgPropertyCollection>   m_properties;
+    STRING                      m_tooltip;
+    STRING                      m_hyperlink;
+};
+/// \}
+
+#endif

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.cpp	2012-06-26 15:31:55 UTC (rev 6819)
@@ -2,19 +2,11 @@
 #include "System/ConfigProperties.h"
 #include "AGGRenderer.h"
 #include "GDRenderer.h"
-//#include "EPlotRenderer.h"
-//#include "DefaultStylizer.h"
 #include "ImageFormats.h"
-//#include "FeatureTypeStyleVisitor.h"
 #include "SymbolInstance.h"
-//#include "Rendering/icons.h"
-//#include "Rendering/RSMgSymbolManager.h"
 #include "Rendering/RSMgFeatureReader.h"
 #include "Rendering/FeatureInfoRenderer.h"
-//#include "Stylization/SEMgSymbolManager.h"
-//#include "StylizationUtil.h"
 #include "Rendering/MappingUtil.h"
-//#include "Rendering/LegendPlotUtil.h"
 #include "MapLayer/Map.h"
 #include "Feature/TransformCache.h"
 #include "ServiceFactory.h"
@@ -491,6 +483,190 @@
     return ret.Detach();
 }
 
+MgdFeatureInformation* MgdRenderingService::QueryFeatures(MgdMap* map,
+                                                          MgStringCollection* layerNames,
+                                                          MgGeometry* filterGeometry,
+                                                          INT32 selectionVariant,
+                                                          INT32 maxFeatures)
+{
+    Ptr<MgdFeatureInformation> ret;
+    MG_LOG_OPERATION_MESSAGE(L"QueryFeatures");
+
+    MG_TRY()
+
+    Ptr<MgResourceIdentifier> mapId = map->GetResourceId();
+    MG_LOG_OPERATION_MESSAGE_INIT(MG_API_VERSION(1, 0, 0), 5);
+    MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING((NULL == mapId) ? L"MgdMap" : mapId->ToString().c_str());
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING((layerNames == NULL) ? L"MgStringCollection" : layerNames->GetLogString());
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"MgGeometry");
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_INT32(selectionVariant);
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_INT32(maxFeatures);
+    MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+    MG_LOG_TRACE_ENTRY(L"MgdRenderingService::QueryFeatures()");
+
+    ret = QueryFeaturesInternal(map, layerNames, filterGeometry, selectionVariant, L"", maxFeatures, 3 /*visible and selectable*/);
+
+    MG_CATCH(L"MgdRenderingService::QueryFeatures")
+
+    if (mgException != NULL)
+    {
+        // Failed operation
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Failure.c_str());
+        MG_DESKTOP_LOG_EXCEPTION();
+    }
+
+    // Add access log entry for operation
+    MG_LOG_OPERATION_MESSAGE_ACCESS_ENTRY();
+
+    MG_THROW()
+    return ret.Detach();
+}
+
+MgdFeatureInformation* MgdRenderingService::QueryFeatures(
+    MgdMap* map,
+    MgStringCollection* layerNames,
+    MgGeometry* filterGeometry,
+    INT32 selectionVariant,
+    CREFSTRING featureFilter,
+    INT32 maxFeatures,
+    INT32 layerAttributeFilter)
+{
+    Ptr<MgdFeatureInformation> ret;
+    MG_LOG_OPERATION_MESSAGE(L"QueryFeatures");
+
+    MG_TRY()
+
+    Ptr<MgResourceIdentifier> mapId = map->GetResourceId();
+    MG_LOG_OPERATION_MESSAGE_INIT(MG_API_VERSION(1, 0, 0), 7);
+    MG_LOG_OPERATION_MESSAGE_PARAMETERS_START();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING((NULL == mapId) ? L"MgdMap" : mapId->ToString().c_str());
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING((layerNames == NULL) ? L"MgStringCollection" : layerNames->GetLogString());
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(L"MgGeometry");
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_INT32(selectionVariant);
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_STRING(featureFilter);
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_INT32(maxFeatures);
+    MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
+    MG_LOG_OPERATION_MESSAGE_ADD_INT32(layerAttributeFilter);
+    MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
+
+    MG_LOG_TRACE_ENTRY(L"MgdRenderingService::QueryFeatures()");
+
+    ret = QueryFeaturesInternal(map, layerNames, filterGeometry, selectionVariant, featureFilter, maxFeatures, layerAttributeFilter);
+
+    MG_CATCH(L"MgdRenderingService::QueryFeatures")
+
+    if (mgException != NULL)
+    {
+        // Failed operation
+        MG_LOG_OPERATION_MESSAGE_ADD_STRING(MgResources::Failure.c_str());
+        MG_DESKTOP_LOG_EXCEPTION();
+    }
+
+    // Add access log entry for operation
+    MG_LOG_OPERATION_MESSAGE_ACCESS_ENTRY();
+
+    MG_THROW()
+    return ret.Detach();
+}
+
+MgdFeatureInformation* MgdRenderingService::QueryFeaturesInternal(MgdMap* map,
+                                                                  MgStringCollection* layerNames,
+                                                                  MgGeometry* geometry,
+                                                                  INT32 selectionVariant,
+                                                                  CREFSTRING featureFilter,
+                                                                  INT32 maxFeatures,
+                                                                  INT32 layerAttributeFilter)
+{
+    Ptr<MgdFeatureInformation> ret;
+
+    MG_TRY()
+
+    //detect case where there is no limit to selection
+    if (maxFeatures == -1)
+        maxFeatures = INT_MAX;
+
+    //create return structure and selection set to fill out
+    ret = new MgdFeatureInformation();
+    Ptr<MgdSelection> sel = new MgdSelection(map);
+
+    double point_buf[2];
+    double* point = NULL;
+    auto_ptr<SE_Renderer> impRenderer;
+    if (geometry && maxFeatures == 1)
+    {
+        MgPolygon* polygon = dynamic_cast<MgPolygon*>(geometry);
+        if (polygon)
+        {
+            Ptr<MgCoordinateIterator> iterator = polygon->GetCoordinates();
+            int num = 0;
+            double pt0_x, pt0_y, pt_x, pt_y;
+            while(iterator->MoveNext())
+            {
+                Ptr<MgCoordinate> coord = iterator->GetCurrent();
+                double x = coord->GetX(), y = coord->GetY();
+                if (!num)
+                {
+                    pt_x = pt0_x = x;
+                    pt_y = pt0_y = y;
+                }
+                else if (x == pt0_x && y == pt0_y)
+                    break;
+                else
+                {
+                    pt_x += x;
+                    pt_y += y;
+                }
+                num++;
+            }
+            if (num > 0)
+            {
+                point_buf[0] = pt_x / num;
+                point_buf[1] = pt_y / num;
+                point = point_buf;
+
+                RS_Color bgColor; // not used
+                impRenderer.reset(CreateRenderer(1, 1, bgColor, false));
+            }
+        }
+    }
+
+    FeatureInfoRenderer fir(sel, maxFeatures, map->GetViewScale(), point, impRenderer.get());
+
+    RenderForSelection(map, layerNames, geometry, selectionVariant, featureFilter, maxFeatures, layerAttributeFilter, &fir);
+
+    //fill out the output object with the info we collected
+    //in the FeatureInfoRenderer for the first feature we hit
+    if (fir.GetNumFeaturesProcessed() > 0)
+    {
+        Ptr<MgPropertyCollection> props = fir.GetProperties();
+        ret->SetProperties(props);
+        ret->SetHyperlink(fir.GetUrl());
+        ret->SetTooltip(fir.GetTooltip());
+    }
+
+    ret->SetSelection(sel);
+
+    #ifdef _DEBUG
+    Ptr<MgReadOnlyLayerCollection> selLayers = sel->GetLayers();
+    ACE_DEBUG((LM_INFO, ACE_TEXT("(%t) MgServerRenderingService::QueryFeatures() Selection Size:%d\n"), selLayers.p? selLayers->GetCount() : 0));
+    #endif
+
+    MG_CATCH_AND_THROW(L"MgdRenderingService::QueryFeaturesInternal")
+
+    return ret.Detach();
+}
+
 MgByteReader* MgdRenderingService::RenderDynamicOverlayInternal(MgdMap* map,
                                                                MgdSelection* selection,
                                                                MgRenderingOptions* options,
@@ -1820,4 +1996,385 @@
     }
 
     return bs->GetReader();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// A helper function that does most of the work for QueryFeatures
+// and QueryFeatureProperties.  Basically runs a rendering loop with
+// a custom renderer supplied by the caller that accumulates selection
+// related things like property values and feature IDs.
+void MgdRenderingService::RenderForSelection(MgdMap* map,
+                                             MgStringCollection* layerNames,
+                                             MgGeometry* geometry,
+                                             INT32 selectionVariant,
+                                             CREFSTRING featureFilter,
+                                             INT32 maxFeatures,
+                                             INT32 layerAttributeFilter,
+                                             FeatureInfoRenderer* selRenderer)
+{
+    // Cache coordinate system transforms for the life of the
+    // stylization operation.
+    TransformCacheMap transformCache;
+
+    MG_TRY()
+
+    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): ** START **\n")));
+    if (NULL == map || (NULL == geometry && featureFilter.empty()))
+        throw new MgNullArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"", NULL);
+
+    if (maxFeatures < 0)
+    {
+        STRING buffer;
+        MgUtil::Int32ToString(maxFeatures, buffer);
+
+        MgStringCollection arguments;
+        arguments.Add(L"5");
+        arguments.Add(buffer);
+
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderForSelection",
+            __LINE__, __WFILE__, &arguments, L"MgValueCannotBeLessThanZero", NULL);
+    }
+
+    // get the session ID
+    STRING sessionId;
+    //Ptr<MgUserInformation> userInfo = MgUserInformation::GetCurrentUserInfo();
+    //if (userInfo != NULL)
+    //    sessionId = userInfo->GetMgSessionId();
+
+    // validate map view parameters
+    int width            = map->GetDisplayWidth();
+    int height           = map->GetDisplayHeight();
+    int dpi              = map->GetDisplayDpi();
+    double scale         = map->GetViewScale();
+    double metersPerUnit = map->GetMetersPerUnit();
+
+    if (width <= 0)
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"MgMapDisplayWidthCannotBeLessThanOrEqualToZero", NULL);
+
+    if (height <= 0)
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"MgMapDisplayHeightCannotBeLessThanOrEqualToZero", NULL);
+
+    if (dpi <= 0)
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"MgMapDisplayDpiCannotBeLessThanOrEqualToZero", NULL);
+
+    if (scale <= 0.0)
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"MgMapViewScaleCannotBeLessThanOrEqualToZero", NULL);
+
+    if (metersPerUnit <= 0.0)
+        throw new MgInvalidArgumentException(L"MgServerRenderingService.RenderForSelection", __LINE__, __WFILE__, NULL, L"MgMapMetersPerUnitCannotBeLessThanOrEqualToZero", NULL);
+
+    // compute map extent that corresponds to pixel extent
+    Ptr<MgPoint> pt          = map->GetViewCenter();
+    Ptr<MgCoordinate> center = pt->GetCoordinate();
+    double unitsPerPixel     = METERS_PER_INCH / (double)dpi / metersPerUnit;
+    double mapWidth2         = 0.5 * (double)width  * unitsPerPixel * scale;
+    double mapHeight2        = 0.5 * (double)height * unitsPerPixel * scale;
+
+    RS_Bounds extent(center->GetX() - mapWidth2,
+                     center->GetY() - mapHeight2,
+                     center->GetX() + mapWidth2,
+                     center->GetY() + mapHeight2);
+
+    // begin map stylization
+    RS_Color bgcolor(0, 0, 0, 255); // not used
+    STRING srs = map->GetMapSRS();
+    RS_MapUIInfo mapInfo(sessionId, map->GetName(), map->GetObjectId(), srs, L"", bgcolor);
+
+    // initialize the stylizer
+    SEMgSymbolManager semgr(m_svcResource);
+    DefaultStylizer ds(&semgr);
+
+    selRenderer->StartMap(&mapInfo, extent, scale, dpi, metersPerUnit, NULL);
+
+    //initial simple selection scheme
+    //Run a geometric FDO query on the given selection geometry
+    //and return the features we get from FDO
+
+    Ptr<MgLayerCollection> layers = map->GetLayers();
+
+    bool bOnlySelectableLayers = !((layerAttributeFilter & FILTER_SELECTABLE) == 0);
+    bool bOnlyVisibleLayers = !((layerAttributeFilter & FILTER_VISIBLE) == 0);
+    bool bOnlyTooltipLayers = !((layerAttributeFilter & FILTER_HASTOOLTIPS) == 0);
+
+    //iterate over all map layers, but only do selection
+    //if the layer is in the passed in collection
+    for (int p=0; p<layers->GetCount(); p++)
+    {
+        //find the layer we need to select features from
+        Ptr<MgLayerBase> layer = layers->GetItem(p);
+
+        ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): Layer: %W  Selectable:%W  Visible: %W\n"), layer->GetName().c_str(), layer->GetSelectable()? L"True" : L"False", layer->IsVisibleAtScale(scale)? L"True" : L"False"));
+
+        //do this first - this check is fast
+        if (bOnlySelectableLayers && !layer->GetSelectable())
+            continue;
+
+        //do we want to select on this layer -- if caller
+        //gave us a layer name collection, check if the layer
+        //is in there
+        if (layerNames && layerNames->GetCount() > 0 && layerNames->IndexOf(layer->GetName()) == -1)
+            continue;
+
+        //check the visibility at scale if we're not ignoring scale ranges
+        if (bOnlyVisibleLayers && !layer->IsVisibleAtScale(scale))
+            continue;
+
+        //if we only want layers with tooltips, check that this layer has tooltips
+        if (bOnlyTooltipLayers)
+        {
+//          layer->GetLayerInfoFromDefinition(m_svcResource);
+            if (!layer->HasTooltips())
+                continue;
+        }
+
+        //have we processed enough features already?
+        if (maxFeatures <= 0)
+            break;
+
+        //get the MDF layer definition
+        Ptr<MgResourceIdentifier> layerResId = layer->GetLayerDefinition();
+        auto_ptr<MdfModel::LayerDefinition> ldf(MgLayerBase::GetLayerDefinition(m_svcResource, layerResId));
+        MdfModel::VectorLayerDefinition* vl = dynamic_cast<MdfModel::VectorLayerDefinition*>(ldf.get());
+
+        //we can only do geometric query selection for vector layers
+        if (vl)
+        {
+            ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): Layer: %W  Vector Layer\n"), layer->GetName().c_str()));
+
+            //check to see if we want even layers that aren't visible at the current scale
+            if (!bOnlyVisibleLayers)
+            {
+                // Modify the layer scale range only for layers that are passed in
+                MdfModel::VectorScaleRangeCollection* scaleRanges = vl->GetScaleRanges();
+                if (scaleRanges)
+                {
+                    MdfModel::VectorScaleRange* scaleRange = scaleRanges->GetAt(0);
+                    if (scaleRange)
+                    {
+                        scaleRange->SetMinScale(0.0);
+                        scaleRange->SetMaxScale(MdfModel::VectorScaleRange::MAX_MAP_SCALE);
+                    }
+                }
+            }
+
+            Ptr<MgResourceIdentifier> featResId = new MgResourceIdentifier(layer->GetFeatureSourceId());
+
+            //get a transform from layer coord sys to map coord sys
+            Ptr<MgCoordinateSystem> mapCs = srs.empty()? NULL : m_pCSFactory->Create(srs);
+            TransformCache* item = TransformCache::GetLayerToMapTransform(transformCache, vl->GetFeatureName(), featResId, mapCs, m_pCSFactory, m_svcFeature);
+            Ptr<MgCoordinateSystemTransform> trans = item? item->GetMgTransform() : NULL;
+            MgCSTrans* xformer = item? item->GetTransform() : NULL;
+
+            Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
+            Ptr<MgGeometricEntity> queryGeom;
+            if (geometry != NULL)
+            {
+                //if we have a valid transform, get the request geom in layer's space
+                queryGeom = SAFE_ADDREF(geometry);
+                STRING geomTextSource = queryGeom->ToAwkt(true);
+                if (trans)
+                {
+                    //get selection geometry in layer space
+                    queryGeom = geometry->Transform(trans);
+                }
+
+                #ifdef _DEBUG
+                // Output the selection geometry
+                STRING geomText = queryGeom->ToAwkt(true);
+                ACE_DEBUG((LM_INFO, ACE_TEXT("(%t) SELECTION FILTER:\n%W\n\n"), geomText.c_str()));
+                #endif
+
+                //set the spatial filter for the selection
+                options->SetSpatialFilter(layer->GetFeatureGeometryName(), (MgGeometry*)(queryGeom.p), /*MgFeatureSpatialOperations*/selectionVariant);
+            }
+
+            // Initialize the reader
+            auto_ptr<RSMgFeatureReader> rsrdr;
+
+            try
+            {
+                if (!featureFilter.empty())
+                {
+                    //set the feature filter, if any
+                    MgdSelection selectionFilter(map, featureFilter);
+                    Ptr<MgReadOnlyLayerCollection> layers = selectionFilter.GetLayers();
+                    if (layers != NULL)
+                    {
+                        for (int i = 0; i < layers->GetCount(); i++)
+                        {
+                            Ptr<MgLayerBase> layer = layers->GetItem(i);
+                            STRING className = layer->GetFeatureClassName();
+                            STRING filter = selectionFilter.GenerateFilter(layer, className);
+                            options->SetFilter(filter);
+                        }
+                    }
+                }
+                else if (!vl->GetFilter().empty())
+                {
+                    //set layer feature filter if any
+                    options->SetFilter(vl->GetFilter());
+                }
+
+                // TODO: can FeatureName be an extension name rather than a FeatureClass?
+                // The reader below needs to be closed and released before the intersectPolygon SelectFeatures below happens
+                // or we end up with a reference count issue that causes a new FDO connection to be cached instead of
+                // reusing the already existing one.
+                Ptr<MgFeatureReader> rdr = m_svcFeature->SelectFeatures(featResId, vl->GetFeatureName(), options);
+                rsrdr.reset(new RSMgFeatureReader(rdr, m_svcFeature, featResId, options, vl->GetGeometry()));
+
+                // Note that the FdoIFeatureReader smart pointer below is created
+                // inside the following IF statement to ensure it gets destroyed
+                // BEFORE the RSMgFeatureReader object above goes out of scope,
+                // even when an exception gets thrown.
+                if (FdoPtr<FdoIFeatureReader>(rsrdr->GetInternalReader()))
+                {
+                    //run a stylization loop with the FeatureInfoRenderer.
+                    //This will build up the selection set and also
+                    //evaluate the tooltip, hyperlink and feature properties
+                    //for the first feature hit
+
+                    RS_UIGraphic uig(NULL, 0, L"");
+                    RS_LayerUIInfo layerinfo(layer->GetName(),
+                                             layer->GetObjectId(), // object ID
+                                             true,   // selectable
+                                             true,   // visible
+                                             true,   // editable
+                                             L"",    // group name
+                                             L"",    // group ID
+                                             true,   // showInLegend
+                                             true,   // expandInLegend
+                                             0.0,    // zOrder
+                                             uig);   // uiGraphic
+
+                    //extract hyperlink and tooltip info
+                    if (!vl->GetToolTip().empty()) 
+                        layerinfo.hastooltips() = true;
+                    if (vl->GetUrlData() && !vl->GetUrlData()->GetUrlContent().empty()) 
+                        layerinfo.hashyperlinks() = true;
+
+                    //set up the property name mapping -- it tells us what
+                    //string the viewer should be displaying as the name of each
+                    //feature property
+                    // TODO: can FeatureName be an extension name rather than a FeatureClass?
+                    RS_FeatureClassInfo fcinfo(vl->GetFeatureName());
+
+                    MdfModel::NameStringPairCollection* pmappings = vl->GetPropertyMappings();
+                    for (int i=0; i<pmappings->GetCount(); i++)
+                    {
+                        MdfModel::NameStringPair* m = pmappings->GetAt(i);
+                        fcinfo.add_mapping(m->GetName(), m->GetValue());
+                    }
+
+                    selRenderer->StartLayer(&layerinfo, &fcinfo);
+                    ds.StylizeVectorLayer(vl, selRenderer, rsrdr.get(), NULL, scale, StylizeThatMany, selRenderer);
+
+                    // Clear the readers in case they are reused below
+                    rdr = NULL;
+                    rsrdr.reset();
+
+                    int numFeaturesProcessed = selRenderer->GetNumFeaturesProcessed();
+                    if (!numFeaturesProcessed && selRenderer->NeedPointTest())
+                    {
+                        // Construct a square selection area 400x larger than then previous area
+                        // centered around the centroid of the original selection area
+                        // Example:  a 4x4 pixel selection area becomes an 80x80 pixel selection area
+                        Ptr<MgPoint> centroid = queryGeom->GetCentroid();
+                        Ptr<MgCoordinate> ctr = centroid->GetCoordinate();
+                        double area = queryGeom->GetArea();
+                        double delta = sqrt(area) * 10.0;
+
+                        // Only process selection if we have a valid area.  The input geometry may not have a
+                        // centroid if it is outside the bounds of the coordinate system.  GetArea() will
+                        // return zero in these cases.
+                        if (delta > 0.0)
+                        {
+                            Ptr<MgCoordinateCollection> coordinates = new MgCoordinateCollection();
+                            Ptr<MgCoordinateXY> coord1 = new MgCoordinateXY(ctr->GetX() - delta, ctr->GetY() - delta);
+                            coordinates->Add(coord1);
+                            Ptr<MgCoordinateXY> coord2 = new MgCoordinateXY(ctr->GetX() - delta, ctr->GetY() + delta);
+                            coordinates->Add(coord2);
+                            Ptr<MgCoordinateXY> coord3 = new MgCoordinateXY(ctr->GetX() + delta, ctr->GetY() + delta);
+                            coordinates->Add(coord3);
+                            Ptr<MgCoordinateXY> coord4 = new MgCoordinateXY(ctr->GetX() + delta, ctr->GetY() - delta);
+                            coordinates->Add(coord4);
+                            coordinates->Add(coord1);
+                            Ptr<MgLinearRing> outerRing = new MgLinearRing(coordinates);
+                            Ptr<MgPolygon> polygon = new MgPolygon(outerRing, NULL);
+
+                            // The selection area may extent past the map extents so clip the selection area to the map extent
+                            Ptr<MgEnvelope> extent = map->GetMapExtent();
+                            Ptr<MgCoordinate> llCoord = extent->GetLowerLeftCoordinate();
+                            Ptr<MgCoordinate> urCoord = extent->GetUpperRightCoordinate();
+                            Ptr<MgCoordinateCollection> extentCoords = new MgCoordinateCollection();
+                            Ptr<MgCoordinateXY> c1 = new MgCoordinateXY(llCoord->GetX(), llCoord->GetY());
+                            extentCoords->Add(c1);
+                            Ptr<MgCoordinateXY> c2 = new MgCoordinateXY(llCoord->GetX(), urCoord->GetY());
+                            extentCoords->Add(c2);
+                            Ptr<MgCoordinateXY> c3 = new MgCoordinateXY(urCoord->GetX(), urCoord->GetY());
+                            extentCoords->Add(c3);
+                            Ptr<MgCoordinateXY> c4 = new MgCoordinateXY(urCoord->GetX(), llCoord->GetY());
+                            extentCoords->Add(c4);
+                            extentCoords->Add(c1);
+                            Ptr<MgLinearRing> extentRing = new MgLinearRing(extentCoords);
+                            Ptr<MgPolygon> extentPolygon = new MgPolygon(extentRing, NULL);
+
+                            Ptr<MgGeometricEntity> queryExtentPolygon = extentPolygon;
+                            if (trans)
+                            {
+                                //get selection geometry in layer space
+                                queryExtentPolygon = extentPolygon->Transform(trans);
+                            }
+                            Ptr<MgGeometry> intersectPolygon = polygon->Intersection((MgPolygon *)queryExtentPolygon.p);
+
+                            if (intersectPolygon != NULL)
+                            {
+                                options->SetSpatialFilter(layer->GetFeatureGeometryName(), intersectPolygon, /*MgFeatureSpatialOperations*/selectionVariant);
+
+                                rdr = m_svcFeature->SelectFeatures(featResId, vl->GetFeatureName(), options);
+                                rsrdr.reset(new RSMgFeatureReader(rdr, m_svcFeature, featResId, options, vl->GetGeometry()));
+                                selRenderer->PointTest(true);
+                                ds.StylizeVectorLayer(vl, selRenderer, rsrdr.get(), xformer, scale, StylizeThatMany, selRenderer);
+
+                                // Clear the readers
+                                rdr = NULL;
+                                rsrdr.reset();
+
+                                selRenderer->PointTest(false);
+                                numFeaturesProcessed = selRenderer->GetNumFeaturesProcessed();
+                            }
+                        }
+                    }
+                    selRenderer->EndLayer();
+
+                    //update maxFeatures to number of features that
+                    //we can select from subsequent layers
+                    maxFeatures -= numFeaturesProcessed;
+                }
+            }
+            catch (MgFdoException* e)
+            {
+                //TODO: what should we really be doing in this case?
+                //This can happen if the underlying FDO provider does not
+                //support a particular spatial operation. One way around this
+                //is to select all features which appear on the screen and then
+                //do our own geometry math.
+                #ifdef _DEBUG
+                STRING error = e->GetExceptionMessage();
+                ACE_DEBUG((LM_INFO, ACE_TEXT("(%t) RenderForSelection() - Error: %S\n"), error.c_str()));
+                #endif
+
+                // Let's throw the exception here, so that it can be recorded in the error log.
+                throw e;
+            }
+        }
+    }
+
+    selRenderer->EndMap();
+    ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) RenderForSelection(): ** END **\n")));
+
+    MG_CATCH(L"MgServerRenderingService.RenderForSelection")
+
+    TransformCache::Clear(transformCache);
+
+    MG_THROW()
 }
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.h	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/RenderingService.h	2012-06-26 15:31:55 UTC (rev 6819)
@@ -2,6 +2,7 @@
 #define DESKTOP_RENDERING_SERVICE_H
 
 class MgdMap;
+class MgdFeatureInformation;
 class SE_Renderer;
 class MgRenderingOptions;
 class FeatureInfoRenderer;
@@ -74,6 +75,21 @@
                                           INT32 height,
                                           MgColor* backgroundColor,
                                           CREFSTRING format);
+
+    virtual MgdFeatureInformation* QueryFeatures(MgdMap* map,
+                                                 MgStringCollection* layerNames,
+                                                 MgGeometry* filterGeometry,
+                                                 INT32 selectionVariant,
+                                                 INT32 maxFeatures);
+
+    virtual MgdFeatureInformation* QueryFeatures(MgdMap* map,
+                                                 MgStringCollection* layerNames,
+                                                 MgGeometry* filterGeometry,
+                                                 INT32 selectionVariant,
+                                                 CREFSTRING featureFilter,
+                                                 INT32 maxFeatures,
+                                                 INT32 layerAttributeFilter);
+
 INTERNAL_API:
 
     virtual MgByteReader* RenderDynamicOverlay(MgdMap* map,
@@ -141,6 +157,14 @@
                                     MdfModel::ProfileRenderMapResult* pPRMResult = NULL);
 
 private:
+    MgdFeatureInformation* QueryFeaturesInternal(MgdMap* map,
+                                                 MgStringCollection* layerNames,
+                                                 MgGeometry* filterGeometry,
+                                                 INT32 selectionVariant,
+                                                 CREFSTRING featureFilter,
+                                                 INT32 maxFeatures,
+                                                 INT32 layerAttributeFilter);
+
     // used for tile generation
     MgByteReader* RenderTile(MgdMap* map,
                              MgLayerGroup* baseGroup,
@@ -199,14 +223,14 @@
                                     bool renderWatermark,
                                     MdfModel::ProfileRenderMapResult* pPRMResult = NULL);
 
-    void RenderForSelection(MgMap* map,
-                         MgStringCollection* layerNames,
-                         MgGeometry* geometry,
-                         INT32 selectionVariant,
-                         CREFSTRING featureFilter,
-                         INT32 maxFeatures,
-                         INT32 layerAttributeFilter,
-                         FeatureInfoRenderer* selRenderer);
+    void RenderForSelection(MgdMap* map,
+                            MgStringCollection* layerNames,
+                            MgGeometry* geometry,
+                            INT32 selectionVariant,
+                            CREFSTRING featureFilter,
+                            INT32 maxFeatures,
+                            INT32 layerAttributeFilter,
+                            FeatureInfoRenderer* selRenderer);
 
     SE_Renderer* CreateRenderer(int width,
                                 int height,

Modified: branches/2.4/MgDev/Desktop/MgDesktop/System/ClassId.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/System/ClassId.h	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/MgDesktop/System/ClassId.h	2012-06-26 15:31:55 UTC (rev 6819)
@@ -111,7 +111,7 @@
 
 // Rendering Service
 #define MapGuide_Desktop_RenderingService_RenderingService                  MAPGUIDE_DESKTOP_RENDERINGSERVICE_ID+0
-//#define MapGuide_Desktop_RenderingService_FeatureInformation                MAPGUIDE_DESKTOP_RENDERINGSERVICE_ID+1
+#define MapGuide_Desktop_RenderingService_FeatureInformation                MAPGUIDE_DESKTOP_RENDERINGSERVICE_ID+1
 #define MapGuide_Desktop_RenderingService_RenderingOptions                  MAPGUIDE_DESKTOP_RENDERINGSERVICE_ID+2
 
 // Resource Service

Modified: branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.cpp	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.cpp	2012-06-26 15:31:55 UTC (rev 6819)
@@ -575,7 +575,6 @@
     }
 }
 
-/*
 void TestRenderingService::TestCase_QueryFeatures()
 {
     try
@@ -590,7 +589,7 @@
         layerNames1->Add(L"Rail");
         layerNames1->Add(L"HydrographicPolygons");
         Ptr<MgPolygon> poly1 = CreateSelectionPolygon(map, 0.3, 0.3);
-        Ptr<MgFeatureInformation> fi1 = m_svcRendering->QueryFeatures(map, layerNames1, poly1, MgFeatureSpatialOperations::Within, -1);
+        Ptr<MgdFeatureInformation> fi1 = m_svcRendering->QueryFeatures(map, layerNames1, poly1, MgFeatureSpatialOperations::Within, -1);
 
         // call the API using a scale of 12000
         map->SetViewScale(12000.0);
@@ -599,7 +598,7 @@
         layerNames2->Add(L"Rail");
         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<MgdFeatureInformation> fi2 = m_svcRendering->QueryFeatures(map, layerNames2, poly2, MgFeatureSpatialOperations::Within, -1);
     }
     catch (MgException* e)
     {
@@ -612,7 +611,6 @@
         throw;
     }
 }
-*/
 
 MgdMap* TestRenderingService::CreateTestMapWithWatermark()
 {

Modified: branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.h
===================================================================
--- branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.h	2012-06-26 14:37:25 UTC (rev 6818)
+++ branches/2.4/MgDev/Desktop/UnitTest/TestRenderingService.h	2012-06-26 15:31:55 UTC (rev 6819)
@@ -39,7 +39,7 @@
     CPPUNIT_TEST(TestCase_RenderMap);
     CPPUNIT_TEST(TestCase_RenderMapWithWatermark);
     CPPUNIT_TEST(TestCase_RenderLegend);
-    //CPPUNIT_TEST(TestCase_QueryFeatures);
+    CPPUNIT_TEST(TestCase_QueryFeatures);
 
     //CPPUNIT_TEST(TestCase_RendererPerformance);
 
@@ -59,7 +59,7 @@
     void TestCase_RenderMap();
     void TestCase_RenderMapWithWatermark();
     void TestCase_RenderLegend();
-    //void TestCase_QueryFeatures();
+    void TestCase_QueryFeatures();
 
     void TestCase_SymbologyPoints();
     void TestCase_SymbologyPointsParam();



More information about the mapguide-commits mailing list