[mapguide-commits] r6644 - in branches/2.4/MgDev/Desktop: MapViewer MapViewer/Properties MapViewer/Resources MapViewerTest MgDesktop MgDesktop/Services MgDesktop/Services/Feature

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sat May 12 22:45:18 EDT 2012


Author: jng
Date: 2012-05-12 19:45:17 -0700 (Sat, 12 May 2012)
New Revision: 6644

Added:
   branches/2.4/MgDev/Desktop/MapViewer/MgThemeComponent.cs
   branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.Designer.cs
   branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.cs
   branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.resx
   branches/2.4/MgDev/Desktop/MapViewer/Resources/AreaRuleTemplate.txt
   branches/2.4/MgDev/Desktop/MapViewer/Util.cs
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/BooleanDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ByteDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DateTimeDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DoubleDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeautreNumericFunctions.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GeometryDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int16DataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int32DataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int64DataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Matrix.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/SingleDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/StringDataReaderCreator.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/UniqueFunction.h
Modified:
   branches/2.4/MgDev/Desktop/MapViewer/MapViewer.csproj
   branches/2.4/MgDev/Desktop/MapViewer/MgBufferControlImpl.cs
   branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.Designer.cs
   branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.resx
   branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.Designer.cs
   branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.resx
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj
   branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.h
   branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp
   branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h
Log:
This mg-desktop submission includes the following changes:
 - Add in required classes to MgDesktop to support the custom theming and distribution functions (needed by the next item in this submission)
 - Add a Theme component to the Map Viewer (straight port of the .net sample)

Modified: branches/2.4/MgDev/Desktop/MapViewer/MapViewer.csproj
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MapViewer.csproj	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MapViewer/MapViewer.csproj	2012-05-13 02:45:17 UTC (rev 6644)
@@ -160,6 +160,15 @@
     <Compile Include="MgTaskPane.Designer.cs">
       <DependentUpon>MgTaskPane.cs</DependentUpon>
     </Compile>
+    <Compile Include="MgThemeComponent.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="MgThemeControlImpl.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="MgThemeControlImpl.Designer.cs">
+      <DependentUpon>MgThemeControlImpl.cs</DependentUpon>
+    </Compile>
     <Compile Include="MgViewerOptionsComponent.cs">
       <SubType>Component</SubType>
     </Compile>
@@ -181,6 +190,7 @@
     <Compile Include="Tasks\MgTaskPaneStub.Designer.cs">
       <DependentUpon>MgTaskPaneStub.cs</DependentUpon>
     </Compile>
+    <Compile Include="Util.cs" />
     <Service Include="{94E38DFF-614B-4cbd-B67C-F211BB35CE8B}" />
   </ItemGroup>
   <ItemGroup>
@@ -212,6 +222,9 @@
     <EmbeddedResource Include="MgTaskPane.resx">
       <DependentUpon>MgTaskPane.cs</DependentUpon>
     </EmbeddedResource>
+    <EmbeddedResource Include="MgThemeControlImpl.resx">
+      <DependentUpon>MgThemeControlImpl.cs</DependentUpon>
+    </EmbeddedResource>
     <EmbeddedResource Include="MgViewerOptionsControlImpl.resx">
       <DependentUpon>MgViewerOptionsControlImpl.cs</DependentUpon>
     </EmbeddedResource>
@@ -411,6 +424,7 @@
   </ItemGroup>
   <ItemGroup>
     <Content Include="Resources\AreaLayerDef.txt" />
+    <None Include="Resources\AreaRuleTemplate.txt" />
     <None Include="Resources\view_log.gif" />
     <None Include="Resources\monitor_status.gif" />
     <None Include="Resources\load_package.gif" />

Modified: branches/2.4/MgDev/Desktop/MapViewer/MgBufferControlImpl.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgBufferControlImpl.cs	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgBufferControlImpl.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -116,7 +116,7 @@
                 MgResourceIdentifier fsId = new MgResourceIdentifier("Session:" + _sessionId + "//" + txtBufferLayer.Text + "_Buffer.FeatureSource");
                 MgResourceIdentifier ldfId = new MgResourceIdentifier("Session:" + _sessionId + "//" + txtBufferLayer.Text + "_Buffer.LayerDefinition");
 
-                MgLayerBase layer = FindLayer(layers, txtBufferLayer.Text);
+                MgLayerBase layer = Util.FindLayer(layers, txtBufferLayer.Text);
                 string[] layerNames = GetLayerNames();
 
                 double distance = Convert.ToDouble(numBufferDistance.Value);
@@ -134,7 +134,7 @@
                         break;
                 }
 
-                String srsDefMap = GetMapSrs(map);
+                String srsDefMap = Util.GetMapSrs(map);
                 MgCoordinateSystem srsMap = provider.GetMapCoordinateSystem();
                 string mapSrsUnits = "";
                 bool arbitraryMapSrs = (srsMap.GetType() == MgCoordinateSystemType.Arbitrary);
@@ -142,9 +142,9 @@
                     mapSrsUnits = srsMap.GetUnits();
 
                 String xtrans = String.Format("{0:x2}", ((int)(255 * Convert.ToInt32(numFillTransparency.Value) / 100)));
-                var lineColor = ToHtmlColor(pnlBorderColor.BackColor);
-                var foreColor = ToHtmlColor(pnlFillColor.BackColor);
-                var backColor = ToHtmlColor(pnlFillBackColor.BackColor);
+                var lineColor = Util.ToHtmlColor(pnlBorderColor.BackColor);
+                var foreColor = Util.ToHtmlColor(pnlFillColor.BackColor);
+                var backColor = Util.ToHtmlColor(pnlFillBackColor.BackColor);
                 String layerTempl = string.Format(Properties.Resources.AreaLayerDef,
                         fsId.ToString(),
                         "BufferSchema:Buffer",
@@ -213,7 +213,7 @@
                 {
                     //data source already exist. clear its content
                     //
-                    ClearDataSource(_featSvc, fsId, "BufferSchema:Buffer");
+                    Util.ClearDataSource(_featSvc, fsId, "BufferSchema:Buffer");
                 }
 
                 var sel = _viewer.GetSelection();
@@ -331,7 +331,7 @@
                                 {
                                     if (srsXform != null)
                                         geomBuffer = (MgGeometry)geomBuffer.Transform(srsXform);
-                                    AddFeatureToCollection(propCollection, agfRW, featId++, geomBuffer);
+                                    Util.AddFeatureToCollection(propCollection, agfRW, featId++, geomBuffer);
                                     bufferFeatures++;
                                 }
                             }
@@ -363,7 +363,7 @@
                         geomBuffer = geomFactory.CreateMultiGeometry(inputGeometries).Buffer(dist, measure);
                         if (geomBuffer != null)
                         {
-                            AddFeatureToCollection(propCollection, agfRW, featId, geomBuffer);
+                            Util.AddFeatureToCollection(propCollection, agfRW, featId, geomBuffer);
                             bufferFeatures = 1;
                         }
                     }
@@ -375,7 +375,7 @@
 
                     //Insert the features in the temporary data source
                     //
-                    ReleaseReader(_featSvc.UpdateFeatures(fsId, commands, false), commands);
+                    Util.ReleaseReader(_featSvc.UpdateFeatures(fsId, commands, false), commands);
                 }
 
                 // Save the new map state
@@ -401,86 +401,6 @@
             }
             return items.ToArray();
         }
-
-        static string ToHtmlColor(Color color)
-        {
-            return String.Format("{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
-        }
-
-        static MgLayerBase FindLayer(MgLayerCollection layers, String layerName)
-        {
-            MgLayerBase layer = null;
-            int i = 0;
-            for (i = 0; i < layers.GetCount(); i++)
-            {
-                MgLayerBase layer1 = layers.GetItem(i);
-
-                if (layer1.GetName() == layerName)
-                {
-                    layer = layer1;
-                    break;
-                }
-            }
-            return layer;
-        }
-
-        static string GetMapSrs(MgMapBase map)
-        {
-            try
-            {
-                String srs = map.GetMapSRS();
-                if (srs != "")
-                    return srs;
-            }
-            catch (MgException e)
-            {
-            }
-
-            //No SRS, set to ArbitrayXY meters
-            //
-            return "LOCALCS[\"Non-Earth (Meter)\",LOCAL_DATUM[\"Local Datum\",0],UNIT[\"Meter\", 1],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]";
-        }
-
-        static void ClearDataSource(MgFeatureService featSvc, MgResourceIdentifier fsId, String featureName)
-        {
-            MgDeleteFeatures deleteCmd = new MgDeleteFeatures(featureName, "ID >= 0");
-            MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
-            commands.Add(deleteCmd);
-            featSvc.UpdateFeatures(fsId, commands, false);
-        }
-
-        static void ReleaseReader(MgPropertyCollection res, MgFeatureCommandCollection commands)
-        {
-            if (res == null)
-                return;
-
-            for (int i = 0; i < res.GetCount(); i++)
-            {
-                MgFeatureCommand cmd = commands.GetItem(i);
-                if (cmd is MgInsertFeatures)
-                {
-                    MgFeatureProperty resProp = res.GetItem(i) as MgFeatureProperty;
-                    if (resProp != null)
-                    {
-                        MgFeatureReader reader = resProp.GetValue() as MgFeatureReader;
-                        if (reader == null)
-                            return;
-                        reader.Close();
-                    }
-                }
-            }
-        }
-
-        static void AddFeatureToCollection(MgBatchPropertyCollection propCollection, MgAgfReaderWriter agfRW, int featureId, MgGeometry featureGeom)
-        {
-            MgPropertyCollection bufferProps = new MgPropertyCollection();
-            MgInt32Property idProp = new MgInt32Property("ID", featureId);
-            bufferProps.Add(idProp);
-            MgByteReader geomReader = agfRW.Write(featureGeom);
-            MgGeometryProperty geomProp = new MgGeometryProperty("GEOM", geomReader);
-            bufferProps.Add(geomProp);
-            propCollection.Add(bufferProps);
-        }
     }
 
     public enum StockPattern

Added: branches/2.4/MgDev/Desktop/MapViewer/MgThemeComponent.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgThemeComponent.cs	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgThemeComponent.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.ComponentModel;
+
+namespace OSGeo.MapGuide.Viewer
+{
+    [ToolboxItem(true)]
+    public class MgThemeComponent : MgViewerComponent
+    {
+        public MgThemeComponent()
+        {
+            this.Icon = Properties.Resources.lc_theme;
+            this.Label = this.ToolTipText = Properties.Resources.TitleTheme;
+        }
+
+        protected override MgControlImpl CreateControlImpl()
+        {
+            return new MgThemeControlImpl(this.Viewer);
+        }
+    }
+}

Added: branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.Designer.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.Designer.cs	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.Designer.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,511 @@
+namespace OSGeo.MapGuide.Viewer
+{
+    partial class MgThemeControlImpl
+    {
+        /// <summary> 
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary> 
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Component Designer generated code
+
+        /// <summary> 
+        /// Required method for Designer support - do not modify 
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.txtThemeName = new System.Windows.Forms.TextBox();
+            this.label2 = new System.Windows.Forms.Label();
+            this.cmbLayer = new System.Windows.Forms.ComboBox();
+            this.label1 = new System.Windows.Forms.Label();
+            this.groupBox2 = new System.Windows.Forms.GroupBox();
+            this.numRules = new System.Windows.Forms.NumericUpDown();
+            this.cmbScaleRange = new System.Windows.Forms.ComboBox();
+            this.label8 = new System.Windows.Forms.Label();
+            this.txtMax = new System.Windows.Forms.TextBox();
+            this.txtMin = new System.Windows.Forms.TextBox();
+            this.cmbDistribution = new System.Windows.Forms.ComboBox();
+            this.cmbProperty = new System.Windows.Forms.ComboBox();
+            this.label7 = new System.Windows.Forms.Label();
+            this.label6 = new System.Windows.Forms.Label();
+            this.label5 = new System.Windows.Forms.Label();
+            this.label4 = new System.Windows.Forms.Label();
+            this.label3 = new System.Windows.Forms.Label();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.btnToBorderColor = new System.Windows.Forms.Button();
+            this.pnlToBorderColor = new System.Windows.Forms.Panel();
+            this.btnFromBorderColor = new System.Windows.Forms.Button();
+            this.btnToFillColor = new System.Windows.Forms.Button();
+            this.pnlFromBorderColor = new System.Windows.Forms.Panel();
+            this.btnFromFillColor = new System.Windows.Forms.Button();
+            this.pnlToFillColor = new System.Windows.Forms.Panel();
+            this.pnlFromFillColor = new System.Windows.Forms.Panel();
+            this.label14 = new System.Windows.Forms.Label();
+            this.label15 = new System.Windows.Forms.Label();
+            this.label13 = new System.Windows.Forms.Label();
+            this.label12 = new System.Windows.Forms.Label();
+            this.label11 = new System.Windows.Forms.Label();
+            this.label10 = new System.Windows.Forms.Label();
+            this.numFillTransparency = new System.Windows.Forms.NumericUpDown();
+            this.label9 = new System.Windows.Forms.Label();
+            this.btnApply = new System.Windows.Forms.Button();
+            this.colorDialog = new System.Windows.Forms.ColorDialog();
+            this.groupBox1.SuspendLayout();
+            this.groupBox2.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.numRules)).BeginInit();
+            this.groupBox3.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.numFillTransparency)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // groupBox1
+            // 
+            this.groupBox1.Controls.Add(this.txtThemeName);
+            this.groupBox1.Controls.Add(this.label2);
+            this.groupBox1.Controls.Add(this.cmbLayer);
+            this.groupBox1.Controls.Add(this.label1);
+            this.groupBox1.Dock = System.Windows.Forms.DockStyle.Top;
+            this.groupBox1.Location = new System.Drawing.Point(0, 0);
+            this.groupBox1.Name = "groupBox1";
+            this.groupBox1.Size = new System.Drawing.Size(269, 112);
+            this.groupBox1.TabIndex = 0;
+            this.groupBox1.TabStop = false;
+            this.groupBox1.Text = "General";
+            // 
+            // txtThemeName
+            // 
+            this.txtThemeName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtThemeName.Location = new System.Drawing.Point(15, 79);
+            this.txtThemeName.Name = "txtThemeName";
+            this.txtThemeName.Size = new System.Drawing.Size(237, 20);
+            this.txtThemeName.TabIndex = 3;
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(12, 63);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(71, 13);
+            this.label2.TabIndex = 2;
+            this.label2.Text = "Theme Name";
+            // 
+            // cmbLayer
+            // 
+            this.cmbLayer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.cmbLayer.DisplayMember = "Name";
+            this.cmbLayer.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cmbLayer.FormattingEnabled = true;
+            this.cmbLayer.Location = new System.Drawing.Point(15, 35);
+            this.cmbLayer.Name = "cmbLayer";
+            this.cmbLayer.Size = new System.Drawing.Size(237, 21);
+            this.cmbLayer.TabIndex = 1;
+            this.cmbLayer.SelectedIndexChanged += new System.EventHandler(this.cmbLayer_SelectedIndexChanged);
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(12, 19);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(57, 13);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "Map Layer";
+            // 
+            // groupBox2
+            // 
+            this.groupBox2.Controls.Add(this.numRules);
+            this.groupBox2.Controls.Add(this.cmbScaleRange);
+            this.groupBox2.Controls.Add(this.label8);
+            this.groupBox2.Controls.Add(this.txtMax);
+            this.groupBox2.Controls.Add(this.txtMin);
+            this.groupBox2.Controls.Add(this.cmbDistribution);
+            this.groupBox2.Controls.Add(this.cmbProperty);
+            this.groupBox2.Controls.Add(this.label7);
+            this.groupBox2.Controls.Add(this.label6);
+            this.groupBox2.Controls.Add(this.label5);
+            this.groupBox2.Controls.Add(this.label4);
+            this.groupBox2.Controls.Add(this.label3);
+            this.groupBox2.Dock = System.Windows.Forms.DockStyle.Top;
+            this.groupBox2.Location = new System.Drawing.Point(0, 112);
+            this.groupBox2.Name = "groupBox2";
+            this.groupBox2.Size = new System.Drawing.Size(269, 276);
+            this.groupBox2.TabIndex = 1;
+            this.groupBox2.TabStop = false;
+            this.groupBox2.Text = "Theme Conditions";
+            // 
+            // numRules
+            // 
+            this.numRules.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.numRules.Location = new System.Drawing.Point(110, 198);
+            this.numRules.Name = "numRules";
+            this.numRules.Size = new System.Drawing.Size(141, 20);
+            this.numRules.TabIndex = 12;
+            // 
+            // cmbScaleRange
+            // 
+            this.cmbScaleRange.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.cmbScaleRange.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cmbScaleRange.FormattingEnabled = true;
+            this.cmbScaleRange.Location = new System.Drawing.Point(15, 241);
+            this.cmbScaleRange.Name = "cmbScaleRange";
+            this.cmbScaleRange.Size = new System.Drawing.Size(237, 21);
+            this.cmbScaleRange.TabIndex = 11;
+            // 
+            // label8
+            // 
+            this.label8.AutoSize = true;
+            this.label8.Location = new System.Drawing.Point(12, 225);
+            this.label8.Name = "label8";
+            this.label8.Size = new System.Drawing.Size(69, 13);
+            this.label8.TabIndex = 10;
+            this.label8.Text = "Scale Range";
+            // 
+            // txtMax
+            // 
+            this.txtMax.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtMax.Location = new System.Drawing.Point(15, 123);
+            this.txtMax.Name = "txtMax";
+            this.txtMax.Size = new System.Drawing.Size(237, 20);
+            this.txtMax.TabIndex = 9;
+            // 
+            // txtMin
+            // 
+            this.txtMin.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtMin.Location = new System.Drawing.Point(15, 79);
+            this.txtMin.Name = "txtMin";
+            this.txtMin.Size = new System.Drawing.Size(237, 20);
+            this.txtMin.TabIndex = 8;
+            // 
+            // cmbDistribution
+            // 
+            this.cmbDistribution.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.cmbDistribution.DisplayMember = "Value";
+            this.cmbDistribution.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cmbDistribution.FormattingEnabled = true;
+            this.cmbDistribution.Location = new System.Drawing.Point(15, 167);
+            this.cmbDistribution.Name = "cmbDistribution";
+            this.cmbDistribution.Size = new System.Drawing.Size(237, 21);
+            this.cmbDistribution.TabIndex = 7;
+            this.cmbDistribution.ValueMember = "Key";
+            this.cmbDistribution.SelectedIndexChanged += new System.EventHandler(this.cmbDistribution_SelectedIndexChanged);
+            // 
+            // cmbProperty
+            // 
+            this.cmbProperty.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.cmbProperty.DisplayMember = "Name";
+            this.cmbProperty.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cmbProperty.FormattingEnabled = true;
+            this.cmbProperty.Location = new System.Drawing.Point(15, 36);
+            this.cmbProperty.Name = "cmbProperty";
+            this.cmbProperty.Size = new System.Drawing.Size(237, 21);
+            this.cmbProperty.TabIndex = 6;
+            this.cmbProperty.SelectedIndexChanged += new System.EventHandler(this.cmbProperty_SelectedIndexChanged);
+            // 
+            // label7
+            // 
+            this.label7.AutoSize = true;
+            this.label7.Location = new System.Drawing.Point(12, 200);
+            this.label7.Name = "label7";
+            this.label7.Size = new System.Drawing.Size(86, 13);
+            this.label7.TabIndex = 4;
+            this.label7.Text = "Number of Rules";
+            // 
+            // label6
+            // 
+            this.label6.AutoSize = true;
+            this.label6.Location = new System.Drawing.Point(12, 151);
+            this.label6.Name = "label6";
+            this.label6.Size = new System.Drawing.Size(59, 13);
+            this.label6.TabIndex = 3;
+            this.label6.Text = "Distribution";
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(12, 107);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(27, 13);
+            this.label5.TabIndex = 2;
+            this.label5.Text = "Max";
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(12, 63);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(24, 13);
+            this.label4.TabIndex = 1;
+            this.label4.Text = "Min";
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(12, 20);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(46, 13);
+            this.label3.TabIndex = 0;
+            this.label3.Text = "Property";
+            // 
+            // groupBox3
+            // 
+            this.groupBox3.Controls.Add(this.btnToBorderColor);
+            this.groupBox3.Controls.Add(this.pnlToBorderColor);
+            this.groupBox3.Controls.Add(this.btnFromBorderColor);
+            this.groupBox3.Controls.Add(this.btnToFillColor);
+            this.groupBox3.Controls.Add(this.pnlFromBorderColor);
+            this.groupBox3.Controls.Add(this.btnFromFillColor);
+            this.groupBox3.Controls.Add(this.pnlToFillColor);
+            this.groupBox3.Controls.Add(this.pnlFromFillColor);
+            this.groupBox3.Controls.Add(this.label14);
+            this.groupBox3.Controls.Add(this.label15);
+            this.groupBox3.Controls.Add(this.label13);
+            this.groupBox3.Controls.Add(this.label12);
+            this.groupBox3.Controls.Add(this.label11);
+            this.groupBox3.Controls.Add(this.label10);
+            this.groupBox3.Controls.Add(this.numFillTransparency);
+            this.groupBox3.Controls.Add(this.label9);
+            this.groupBox3.Dock = System.Windows.Forms.DockStyle.Top;
+            this.groupBox3.Location = new System.Drawing.Point(0, 388);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(269, 162);
+            this.groupBox3.TabIndex = 2;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Style Ramp";
+            // 
+            // btnToBorderColor
+            // 
+            this.btnToBorderColor.Location = new System.Drawing.Point(222, 123);
+            this.btnToBorderColor.Name = "btnToBorderColor";
+            this.btnToBorderColor.Size = new System.Drawing.Size(29, 23);
+            this.btnToBorderColor.TabIndex = 13;
+            this.btnToBorderColor.Text = "...";
+            this.btnToBorderColor.UseVisualStyleBackColor = true;
+            this.btnToBorderColor.Click += new System.EventHandler(this.btnToBorderColor_Click);
+            // 
+            // pnlToBorderColor
+            // 
+            this.pnlToBorderColor.BackColor = System.Drawing.Color.Black;
+            this.pnlToBorderColor.Location = new System.Drawing.Point(178, 123);
+            this.pnlToBorderColor.Name = "pnlToBorderColor";
+            this.pnlToBorderColor.Size = new System.Drawing.Size(38, 23);
+            this.pnlToBorderColor.TabIndex = 12;
+            // 
+            // btnFromBorderColor
+            // 
+            this.btnFromBorderColor.Location = new System.Drawing.Point(110, 123);
+            this.btnFromBorderColor.Name = "btnFromBorderColor";
+            this.btnFromBorderColor.Size = new System.Drawing.Size(29, 23);
+            this.btnFromBorderColor.TabIndex = 11;
+            this.btnFromBorderColor.Text = "...";
+            this.btnFromBorderColor.UseVisualStyleBackColor = true;
+            this.btnFromBorderColor.Click += new System.EventHandler(this.btnFromBorderColor_Click);
+            // 
+            // btnToFillColor
+            // 
+            this.btnToFillColor.Location = new System.Drawing.Point(222, 71);
+            this.btnToFillColor.Name = "btnToFillColor";
+            this.btnToFillColor.Size = new System.Drawing.Size(29, 23);
+            this.btnToFillColor.TabIndex = 11;
+            this.btnToFillColor.Text = "...";
+            this.btnToFillColor.UseVisualStyleBackColor = true;
+            this.btnToFillColor.Click += new System.EventHandler(this.btnToFillColor_Click);
+            // 
+            // pnlFromBorderColor
+            // 
+            this.pnlFromBorderColor.BackColor = System.Drawing.Color.Black;
+            this.pnlFromBorderColor.Location = new System.Drawing.Point(66, 123);
+            this.pnlFromBorderColor.Name = "pnlFromBorderColor";
+            this.pnlFromBorderColor.Size = new System.Drawing.Size(38, 23);
+            this.pnlFromBorderColor.TabIndex = 10;
+            // 
+            // btnFromFillColor
+            // 
+            this.btnFromFillColor.Location = new System.Drawing.Point(110, 71);
+            this.btnFromFillColor.Name = "btnFromFillColor";
+            this.btnFromFillColor.Size = new System.Drawing.Size(29, 23);
+            this.btnFromFillColor.TabIndex = 9;
+            this.btnFromFillColor.Text = "...";
+            this.btnFromFillColor.UseVisualStyleBackColor = true;
+            this.btnFromFillColor.Click += new System.EventHandler(this.btnFromFillColor_Click);
+            // 
+            // pnlToFillColor
+            // 
+            this.pnlToFillColor.BackColor = System.Drawing.Color.Blue;
+            this.pnlToFillColor.Location = new System.Drawing.Point(178, 71);
+            this.pnlToFillColor.Name = "pnlToFillColor";
+            this.pnlToFillColor.Size = new System.Drawing.Size(38, 23);
+            this.pnlToFillColor.TabIndex = 10;
+            // 
+            // pnlFromFillColor
+            // 
+            this.pnlFromFillColor.BackColor = System.Drawing.Color.Red;
+            this.pnlFromFillColor.Location = new System.Drawing.Point(66, 71);
+            this.pnlFromFillColor.Name = "pnlFromFillColor";
+            this.pnlFromFillColor.Size = new System.Drawing.Size(38, 23);
+            this.pnlFromFillColor.TabIndex = 8;
+            // 
+            // label14
+            // 
+            this.label14.AutoSize = true;
+            this.label14.Location = new System.Drawing.Point(152, 128);
+            this.label14.Name = "label14";
+            this.label14.Size = new System.Drawing.Size(20, 13);
+            this.label14.TabIndex = 7;
+            this.label14.Text = "To";
+            // 
+            // label15
+            // 
+            this.label15.AutoSize = true;
+            this.label15.Location = new System.Drawing.Point(30, 128);
+            this.label15.Name = "label15";
+            this.label15.Size = new System.Drawing.Size(30, 13);
+            this.label15.TabIndex = 6;
+            this.label15.Text = "From";
+            // 
+            // label13
+            // 
+            this.label13.AutoSize = true;
+            this.label13.Location = new System.Drawing.Point(152, 76);
+            this.label13.Name = "label13";
+            this.label13.Size = new System.Drawing.Size(20, 13);
+            this.label13.TabIndex = 5;
+            this.label13.Text = "To";
+            // 
+            // label12
+            // 
+            this.label12.AutoSize = true;
+            this.label12.Location = new System.Drawing.Point(30, 76);
+            this.label12.Name = "label12";
+            this.label12.Size = new System.Drawing.Size(30, 13);
+            this.label12.TabIndex = 4;
+            this.label12.Text = "From";
+            // 
+            // label11
+            // 
+            this.label11.AutoSize = true;
+            this.label11.Location = new System.Drawing.Point(12, 107);
+            this.label11.Name = "label11";
+            this.label11.Size = new System.Drawing.Size(65, 13);
+            this.label11.TabIndex = 3;
+            this.label11.Text = "Border Color";
+            // 
+            // label10
+            // 
+            this.label10.AutoSize = true;
+            this.label10.Location = new System.Drawing.Point(12, 52);
+            this.label10.Name = "label10";
+            this.label10.Size = new System.Drawing.Size(46, 13);
+            this.label10.TabIndex = 2;
+            this.label10.Text = "Fill Color";
+            // 
+            // numFillTransparency
+            // 
+            this.numFillTransparency.Location = new System.Drawing.Point(123, 25);
+            this.numFillTransparency.Name = "numFillTransparency";
+            this.numFillTransparency.Size = new System.Drawing.Size(65, 20);
+            this.numFillTransparency.TabIndex = 1;
+            // 
+            // label9
+            // 
+            this.label9.AutoSize = true;
+            this.label9.Location = new System.Drawing.Point(12, 27);
+            this.label9.Name = "label9";
+            this.label9.Size = new System.Drawing.Size(104, 13);
+            this.label9.TabIndex = 0;
+            this.label9.Text = "Fill Transparency (%)";
+            // 
+            // btnApply
+            // 
+            this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnApply.Location = new System.Drawing.Point(177, 556);
+            this.btnApply.Name = "btnApply";
+            this.btnApply.Size = new System.Drawing.Size(75, 23);
+            this.btnApply.TabIndex = 3;
+            this.btnApply.Text = "Apply";
+            this.btnApply.UseVisualStyleBackColor = true;
+            this.btnApply.Click += new System.EventHandler(this.btnApply_Click);
+            // 
+            // MgThemeControlImpl
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.Controls.Add(this.btnApply);
+            this.Controls.Add(this.groupBox3);
+            this.Controls.Add(this.groupBox2);
+            this.Controls.Add(this.groupBox1);
+            this.Name = "MgThemeControlImpl";
+            this.Size = new System.Drawing.Size(269, 593);
+            this.groupBox1.ResumeLayout(false);
+            this.groupBox1.PerformLayout();
+            this.groupBox2.ResumeLayout(false);
+            this.groupBox2.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.numRules)).EndInit();
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.numFillTransparency)).EndInit();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.GroupBox groupBox1;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.ComboBox cmbLayer;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.TextBox txtThemeName;
+        private System.Windows.Forms.GroupBox groupBox2;
+        private System.Windows.Forms.ComboBox cmbScaleRange;
+        private System.Windows.Forms.Label label8;
+        private System.Windows.Forms.TextBox txtMax;
+        private System.Windows.Forms.TextBox txtMin;
+        private System.Windows.Forms.ComboBox cmbDistribution;
+        private System.Windows.Forms.ComboBox cmbProperty;
+        private System.Windows.Forms.Label label7;
+        private System.Windows.Forms.Label label6;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.Label label3;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.Button btnToBorderColor;
+        private System.Windows.Forms.Panel pnlToBorderColor;
+        private System.Windows.Forms.Button btnFromBorderColor;
+        private System.Windows.Forms.Button btnToFillColor;
+        private System.Windows.Forms.Panel pnlFromBorderColor;
+        private System.Windows.Forms.Button btnFromFillColor;
+        private System.Windows.Forms.Panel pnlToFillColor;
+        private System.Windows.Forms.Panel pnlFromFillColor;
+        private System.Windows.Forms.Label label14;
+        private System.Windows.Forms.Label label15;
+        private System.Windows.Forms.Label label13;
+        private System.Windows.Forms.Label label12;
+        private System.Windows.Forms.Label label11;
+        private System.Windows.Forms.Label label10;
+        private System.Windows.Forms.NumericUpDown numFillTransparency;
+        private System.Windows.Forms.Label label9;
+        private System.Windows.Forms.Button btnApply;
+        private System.Windows.Forms.NumericUpDown numRules;
+        private System.Windows.Forms.ColorDialog colorDialog;
+    }
+}

Added: branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.cs	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,509 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Text;
+using System.Windows.Forms;
+using System.Xml;
+using System.Globalization;
+
+namespace OSGeo.MapGuide.Viewer
+{
+    public partial class MgThemeControlImpl : MgControlImpl
+    {
+        private IMapViewer _viewer;
+        private BindingList<MgDataPropertyDefinition> _properties;
+        private BindingList<MgLayerBase> _layers;
+        private MgResourceService _resSvc;
+        private string _sessionId;
+
+        private Dictionary<string, string> _distros;
+
+        public MgThemeControlImpl(IMapViewer viewer)
+        {
+            InitializeComponent();
+            this.Title = Properties.Resources.TitleTheme;
+            this.Disposed += new EventHandler(OnDisposed);
+            _viewer = viewer;
+            _properties = new BindingList<MgDataPropertyDefinition>();
+            _layers = new BindingList<MgLayerBase>();
+
+            numRules.Minimum = Int32.MinValue;
+            numRules.Maximum = Int32.MaxValue;
+
+            _distros = new Dictionary<string,string>() 
+            {
+                { THEME_INDIVIDUAL, "Individual" },
+                { THEME_EQUAL, "Equal" },
+                { THEME_STDDEV, "Standard Deviation" },
+                { THEME_QUANT, "Quantile" },
+                { THEME_JENK, "Jenks (Natural Breaks)"}
+            };
+
+            cmbLayer.DataSource = _layers;
+            cmbProperty.DataSource = _properties;
+            cmbDistribution.DataSource = GetDistroValues(THEME_INDIVIDUAL, THEME_EQUAL, THEME_STDDEV, THEME_QUANT, THEME_JENK);
+
+            var map = viewer.GetMap();
+            var layers = map.GetLayers();
+            for (var i = 0; i < layers.GetCount(); i++)
+            {
+                _layers.Add(layers.GetItem(i));
+            }
+            cmbLayer.SelectedIndex = 0;
+            cmbLayer_SelectedIndexChanged(this, EventArgs.Empty);
+            cmbDistribution.SelectedIndex = 0;
+            _sessionId = Guid.NewGuid().ToString();
+        }
+
+        private KeyValuePair<string, string>[] GetDistroValues(params string[] distroKeys)
+        {
+            var values = new List<KeyValuePair<string, string>>();
+            foreach (var key in distroKeys)
+            {
+                if (_distros.ContainsKey(key))
+                    values.Add(new KeyValuePair<string, string>(key, _distros[key]));
+            }
+            return values.ToArray();
+        }
+
+        void OnDisposed(object sender, EventArgs e)
+        {
+            _properties.Clear();
+            _layers.Clear();
+            if (_resSvc != null)
+            {
+                _resSvc.Dispose();
+                _resSvc = null;
+            }
+        }
+
+        private void cmbLayer_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            var layer = cmbLayer.SelectedItem as MgLayerBase;
+            if (layer != null)
+            {
+                var cls = layer.GetClassDefinition();
+                var clsProps = cls.GetProperties();
+                _properties.Clear();
+                for (var i = 0; i < clsProps.GetCount(); i++)
+                {
+                    var prop = clsProps.GetItem(i);
+                    if (prop.GetPropertyType() == MgFeaturePropertyType.DataProperty)
+                    {
+                        _properties.Add((MgDataPropertyDefinition)prop);
+                    }
+                }
+                cmbProperty.SelectedIndex = 0;
+                cmbProperty_SelectedIndexChanged(this, EventArgs.Empty);
+                cmbScaleRange.DataSource = GetScaleRanges(layer);
+            }
+        }
+
+        private string[] GetScaleRanges(MgLayerBase layer)
+        {
+            if (_resSvc == null)
+            {
+                var provider = _viewer.GetProvider();
+                _resSvc = (MgResourceService)provider.CreateService(MgServiceType.ResourceService);
+            }
+
+            MgResourceIdentifier layerDefResId = layer.GetLayerDefinition();
+            MgByteReader byteReader = _resSvc.GetResourceContent(layerDefResId);
+
+            XmlDocument doc = new XmlDocument();
+            doc.LoadXml(byteReader.ToString());
+            XmlNodeList nodeList = doc.GetElementsByTagName("VectorScaleRange");
+
+            var scaleRanges = new List<string>();
+            foreach (XmlElement node in nodeList)
+            {
+                String range = null;
+
+                XmlNodeList minNodeList = node.GetElementsByTagName("MinScale");
+                if (minNodeList.Count > 0)
+                {
+                    range = minNodeList.Item(0).FirstChild.Value;
+                }
+                else
+                {
+                    range = "0";
+                }
+
+                XmlNodeList maxNodeList = node.GetElementsByTagName("MaxScale");
+                if (maxNodeList.Count > 0)
+                {
+                    range = range + " - " + maxNodeList.Item(0).FirstChild.Value;
+                }
+                else
+                {
+                    range = range + " - Infinity";
+                }
+
+                scaleRanges.Add(range);
+            }
+            return scaleRanges.ToArray();
+        }
+
+        private int featureCount;
+        private int ruleCount = 8;
+
+        private void cmbDistribution_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            if (cmbDistribution.SelectedIndex == 0)
+            {
+                numRules.Enabled = false;
+                numRules.Value = featureCount;
+            }
+            else
+            {
+                numRules.Enabled = true;
+                numRules.Value = ruleCount;
+            }
+        }
+
+        private void cmbProperty_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            var layer = cmbLayer.SelectedItem as MgLayerBase;
+            var prop = cmbProperty.SelectedItem as MgDataPropertyDefinition;
+            if (layer != null && prop != null)
+            {
+                SetPropertyMinMaxCount(layer, prop);
+                cmbDistribution.DataSource = GetDistributionsForDataType(prop.DataType);
+            }
+        }
+
+        private void btnFromFillColor_Click(object sender, EventArgs e)
+        {
+            if (colorDialog.ShowDialog() == DialogResult.OK)
+            {
+                pnlFromFillColor.BackColor = colorDialog.Color;
+            }
+        }
+
+        private void btnToFillColor_Click(object sender, EventArgs e)
+        {
+            if (colorDialog.ShowDialog() == DialogResult.OK)
+            {
+                pnlToFillColor.BackColor = colorDialog.Color;
+            }
+        }
+
+        private void btnFromBorderColor_Click(object sender, EventArgs e)
+        {
+            if (colorDialog.ShowDialog() == DialogResult.OK)
+            {
+                pnlFromBorderColor.BackColor = colorDialog.Color;
+            }
+        }
+
+        private void btnToBorderColor_Click(object sender, EventArgs e)
+        {
+            if (colorDialog.ShowDialog() == DialogResult.OK)
+            {
+                pnlToBorderColor.BackColor = colorDialog.Color;
+            }
+        }
+
+        private void btnApply_Click(object sender, EventArgs e)
+        {
+            var tp = new ThemeParams() 
+            {
+                borderFrom = Util.ToHtmlColor(pnlFromBorderColor.BackColor),
+                borderTo = Util.ToHtmlColor(pnlToBorderColor.BackColor),
+                distro = cmbDistribution.SelectedValue.ToString(),
+                fillFrom = Util.ToHtmlColor(pnlFromFillColor.BackColor),
+                fillTo = Util.ToHtmlColor(pnlToFillColor.BackColor),
+                fillTrans = Convert.ToInt32(numFillTransparency.Value),
+                layer = (MgLayerBase)cmbLayer.SelectedItem,
+                maxValue = txtMax.Text,
+                minValue = txtMin.Text,
+                numRules = Convert.ToInt32(numRules.Value),
+                property = (MgDataPropertyDefinition)cmbProperty.SelectedItem,
+                scaleRangeIndex = cmbScaleRange.SelectedIndex,
+                themeName = txtThemeName.Text
+            };
+            string name = ApplyTheme(tp);
+            _viewer.RefreshMap();
+            MessageBox.Show("Theme layer (" + name + ") created");
+        }
+
+        private void SetPropertyMinMaxCount(MgLayerBase layer, MgDataPropertyDefinition prop)
+        {
+            var provider = _viewer.GetProvider();
+
+            var featureService = (MgFeatureService)provider.CreateService(MgServiceType.FeatureService);
+            MgResourceIdentifier resId = new MgResourceIdentifier(layer.GetFeatureSourceId());
+
+            String minValue = null;
+            String maxValue = null;
+            int count = 0;
+
+            MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
+            queryOptions.AddFeatureProperty(prop.Name);
+
+            MgFeatureReader featureReader = featureService.SelectFeatures(resId, layer.GetFeatureClassName(), queryOptions);
+            while (featureReader.ReadNext())
+            {
+                String value = Util.GetFeaturePropertyValue(featureReader, prop.Name);
+                int propertyType = featureReader.GetPropertyType(prop.Name);
+                if (count == 0)
+                {
+                    maxValue = value;
+                    minValue = value;
+                }
+                switch (propertyType)
+                {
+                    case MgPropertyType.String:
+                        if (value.Length > 0)
+                        {
+                            if (value.CompareTo(maxValue) > 0)
+                                maxValue = value;
+                            if (value.CompareTo(minValue) < 0)
+                                minValue = value;
+                        }
+                        break;
+                    case MgPropertyType.Byte:
+                    case MgPropertyType.Int16:
+                    case MgPropertyType.Int32:
+                    case MgPropertyType.Int64:
+                        if (value.Length > 0)
+                        {
+                            if (Int64.Parse(value) > Int64.Parse(maxValue))
+                                maxValue = value;
+                            if (Int64.Parse(value) < Int64.Parse(minValue))
+                                minValue = value;
+                        }
+                        break;
+                    case MgPropertyType.Single:
+                    case MgPropertyType.Double:
+                        if (value != null)
+                        {
+                            if (Double.Parse(value) > Double.Parse(maxValue))
+                                maxValue = value;
+                            if (Double.Parse(value) < Double.Parse(minValue))
+                                minValue = value;
+                        }
+                        count++;
+                        break;
+                    case MgPropertyType.Boolean:
+                    case MgPropertyType.DateTime:
+                    case MgPropertyType.Null:
+                    case MgPropertyType.Blob:
+                    case MgPropertyType.Clob:
+                    case MgPropertyType.Feature:
+                    case MgPropertyType.Geometry:
+                        break;
+                }
+                count++;
+            }
+            featureReader.Close();
+
+            txtMin.Text = minValue;
+            txtMax.Text = maxValue;
+            numRules.Value = featureCount = count;
+        }
+
+        const string THEME_INDIVIDUAL = "INDIV_DIST";
+        const string THEME_EQUAL = "EQUAL_DIST";
+        const string THEME_STDDEV = "STDEV_DIST";
+        const string THEME_QUANT = "QUANT_DIST";
+        const string THEME_JENK = "JENK_DIST";
+
+        class ThemeParams
+        {
+            public MgLayerBase layer;
+            public MgDataPropertyDefinition property;
+            public int scaleRangeIndex;
+            public int numRules;
+            public string distro;
+            public string fillFrom;
+            public string fillTo;
+            public string borderFrom;
+            public string borderTo;
+            public int fillTrans;
+            public string minValue;
+            public string maxValue;
+            public string themeName;
+            //public string layerName;
+        }
+
+        private string ApplyTheme(ThemeParams themeParams)
+        {
+            var provider = _viewer.GetProvider();
+            var map = _viewer.GetMap();
+            var layers = map.GetLayers();
+
+            MgResourceService resourceService = (MgResourceService)provider.CreateService(MgServiceType.ResourceService);
+            MgFeatureService featureService = (MgFeatureService)provider.CreateService(MgServiceType.FeatureService);
+
+            MgResourceIdentifier resId = new MgResourceIdentifier(themeParams.layer.GetFeatureSourceId());
+            MgResourceIdentifier layerDefResId = themeParams.layer.GetLayerDefinition();
+            MgByteReader byteReader = resourceService.GetResourceContent(layerDefResId);
+
+            // Load the Layer Definition and Navigate to the specified <VectorScaleRange>
+
+            XmlDocument doc = new XmlDocument();
+            String xmlLayerDef = byteReader.ToString();
+            doc.LoadXml(xmlLayerDef);
+            XmlNodeList nodeList = doc.GetElementsByTagName("VectorScaleRange");
+
+            XmlElement vectorScaleRangecElement = (XmlElement)nodeList.Item(themeParams.scaleRangeIndex);
+            XmlElement areaTypeStyle = (XmlElement)vectorScaleRangecElement.GetElementsByTagName("AreaTypeStyle").Item(0);
+
+            // Remove any existing <AreaRule> elements.
+
+            XmlNodeList areaRuleList = areaTypeStyle.GetElementsByTagName("AreaRule");
+            int count = areaRuleList.Count;
+            for (int i = 0; i < count; i++)
+            {
+                //The areaRuleList shrinks as we remove items, so always
+                //remove the first item (don't use the index i)
+                areaTypeStyle.RemoveChild(areaRuleList.Item(0));
+            }
+
+            // Now create the new <AreaRule> elements.
+
+            String areaRuleTemplate = Properties.Resources.AreaRuleTemplate;
+            MgFeatureAggregateOptions aggregateOptions = new MgFeatureAggregateOptions();
+
+            String value = null;
+            String filterText = null;
+            String areaRuleXML = null;
+            XmlDocument areaDoc = null;
+            XmlNode areaNode = null;
+            double portion = 0.0;
+            double increment = (themeParams.numRules > 1) ? 1.0 / (themeParams.numRules - 1) : 1.0;
+
+            if (THEME_INDIVIDUAL == themeParams.distro)
+            {
+                aggregateOptions.AddFeatureProperty(themeParams.property.Name);
+                aggregateOptions.SelectDistinct(true);
+
+                MgDataReader dataReader = featureService.SelectAggregate(resId, themeParams.layer.GetFeatureClassName(), aggregateOptions);
+                while (dataReader.ReadNext())
+                {
+                    value = Util.GetFeaturePropertyValue(dataReader, themeParams.property.Name);
+
+                    filterText = "&quot;" + themeParams.property.Name + "&quot; = ";
+                    if (themeParams.property.DataType == MgPropertyType.String)
+                        filterText = filterText + "'" + value + "'";
+                    else
+                        filterText = filterText + value;
+
+                    areaRuleXML = String.Format(areaRuleTemplate,
+                                                themeParams.property.Name + ":" + value,
+                                                filterText,
+                                                Util.InterpolateColor(portion, themeParams.fillFrom, themeParams.fillTo, themeParams.fillTrans),
+                                                Util.InterpolateColor(portion, themeParams.borderFrom, themeParams.borderTo, 0));
+                    areaDoc = new XmlDocument();
+                    areaDoc.LoadXml(areaRuleXML);
+                    areaNode = doc.ImportNode(areaDoc.DocumentElement, true);
+                    areaTypeStyle.AppendChild(areaNode);
+
+                    portion = portion + increment;
+                }
+                dataReader.Close();
+            }
+            else
+            {
+                var values = new List<string>();
+
+                var expr = themeParams.distro + "(\"" + themeParams.property.Name + "\"," + themeParams.numRules + "," + themeParams.minValue + "," + themeParams.maxValue + ")";
+                aggregateOptions.AddComputedProperty("THEME_VALUE", expr);
+                MgDataReader dataReader = featureService.SelectAggregate(resId, themeParams.layer.GetFeatureClassName(), aggregateOptions);
+                while (dataReader.ReadNext())
+                {
+                    value = Util.GetFeaturePropertyValue(dataReader, "THEME_VALUE");
+                    values.Add(value);
+                }
+                dataReader.Close();
+
+                for (int i = 0; i < values.Count - 1; i++)
+                {
+                    filterText = "&quot;" + themeParams.property.Name + "&quot; &gt;= " + values[i] + " AND &quot;" + themeParams.property.Name;
+                    if (i == values.Count - 1)
+                        filterText = filterText + "&quot; &lt;= " + values[i + 1];
+                    else
+                        filterText = filterText + "&quot; &lt; " + values[i + 1];
+
+                    areaRuleXML = String.Format(areaRuleTemplate,
+                                                themeParams.property.Name + ":" + values[i] + " - " + values[i + 1],
+                                                filterText,
+                                                Util.InterpolateColor(portion, themeParams.fillFrom, themeParams.fillTo, themeParams.fillTrans),
+                                                Util.InterpolateColor(portion, themeParams.borderFrom, themeParams.borderTo, 0));
+
+                    areaDoc = new XmlDocument();
+                    areaDoc.LoadXml(areaRuleXML);
+                    areaNode = doc.ImportNode(areaDoc.DocumentElement, true);
+                    areaTypeStyle.AppendChild(areaNode);
+
+                    portion = portion + increment;
+                }
+            }
+
+            // Now save our new layer definition to the session and add it to the map.
+
+            String xmlString = doc.DocumentElement.OuterXml;
+            String uniqueName = Util.MakeUniqueLayerName(map, themeParams.layer.Name, themeParams.themeName);
+            String legendLabel = themeParams.layer.GetLegendLabel();
+            if (!string.IsNullOrEmpty(themeParams.themeName))
+                legendLabel = legendLabel + " (" + themeParams.themeName + ")";
+
+            MgResourceIdentifier layerResId = new MgResourceIdentifier("Session:" + _sessionId + "//" + uniqueName + ".LayerDefinition");
+            resourceService.SetResource(layerResId, new MgByteReader(xmlString, "text/xml"), null);
+
+            var newLayer = provider.CreateLayer(layerResId);
+            newLayer.SetName(uniqueName);
+            newLayer.SetLegendLabel(legendLabel);
+            newLayer.SetDisplayInLegend(themeParams.layer.GetDisplayInLegend());
+            newLayer.SetVisible(true);
+            newLayer.SetSelectable(themeParams.layer.GetSelectable());
+
+            layers.Insert(layers.IndexOf(themeParams.layer), newLayer);
+
+            //map.Save(resourceService);
+
+            return uniqueName;
+        }
+
+        private KeyValuePair<string, string>[] GetDistributionsForDataType(int type)
+        {
+            var distroTypes = new List<string>();
+
+            switch (type)
+            {
+                case MgPropertyType.String:
+                    distroTypes.Add(THEME_INDIVIDUAL);
+                    break;
+                case MgPropertyType.Byte:
+                case MgPropertyType.Int16:
+                case MgPropertyType.Int32:
+                case MgPropertyType.Int64:
+                    distroTypes.Add(THEME_INDIVIDUAL);
+                    distroTypes.Add(THEME_EQUAL);
+                    distroTypes.Add(THEME_STDDEV);
+                    distroTypes.Add(THEME_QUANT);
+                    distroTypes.Add(THEME_JENK);
+                    break;
+                case MgPropertyType.Single:
+                case MgPropertyType.Double:
+                    distroTypes.Add(THEME_EQUAL);
+                    distroTypes.Add(THEME_STDDEV);
+                    distroTypes.Add(THEME_QUANT);
+                    distroTypes.Add(THEME_JENK);
+                    break;
+                case MgPropertyType.Boolean:
+                case MgPropertyType.DateTime:
+                case MgPropertyType.Blob:
+                case MgPropertyType.Clob:
+                case MgPropertyType.Feature:
+                case MgPropertyType.Geometry:
+                case MgPropertyType.Null:
+                    break;
+            }
+            return GetDistroValues(distroTypes.ToArray());
+        }
+    }
+}

Added: branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.resx
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.resx	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MapViewer/MgThemeControlImpl.resx	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <metadata name="colorDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 17</value>
+  </metadata>
+</root>
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.Designer.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.Designer.cs	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.Designer.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -89,6 +89,32 @@
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to &lt;AreaRule&gt;
+        /// &lt;LegendLabel&gt;{0}&lt;/LegendLabel&gt;
+        /// &lt;Filter&gt;{1}&lt;/Filter&gt;
+        /// &lt;AreaSymbolization2D&gt;
+        ///  &lt;Fill&gt;
+        ///   &lt;FillPattern&gt;Solid&lt;/FillPattern&gt;
+        ///   &lt;ForegroundColor&gt;{2}&lt;/ForegroundColor&gt;
+        ///   &lt;BackgroundColor&gt;FF000000&lt;/BackgroundColor&gt;
+        ///  &lt;/Fill&gt;
+        ///  &lt;Stroke&gt;
+        ///   &lt;LineStyle&gt;Solid&lt;/LineStyle&gt;
+        ///   &lt;Thickness&gt;0&lt;/Thickness&gt;
+        ///   &lt;Color&gt;{3}&lt;/Color&gt;
+        ///   &lt;Unit&gt;Inches&lt;/Unit&gt;
+        ///  &lt;/Stroke&gt;
+        /// &lt;/AreaSymbolization2D&gt;
+        ///&lt;/AreaRule&gt;
+        ///.
+        /// </summary>
+        internal static string AreaRuleTemplate {
+            get {
+                return ResourceManager.GetString("AreaRuleTemplate", resourceCulture);
+            }
+        }
+        
         internal static System.Drawing.Bitmap buffer {
             get {
                 object obj = ResourceManager.GetObject("buffer", resourceCulture);
@@ -758,6 +784,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Theme.
+        /// </summary>
+        internal static string TitleTheme {
+            get {
+                return ResourceManager.GetString("TitleTheme", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Viewer Options.
         /// </summary>
         internal static string TitleViewerOptions {

Modified: branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.resx
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.resx	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MapViewer/Properties/Resources.resx	2012-05-13 02:45:17 UTC (rev 6644)
@@ -427,4 +427,10 @@
   <data name="TextScale" xml:space="preserve">
     <value>Scale</value>
   </data>
+  <data name="TitleTheme" xml:space="preserve">
+    <value>Theme</value>
+  </data>
+  <data name="AreaRuleTemplate" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\AreaRuleTemplate.txt;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
 </root>
\ No newline at end of file

Added: branches/2.4/MgDev/Desktop/MapViewer/Resources/AreaRuleTemplate.txt
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/Resources/AreaRuleTemplate.txt	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MapViewer/Resources/AreaRuleTemplate.txt	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,17 @@
+<AreaRule>
+ <LegendLabel>{0}</LegendLabel>
+ <Filter>{1}</Filter>
+ <AreaSymbolization2D>
+  <Fill>
+   <FillPattern>Solid</FillPattern>
+   <ForegroundColor>{2}</ForegroundColor>
+   <BackgroundColor>FF000000</BackgroundColor>
+  </Fill>
+  <Stroke>
+   <LineStyle>Solid</LineStyle>
+   <Thickness>0</Thickness>
+   <Color>{3}</Color>
+   <Unit>Inches</Unit>
+  </Stroke>
+ </AreaSymbolization2D>
+</AreaRule>

Added: branches/2.4/MgDev/Desktop/MapViewer/Util.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewer/Util.cs	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MapViewer/Util.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Globalization;
+using System.Drawing;
+
+namespace OSGeo.MapGuide.Viewer
+{
+    internal static class Util
+    {
+        public static string ToHtmlColor(Color color)
+        {
+            return String.Format("{0:X2}{1:X2}{2:X2}", color.R, color.G, color.B);
+        }
+
+        public static MgLayerBase FindLayer(MgLayerCollection layers, String layerName)
+        {
+            MgLayerBase layer = null;
+            int i = 0;
+            for (i = 0; i < layers.GetCount(); i++)
+            {
+                MgLayerBase layer1 = layers.GetItem(i);
+
+                if (layer1.GetName() == layerName)
+                {
+                    layer = layer1;
+                    break;
+                }
+            }
+            return layer;
+        }
+
+        public static string GetMapSrs(MgMapBase map)
+        {
+            try
+            {
+                String srs = map.GetMapSRS();
+                if (srs != "")
+                    return srs;
+            }
+            catch (MgException e)
+            {
+            }
+
+            //No SRS, set to ArbitrayXY meters
+            //
+            return "LOCALCS[\"Non-Earth (Meter)\",LOCAL_DATUM[\"Local Datum\",0],UNIT[\"Meter\", 1],AXIS[\"X\",EAST],AXIS[\"Y\",NORTH]]";
+        }
+
+        public static void ClearDataSource(MgFeatureService featSvc, MgResourceIdentifier fsId, String featureName)
+        {
+            MgDeleteFeatures deleteCmd = new MgDeleteFeatures(featureName, "ID >= 0");
+            MgFeatureCommandCollection commands = new MgFeatureCommandCollection();
+            commands.Add(deleteCmd);
+            featSvc.UpdateFeatures(fsId, commands, false);
+        }
+
+        public static void ReleaseReader(MgPropertyCollection res, MgFeatureCommandCollection commands)
+        {
+            if (res == null)
+                return;
+
+            for (int i = 0; i < res.GetCount(); i++)
+            {
+                MgFeatureCommand cmd = commands.GetItem(i);
+                if (cmd is MgInsertFeatures)
+                {
+                    MgFeatureProperty resProp = res.GetItem(i) as MgFeatureProperty;
+                    if (resProp != null)
+                    {
+                        MgFeatureReader reader = resProp.GetValue() as MgFeatureReader;
+                        if (reader == null)
+                            return;
+                        reader.Close();
+                    }
+                }
+            }
+        }
+
+        public static void AddFeatureToCollection(MgBatchPropertyCollection propCollection, MgAgfReaderWriter agfRW, int featureId, MgGeometry featureGeom)
+        {
+            MgPropertyCollection bufferProps = new MgPropertyCollection();
+            MgInt32Property idProp = new MgInt32Property("ID", featureId);
+            bufferProps.Add(idProp);
+            MgByteReader geomReader = agfRW.Write(featureGeom);
+            MgGeometryProperty geomProp = new MgGeometryProperty("GEOM", geomReader);
+            bufferProps.Add(geomProp);
+            propCollection.Add(bufferProps);
+        }
+
+        public static String GetFeaturePropertyValue(MgReader featureReader, String propName)
+        {
+            String value = "";
+            int propertyType = featureReader.GetPropertyType(propName);
+            switch (propertyType)
+            {
+                case MgPropertyType.Boolean:
+                    value = featureReader.GetBoolean(propName).ToString();
+                    break;
+                case MgPropertyType.Byte:
+                    value = featureReader.GetByte(propName).ToString();
+                    break;
+                case MgPropertyType.Single:
+                    value = featureReader.GetSingle(propName).ToString();
+                    break;
+                case MgPropertyType.Double:
+                    value = featureReader.GetDouble(propName).ToString();
+                    break;
+                case MgPropertyType.Int16:
+                    value = featureReader.GetInt16(propName).ToString();
+                    break;
+                case MgPropertyType.Int32:
+                    value = featureReader.GetInt32(propName).ToString();
+                    break;
+                case MgPropertyType.Int64:
+                    value = featureReader.GetInt64(propName).ToString();
+                    break;
+                case MgPropertyType.String:
+                    value = featureReader.GetString(propName);
+                    break;
+                case MgPropertyType.DateTime:
+                case MgPropertyType.Null:
+                case MgPropertyType.Blob:
+                case MgPropertyType.Clob:
+                case MgPropertyType.Feature:
+                case MgPropertyType.Geometry:
+                case MgPropertyType.Raster:
+                    value = "[unsupported data type]";
+                    break;
+            }
+            return value;
+        }
+
+        public static String MakeUniqueLayerName(MgMapBase map, String layerName, String themeName)
+        {
+            String desiredName = "_" + layerName + themeName;
+            String uniqueName = desiredName;
+            int index = 1;
+
+            var layers = map.GetLayers();
+            while (layers.Contains(uniqueName))
+            {
+                uniqueName = desiredName + index.ToString();
+                index++;
+            }
+            return uniqueName;
+        }
+
+        public static String InterpolateColor(double portion, String startColor, String endColor, int percentTransparent)
+        {
+            int alpha = (int)(255 * (100.0 - percentTransparent) / 100.0);
+            String result = "";
+            if (startColor.Equals(endColor))
+            {
+                result = String.Format("{0:X2}{1}", alpha, startColor);
+            }
+            else
+            {
+                int red = CalculateRGB(portion, startColor.Substring(0, 2), endColor.Substring(0, 2));
+                int green = CalculateRGB(portion, startColor.Substring(2, 2), endColor.Substring(2, 2));
+                int blue = CalculateRGB(portion, startColor.Substring(4, 2), endColor.Substring(4, 2));
+                result = String.Format("{0:X2}{1:X2}{2:X2}{3:X2}", alpha, red, green, blue);
+            }
+            return result;
+        }
+
+        public static int CalculateRGB(double portion, String startRGB, String endRGB)
+        {
+            double result = Int32.Parse(startRGB, NumberStyles.HexNumber) + portion * (Int32.Parse(endRGB, NumberStyles.HexNumber) - Int32.Parse(startRGB, NumberStyles.HexNumber));
+            return (int)result;
+        }
+    }
+}

Modified: branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.Designer.cs
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.Designer.cs	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.Designer.cs	2012-05-13 02:45:17 UTC (rev 6644)
@@ -89,6 +89,7 @@
             this.toolStripButton13 = new System.Windows.Forms.ToolStripButton();
             this.toolStripMenuItem8 = new System.Windows.Forms.ToolStripMenuItem();
             this.toolStripMenuItem25 = new System.Windows.Forms.ToolStripMenuItem();
+            this.toolStripMenuItem26 = new System.Windows.Forms.ToolStripMenuItem();
             this.taskPane = new OSGeo.MapGuide.Viewer.MgTaskPane();
             this.toolStripMenuItem5 = new System.Windows.Forms.ToolStripMenuItem();
             this.toolStripMenuItem6 = new System.Windows.Forms.ToolStripMenuItem();
@@ -131,10 +132,13 @@
             this.mgZoomToSelectionComponent1 = new OSGeo.MapGuide.Viewer.MgZoomToSelectionComponent();
             this.mgMenuItemComponentInvoker1 = new OSGeo.MapGuide.Viewer.MgMenuItemComponentInvoker();
             this.loadCompactViewerComponent = new OSGeo.MapGuide.Viewer.MgGenericInvokeComponent();
+            this.profileComponent = new OSGeo.MapGuide.Viewer.MgGenericInvokeComponent();
             this.mgToolButtonComponentInvoker1 = new OSGeo.MapGuide.Viewer.MgToolButtonComponentInvoker();
             this.mgLayerSelectionHandler1 = new OSGeo.MapGuide.Viewer.MgLayerSelectionHandler();
-            this.profileComponent = new OSGeo.MapGuide.Viewer.MgGenericInvokeComponent();
-            this.toolStripMenuItem26 = new System.Windows.Forms.ToolStripMenuItem();
+            this.mgThemeComponent1 = new OSGeo.MapGuide.Viewer.MgThemeComponent();
+            this.toolStripMenuItem27 = new System.Windows.Forms.ToolStripMenuItem();
+            this.toolStripMenuItem28 = new System.Windows.Forms.ToolStripMenuItem();
+            this.toolStripMenuItem29 = new System.Windows.Forms.ToolStripMenuItem();
             this.appMenu.SuspendLayout();
             this.appContextMenu.SuspendLayout();
             this.appContainer.Panel1.SuspendLayout();
@@ -161,6 +165,7 @@
             ((System.ComponentModel.ISupportInitialize)(this.mgMeasureComponent1)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.mgQueryComponent1)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.mgViewerOptionsComponent1)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.mgThemeComponent1)).BeginInit();
             this.SuspendLayout();
             // 
             // appMenu
@@ -188,6 +193,7 @@
             this.toolStripMenuItem2,
             this.toolStripMenuItem3,
             this.toolStripMenuItem4,
+            this.toolStripMenuItem28,
             this.toolStripSeparator9,
             this.toolStripMenuItem12});
             this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
@@ -425,7 +431,8 @@
             this.toolStripDropDownButton1.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.toolStripMenuItem9,
             this.toolStripMenuItem10,
-            this.toolStripMenuItem11});
+            this.toolStripMenuItem11,
+            this.toolStripMenuItem27});
             this.toolStripDropDownButton1.Image = global::MapViewerTest.Properties.Resources.icon_tasks;
             this.toolStripDropDownButton1.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.toolStripDropDownButton1.Name = "toolStripDropDownButton1";
@@ -489,7 +496,8 @@
             this.taskMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.toolStripMenuItem5,
             this.toolStripMenuItem6,
-            this.toolStripMenuItem7});
+            this.toolStripMenuItem7,
+            this.toolStripMenuItem29});
             this.taskMenu.Image = global::MapViewerTest.Properties.Resources.icon_tasks;
             this.taskMenu.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.taskMenu.Name = "taskMenu";
@@ -722,7 +730,7 @@
             this.toolStripMenuItem9.Enabled = false;
             this.toolStripMenuItem9.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem9.Image")));
             this.toolStripMenuItem9.Name = "toolStripMenuItem9";
-            this.toolStripMenuItem9.Size = new System.Drawing.Size(119, 22);
+            this.toolStripMenuItem9.Size = new System.Drawing.Size(152, 22);
             this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem9, this.mgBufferComponent1);
             this.toolStripMenuItem9.Text = "Buffer";
             // 
@@ -731,7 +739,7 @@
             this.toolStripMenuItem10.Enabled = false;
             this.toolStripMenuItem10.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem10.Image")));
             this.toolStripMenuItem10.Name = "toolStripMenuItem10";
-            this.toolStripMenuItem10.Size = new System.Drawing.Size(119, 22);
+            this.toolStripMenuItem10.Size = new System.Drawing.Size(152, 22);
             this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem10, this.mgMeasureComponent1);
             this.toolStripMenuItem10.Text = "Measure";
             // 
@@ -740,7 +748,7 @@
             this.toolStripMenuItem11.Enabled = false;
             this.toolStripMenuItem11.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem11.Image")));
             this.toolStripMenuItem11.Name = "toolStripMenuItem11";
-            this.toolStripMenuItem11.Size = new System.Drawing.Size(119, 22);
+            this.toolStripMenuItem11.Size = new System.Drawing.Size(152, 22);
             this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem11, this.mgQueryComponent1);
             this.toolStripMenuItem11.Text = "Query";
             // 
@@ -775,6 +783,16 @@
             this.toolStripMenuItem25.Text = "Load Compact Viewer";
             this.toolStripMenuItem25.ToolTipText = "Load Compact Viewer";
             // 
+            // toolStripMenuItem26
+            // 
+            this.toolStripMenuItem26.Enabled = false;
+            this.toolStripMenuItem26.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem26.Image")));
+            this.toolStripMenuItem26.Name = "toolStripMenuItem26";
+            this.toolStripMenuItem26.Size = new System.Drawing.Size(190, 22);
+            this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem26, this.profileComponent);
+            this.toolStripMenuItem26.Text = "Profile";
+            this.toolStripMenuItem26.ToolTipText = "Profile this Map";
+            // 
             // taskPane
             // 
             this.taskPane.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -788,7 +806,7 @@
             this.toolStripMenuItem5.Enabled = false;
             this.toolStripMenuItem5.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem5.Image")));
             this.toolStripMenuItem5.Name = "toolStripMenuItem5";
-            this.toolStripMenuItem5.Size = new System.Drawing.Size(119, 22);
+            this.toolStripMenuItem5.Size = new System.Drawing.Size(152, 22);
             this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem5, this.mgBufferComponent1);
             this.toolStripMenuItem5.Text = "Buffer";
             // 
@@ -797,7 +815,7 @@
             this.toolStripMenuItem6.Enabled = false;
             this.toolStripMenuItem6.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem6.Image")));
             this.toolStripMenuItem6.Name = "toolStripMenuItem6";
-            this.toolStripMenuItem6.Size = new System.Drawing.Size(119, 22);
+            this.toolStripMenuItem6.Size = new System.Drawing.Size(152, 22);
             this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem6, this.mgMeasureComponent1);
             this.toolStripMenuItem6.Text = "Measure";
             // 
@@ -806,7 +824,7 @@
             this.toolStripMenuItem7.Enabled = false;
             this.toolStripMenuItem7.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem7.Image")));
             this.toolStripMenuItem7.Name = "toolStripMenuItem7";
-            this.toolStripMenuItem7.Size = new System.Drawing.Size(119, 22);
+            this.toolStripMenuItem7.Size = new System.Drawing.Size(152, 22);
             this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem7, this.mgQueryComponent1);
             this.toolStripMenuItem7.Text = "Query";
             // 
@@ -1131,13 +1149,6 @@
             this.loadCompactViewerComponent.Viewer = this.mapViewer;
             this.loadCompactViewerComponent.Invoked += new System.EventHandler(this.loadCompactViewerComponent_Invoked);
             // 
-            // mgLayerSelectionHandler1
-            // 
-            this.mgLayerSelectionHandler1.Layers = new string[] {
-        "Parcels"};
-            this.mgLayerSelectionHandler1.Viewer = this.mapViewer;
-            this.mgLayerSelectionHandler1.SelectionMade += new OSGeo.MapGuide.Viewer.MgLayerSelectionEventHandler(this.mgLayerSelectionHandler1_SelectionMade);
-            // 
             // profileComponent
             // 
             this.profileComponent.CanInvokeWithoutLoadedMap = false;
@@ -1147,16 +1158,52 @@
             this.profileComponent.Viewer = this.mapViewer;
             this.profileComponent.Invoked += new System.EventHandler(this.profileComponent_Invoked);
             // 
-            // toolStripMenuItem26
+            // mgLayerSelectionHandler1
             // 
-            this.toolStripMenuItem26.Enabled = false;
-            this.toolStripMenuItem26.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem26.Image")));
-            this.toolStripMenuItem26.Name = "toolStripMenuItem26";
-            this.toolStripMenuItem26.Size = new System.Drawing.Size(190, 22);
-            this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem26, this.profileComponent);
-            this.toolStripMenuItem26.Text = "Profile";
-            this.toolStripMenuItem26.ToolTipText = "Profile this Map";
+            this.mgLayerSelectionHandler1.Layers = new string[] {
+        "Parcels"};
+            this.mgLayerSelectionHandler1.Viewer = this.mapViewer;
+            this.mgLayerSelectionHandler1.SelectionMade += new OSGeo.MapGuide.Viewer.MgLayerSelectionEventHandler(this.mgLayerSelectionHandler1_SelectionMade);
             // 
+            // mgThemeComponent1
+            // 
+            this.mgThemeComponent1.Icon = ((System.Drawing.Image)(resources.GetObject("mgThemeComponent1.Icon")));
+            this.mgThemeComponent1.Label = "Theme";
+            this.mgThemeComponent1.Target = OSGeo.MapGuide.Viewer.MgViewerTarget.TaskPane;
+            this.mgThemeComponent1.TaskPane = this.taskPane;
+            this.mgThemeComponent1.ToolTipText = "Theme";
+            this.mgThemeComponent1.Viewer = this.mapViewer;
+            // 
+            // toolStripMenuItem27
+            // 
+            this.toolStripMenuItem27.Enabled = false;
+            this.toolStripMenuItem27.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem27.Image")));
+            this.toolStripMenuItem27.Name = "toolStripMenuItem27";
+            this.toolStripMenuItem27.Size = new System.Drawing.Size(152, 22);
+            this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem27, this.mgThemeComponent1);
+            this.toolStripMenuItem27.Text = "Theme";
+            this.toolStripMenuItem27.ToolTipText = "Theme";
+            // 
+            // toolStripMenuItem28
+            // 
+            this.toolStripMenuItem28.Enabled = false;
+            this.toolStripMenuItem28.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem28.Image")));
+            this.toolStripMenuItem28.Name = "toolStripMenuItem28";
+            this.toolStripMenuItem28.Size = new System.Drawing.Size(154, 22);
+            this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem28, this.mgThemeComponent1);
+            this.toolStripMenuItem28.Text = "Theme";
+            this.toolStripMenuItem28.ToolTipText = "Theme";
+            // 
+            // toolStripMenuItem29
+            // 
+            this.toolStripMenuItem29.Enabled = false;
+            this.toolStripMenuItem29.Image = ((System.Drawing.Image)(resources.GetObject("toolStripMenuItem29.Image")));
+            this.toolStripMenuItem29.Name = "toolStripMenuItem29";
+            this.toolStripMenuItem29.Size = new System.Drawing.Size(152, 22);
+            this.mgMenuItemComponentInvoker1.SetTargetComponent(this.toolStripMenuItem29, this.mgThemeComponent1);
+            this.toolStripMenuItem29.Text = "Theme";
+            this.toolStripMenuItem29.ToolTipText = "Theme";
+            // 
             // MgAppWindow
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -1201,6 +1248,7 @@
             ((System.ComponentModel.ISupportInitialize)(this.mgMeasureComponent1)).EndInit();
             ((System.ComponentModel.ISupportInitialize)(this.mgQueryComponent1)).EndInit();
             ((System.ComponentModel.ISupportInitialize)(this.mgViewerOptionsComponent1)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.mgThemeComponent1)).EndInit();
             this.ResumeLayout(false);
             this.PerformLayout();
 
@@ -1313,6 +1361,10 @@
         private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem25;
         private OSGeo.MapGuide.Viewer.MgGenericInvokeComponent profileComponent;
         private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem26;
+        private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem28;
+        private OSGeo.MapGuide.Viewer.MgThemeComponent mgThemeComponent1;
+        private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem27;
+        private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem29;
 
     }
 }
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.resx
===================================================================
--- branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.resx	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MapViewerTest/MgAppWindow.resx	2012-05-13 02:45:17 UTC (rev 6644)
@@ -120,13 +120,135 @@
   <metadata name="appMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="toolStripMenuItem2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
+        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
+        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
+        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
+        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
+        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
+        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
+</value>
+  </data>
+  <metadata name="mgMenuItemComponentInvoker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>802, 95</value>
+  </metadata>
+  <metadata name="mgBufferComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>446, 173</value>
+  </metadata>
+  <data name="mgBufferComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
+        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
+        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
+        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
+        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
+        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
+        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
+</value>
+  </data>
   <metadata name="appContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>338, 17</value>
   </metadata>
+  <data name="toolStripMenuItem3.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
+        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
+        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
+</value>
+  </data>
+  <metadata name="mgMeasureComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>17, 212</value>
+  </metadata>
+  <data name="mgMeasureComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
+        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
+        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem4.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
+        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
+        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
+        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
+        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
+        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
+        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
+        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
+        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
+        RK5CYII=
+</value>
+  </data>
+  <metadata name="mgQueryComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>840, 173</value>
+  </metadata>
+  <data name="mgQueryComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
+        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
+        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
+        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
+        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
+        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
+        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
+        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
+        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
+        RK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem28.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        R0lGODlhEAAQAIMAAAAAAP///6e6zXG39mCc0bzd+87trIC4QpfYTv/eStm9P//vqmdnZywsLP///wAA
+        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQBAAAOACwAAAAAEAAQAAAIeQAdCBxIsKADBggTIjQokIGBhxAb
+        MDxoAIFFBAckMnRoUaFCghwRMFhAsqTGhhVFLkjAMoGCkxQPHBjJ0qPCBjhpJmBQoKfPBgKCCtDJc4DR
+        AQRgjlSgoOjRpCBxNnBqFOpAoUMLHEUKE2QBAmDBdh3IQKrZiVixBgQAOw==
+</value>
+  </data>
+  <metadata name="mgThemeComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>508, 212</value>
+  </metadata>
+  <data name="mgThemeComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        R0lGODlhEAAQAIMAAAAAAP///6e6zXG39mCc0bzd+87trIC4QpfYTv/eStm9P//vqmdnZywsLP///wAA
+        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQBAAAOACwAAAAAEAAQAAAIeQAdCBxIsKADBggTIjQokIGBhxAb
+        MDxoAIFFBAckMnRoUaFCghwRMFhAsqTGhhVFLkjAMoGCkxQPHBjJ0qPCBjhpJmBQoKfPBgKCCtDJc4DR
+        AQRgjlSgoOjRpCBxNnBqFOpAoUMLHEUKE2QBAmDBdh3IQKrZiVixBgQAOw==
+</value>
+  </data>
+  <data name="toolStripMenuItem12.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC0SURBVDhPrZPLCsIwEEXzXeKyS/0bQUFxISiKK8EH/TXF
+        QtRiKBaLSqyrkQnkgovCkBg4zFyYOYRAlIo9raSTtpMuhcC7ihfPuQGD2Yak8K4TxOAEoQc3OGQnkrI/
+        avJAkOmcepMV4CwBAn0x1J+u6fmyrvrMfRM8A0F+LX5enrMECExRUggQ3MqKhvMt4CwBgnv1oNFiR3X9
+        cdVn7pvgGQj48cbLFHCWAIG1bwrhP4LY3/gFpD/IGPp59QYAAAAASUVORK5CYII=
+</value>
+  </data>
+  <metadata name="mgViewerOptionsComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>619, 173</value>
+  </metadata>
+  <data name="mgViewerOptionsComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC0SURBVDhPrZPLCsIwEEXzXeKyS/0bQUFxISiKK8EH/TXF
+        QtRiKBaLSqyrkQnkgovCkBg4zFyYOYRAlIo9raSTtpMuhcC7ihfPuQGD2Yak8K4TxOAEoQc3OGQnkrI/
+        avJAkOmcepMV4CwBAn0x1J+u6fmyrvrMfRM8A0F+LX5enrMECExRUggQ3MqKhvMt4CwBgnv1oNFiR3X9
+        cdVn7pvgGQj48cbLFHCWAIG1bwrhP4LY3/gFpD/IGPp59QYAAAAASUVORK5CYII=
+</value>
+  </data>
   <metadata name="appToolbar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>121, 17</value>
   </metadata>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   <data name="toolStripButton1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
@@ -444,6 +566,49 @@
         AABJRU5ErkJggg==
 </value>
   </data>
+  <data name="toolStripMenuItem9.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
+        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
+        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
+        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
+        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
+        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
+        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem10.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
+        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
+        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem11.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
+        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
+        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
+        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
+        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
+        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
+        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
+        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
+        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
+        RK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem27.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        R0lGODlhEAAQAIMAAAAAAP///6e6zXG39mCc0bzd+87trIC4QpfYTv/eStm9P//vqmdnZywsLP///wAA
+        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQBAAAOACwAAAAAEAAQAAAIeQAdCBxIsKADBggTIjQokIGBhxAb
+        MDxoAIFFBAckMnRoUaFCghwRMFhAsqTGhhVFLkjAMoGCkxQPHBjJ0qPCBjhpJmBQoKfPBgKCCtDJc4DR
+        AQRgjlSgoOjRpCBxNnBqFOpAoUMLHEUKE2QBAmDBdh3IQKrZiVixBgQAOw==
+</value>
+  </data>
   <data name="toolStripButton13.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
@@ -453,18 +618,55 @@
         cdVn7pvgGQj48cbLFHCWAIG1bwrhP4LY3/gFpD/IGPp59QYAAAAASUVORK5CYII=
 </value>
   </data>
-  <metadata name="mgViewerOptionsComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>619, 173</value>
+  <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>205, 212</value>
   </metadata>
-  <data name="mgViewerOptionsComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+  <data name="toolStripMenuItem5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC0SURBVDhPrZPLCsIwEEXzXeKyS/0bQUFxISiKK8EH/TXF
-        QtRiKBaLSqyrkQnkgovCkBg4zFyYOYRAlIo9raSTtpMuhcC7ihfPuQGD2Yak8K4TxOAEoQc3OGQnkrI/
-        avJAkOmcepMV4CwBAn0x1J+u6fmyrvrMfRM8A0F+LX5enrMECExRUggQ3MqKhvMt4CwBgnv1oNFiR3X9
-        cdVn7pvgGQj48cbLFHCWAIG1bwrhP4LY3/gFpD/IGPp59QYAAAAASUVORK5CYII=
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
+        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
+        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
+        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
+        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
+        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
+        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
 </value>
   </data>
+  <data name="toolStripMenuItem6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
+        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
+        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem7.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
+        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
+        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
+        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
+        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
+        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
+        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
+        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
+        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
+        RK5CYII=
+</value>
+  </data>
+  <data name="toolStripMenuItem29.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        R0lGODlhEAAQAIMAAAAAAP///6e6zXG39mCc0bzd+87trIC4QpfYTv/eStm9P//vqmdnZywsLP///wAA
+        ACH/C05FVFNDQVBFMi4wAwEBAAAh+QQBAAAOACwAAAAAEAAQAAAIeQAdCBxIsKADBggTIjQokIGBhxAb
+        MDxoAIFFBAckMnRoUaFCghwRMFhAsqTGhhVFLkjAMoGCkxQPHBjJ0qPCBjhpJmBQoKfPBgKCCtDJc4DR
+        AQRgjlSgoOjRpCBxNnBqFOpAoUMLHEUKE2QBAmDBdh3IQKrZiVixBgQAOw==
+</value>
+  </data>
+  <metadata name="statusBar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>237, 17</value>
+  </metadata>
   <data name="toolStripMenuItem8.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
@@ -479,9 +681,6 @@
         RU5ErkJggg==
 </value>
   </data>
-  <metadata name="mgMenuItemComponentInvoker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>802, 95</value>
-  </metadata>
   <metadata name="plotToDwfComponent.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>211, 56</value>
   </metadata>
@@ -502,7 +701,7 @@
   <data name="toolStripMenuItem25.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAACw8AAAsPAZL5A6UAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
+        YQUAAAAJcEhZcwAACw0AAAsNAe0HwCwAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
         CKmoIj42BLFjI5FGxI7/QCIsrLC20IU2Umm1PkZFW02FdjBpXvfM7fjKUIsn55w7c9/73nPvJQDEtLZ0
         LQrwTxateebkkgB29g7wZhhl4UV+FfinA3uB4+CZ6eI3vq5s64AF/qKswMnpOZhgSGDlXJfysgLhSBzh
         SKIE53HEr5LIZHPQX15hiAZb1m23EEtoiCZuBRo4v09ncZWJwbvRBGXAAVcnwd1HhjJHR+oKVbPIt2PU
@@ -519,7 +718,7 @@
   <data name="loadCompactViewerComponent.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAACw8AAAsPAZL5A6UAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
+        YQUAAAAJcEhZcwAACw0AAAsNAe0HwCwAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
         CKmoIj42BLFjI5FGxI7/QCIsrLC20IU2Umm1PkZFW02FdjBpXvfM7fjKUIsn55w7c9/73nPvJQDEtLZ0
         LQrwTxateebkkgB29g7wZhhl4UV+FfinA3uB4+CZ6eI3vq5s64AF/qKswMnpOZhgSGDlXJfysgLhSBzh
         SKIE53HEr5LIZHPQX15hiAZb1m23EEtoiCZuBRo4v09ncZWJwbvRBGXAAVcnwd1HhjJHR+oKVbPIt2PU
@@ -533,7 +732,7 @@
   <data name="toolStripMenuItem26.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAACxAAAAsQAa0jvXUAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
+        YQUAAAAJcEhZcwAACw4AAAsOAUC+4UEAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
         CKmoIj42BLFjI5FGxI7/QCIsrLC20IU2Umm1PkZFW02FdjBpXvfM7fjKUIsn55w7c9/73nPvJQDEtLZ0
         LQrwTxateebkkgB29g7wZhhl4UV+FfinA3uB4+CZ6eI3vq5s64AF/qKswMnpOZhgSGDlXJfysgLhSBzh
         SKIE53HEr5LIZHPQX15hiAZb1m23EEtoiCZuBRo4v09ncZWJwbvRBGXAAVcnwd1HhjJHR+oKVbPIt2PU
@@ -550,7 +749,7 @@
   <data name="profileComponent.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAACxAAAAsQAa0jvXUAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
+        YQUAAAAJcEhZcwAACw4AAAsOAUC+4UEAAAG4SURBVDhPjZNNLwNRFIbPohv/oVhVk8kkNl0RQiQkWEkk
         CKmoIj42BLFjI5FGxI7/QCIsrLC20IU2Umm1PkZFW02FdjBpXvfM7fjKUIsn55w7c9/73nPvJQDEtLZ0
         LQrwTxateebkkgB29g7wZhhl4UV+FfinA3uB4+CZ6eI3vq5s64AF/qKswMnpOZhgSGDlXJfysgLhSBzh
         SKIE53HEr5LIZHPQX15hiAZb1m23EEtoiCZuBRo4v09ncZWJwbvRBGXAAVcnwd1HhjJHR+oKVbPIt2PU
@@ -561,126 +760,6 @@
         RU5ErkJggg==
 </value>
   </data>
-  <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>205, 212</value>
-  </metadata>
-  <metadata name="statusBar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>237, 17</value>
-  </metadata>
-  <data name="toolStripMenuItem9.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
-        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
-        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
-        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
-        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
-        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
-        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
-</value>
-  </data>
-  <metadata name="mgBufferComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>446, 173</value>
-  </metadata>
-  <data name="mgBufferComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
-        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
-        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
-        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
-        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
-        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
-        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem10.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
-        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
-        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
-</value>
-  </data>
-  <metadata name="mgMeasureComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>17, 212</value>
-  </metadata>
-  <data name="mgMeasureComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
-        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
-        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem11.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
-        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
-        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
-        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
-        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
-        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
-        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
-        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
-        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
-        RK5CYII=
-</value>
-  </data>
-  <metadata name="mgQueryComponent1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>840, 173</value>
-  </metadata>
-  <data name="mgQueryComponent1.Icon" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
-        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
-        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
-        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
-        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
-        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
-        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
-        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
-        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
-        RK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem5.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
-        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
-        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
-        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
-        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
-        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
-        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem6.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
-        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
-        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem7.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
-        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
-        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
-        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
-        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
-        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
-        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
-        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
-        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
-        RK5CYII=
-</value>
-  </data>
   <data name="toolStripMenuItem1.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         R0lGODlhEAAQAIMAAAAAAP///ydYF5fYTmBfDJlmAGYzALWEU8yZZtSmeP/jyP///wAAAAAAAAAAAAAA
@@ -700,50 +779,6 @@
         nSWTmjy4k2hPoE6bOoVKVCpRqj6tFo0604DXr2DBKhwrMCAAOw==
 </value>
   </data>
-  <data name="toolStripMenuItem2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAFoSURBVDhPpVNdKwRRGN47jZ/g57hQJGSzmxSTUv4DF26F
-        tRa12JLaXVtKMimJ3ZKLsUyWbEImdsUwF37C4zwzTZ2z7a4pp956v57ned9zZiIRcbTJgy5NNzIduvGj
-        jRtVbcKYY461UIeAWNpC2qxj/swG/U7dgAz2REhMgUYRJhaKNmZSOfR0R5GtfKA3YSokJIwLYvbR6HNq
-        T4QEiyJJcGD520/0LfskNPrMsT6byiNTfgdX9gnEaKMbFgp3fkNgjGWTa4mSDQr7BGI/qvQnTezdqySM
-        m+XGNsUKQli5ZJIMJC+xX3WUSWRl1tjD3qYvxcLhg+OZDKTP3OCKD275vCwePX55JhMwHkqFAA+vlnH8
-        /K2AGTPfUjm4xKhoOn1RwYyZbzs2b3Nq+wYl21WUGY+s/QEOPqTsVU0Bn7+6iK2HAAcEuesalrYKHsnF
-        m4t4WHDwJU7vVHDy5GDXqoN+250b3/A/v/MvkqOAAMpRUaEAAAAASUVORK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem3.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAABjSURBVDhPY2AY+sDGxuY/Ob6A64MxiDUIQz1IgFwMdjlV
-        XEBRGJCjGUXPxCC2VfVBbP/QMVD8PzZxmBhIH9ggkMD/Fyn/F5ea/SeFBumDG/D9FNt/UjDIIrgBFHuB
-        4kAccAMAwje0sEjeZewAAAAASUVORK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem4.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADrwAAA68AZW8ckkAAAHySURBVDhPnZPLSxtRFMb9T6rUTW3Ulmw0GhqMNk0wSqCO
-        YhnNIkZUjCKUgvj4C7rSlUtXQksKRUHQxk0XhYpF8IETkpiHjxiT0TgTI0nm6z0DloxJbOmFj3Mf5/7u
-        me8wVVVFY2hyasLmcPjr6l8o1TW1eKZrVGhN+8V5ZeedbznB1PEGS5+82No/xHd/QI1Ln71oNppgc3D+
-        ipCuHk74uLCIH4EQdiIx/GLaDkfx8zii6ujsHIPDI6C8EsjY+w8TbRYbdo7D2D89Qzx9A+nuTp3vxk7+
-        aDsYQqupDZSvgXRz/cLK6hqOzuOIiSIKioLrTAZC/AKH7OViLXu/oJt7UIWu4aVyEI0hnEwhm8tBYYAT
-        8QrBxCUCD7QXieI5M1hTwZPqpwhfJnF6da1eTkqyCoimxBKFLhKg7mgAOkaMsIPEjaRepkg+lFOQ+UL5
-        GgD3jhfWv/kgypm/yvt1FZSvAUxPz3qaDUbI2Sxk5n45kTepdBpNhlZQfkkr+/oG/J7JKci3t8gVCiWS
-        WFdGx8bBDzhhbn+t9eCexvO88Ir12efbgsS8yOfzLErY2NiEocWI3t5+2O12uN3uypDZ+XkPgepZa6k7
-        FGlN+/SyXq+H1WqFy+WqDHnsp7mHWCwWOJ2PfM6/QMxm8/9VQXCqhDQzM4ffTfzkLal2r4sAAAAASUVO
-        RK5CYII=
-</value>
-  </data>
-  <data name="toolStripMenuItem12.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAC0SURBVDhPrZPLCsIwEEXzXeKyS/0bQUFxISiKK8EH/TXF
-        QtRiKBaLSqyrkQnkgovCkBg4zFyYOYRAlIo9raSTtpMuhcC7ihfPuQGD2Yak8K4TxOAEoQc3OGQnkrI/
-        avJAkOmcepMV4CwBAn0x1J+u6fmyrvrMfRM8A0F+LX5enrMECExRUggQ3MqKhvMt4CwBgnv1oNFiR3X9
-        cdVn7pvgGQj48cbLFHCWAIG1bwrhP4LY3/gFpD/IGPp59QYAAAAASUVORK5CYII=
-</value>
-  </data>
   <data name="toolStripMenuItem13.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktop.vcproj	2012-05-13 02:45:17 UTC (rev 6644)
@@ -1156,6 +1156,78 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeatureDistribution.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\FeatureGeometricFunctions.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\Rendering\FeatureInfoRenderer.cpp"
 				>
 				<FileConfiguration
@@ -1192,6 +1264,42 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeatureNumericFunctions.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\FeatureReader.cpp"
 				>
 				<FileConfiguration
@@ -1408,6 +1516,42 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeatureStringFunctions.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\FeatureUtil.cpp"
 				>
 				<FileConfiguration
@@ -2384,6 +2528,42 @@
 				</FileConfiguration>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\ProxyDataReader.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\RasterHelper.cpp"
 				>
 				<FileConfiguration
@@ -3510,6 +3690,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\BooleanDataReaderCreator.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\ByteDataReaderCreator.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Resource\ByteSourceDwfInputStreamImpl.h"
 				>
 			</File>
@@ -3546,6 +3734,18 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\DataReaderCreator.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\DateTimeDataReaderCreator.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\DoubleDataReaderCreator.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Drawing\DrawingDefs.h"
 				>
 			</File>
@@ -3606,10 +3806,22 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeatureDistribution.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\FeatureGeometricFunctions.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Rendering\FeatureInfoRenderer.h"
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeatureNumericFunctions.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\FeatureReader.h"
 				>
 			</File>
@@ -3634,10 +3846,22 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeatureStringFunctions.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\FeatureUtil.h"
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\FeautreNumericFunctions.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\GeometryDataReaderCreator.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\GwsConnectionPool.h"
 				>
 			</File>
@@ -3654,6 +3878,18 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\Int16DataReaderCreator.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\Int32DataReaderCreator.h"
+				>
+			</File>
+			<File
+				RelativePath=".\Services\Feature\Int64DataReaderCreator.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Exception\InvalidDwfPackageException.h"
 				>
 			</File>
@@ -3718,6 +3954,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\Matrix.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\MgCSTrans.h"
 				>
 			</File>
@@ -3762,6 +4002,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\ProxyDataReader.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\RasterHelper.h"
 				>
 			</File>
@@ -3834,6 +4078,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\SingleDataReaderCreator.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Feature\SpatialContextCacheItem.h"
 				>
 			</File>
@@ -3842,6 +4090,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\StringDataReaderCreator.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Exception\StylizeLayerFailedException.h"
 				>
 			</File>
@@ -3870,6 +4122,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\Services\Feature\UniqueFunction.h"
+				>
+			</File>
+			<File
 				RelativePath=".\Services\Rendering\UnitType.h"
 				>
 			</File>

Modified: branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MgDesktop/MgDesktopBuild.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -44,16 +44,21 @@
 #include "Services/Feature/FdoForcedOneToOneFeatureReader.cpp"
 #include "Services/Feature/FeatureClassCacheItem.cpp"
 #include "Services/Feature/FeatureConnection.cpp"
+#include "Services/Feature/FeatureDistribution.cpp"
+#include "Services/Feature/FeatureGeometricFunctions.cpp"
+#include "Services/Feature/FeatureNumericFunctions.cpp"
 #include "Services/Feature/FeatureSchemaCacheItem.cpp"
 #include "Services/Feature/FeatureServiceCacheEntry.cpp"
 #include "Services/Feature/FeatureServiceCache.cpp"
 #include "Services/Feature/FeatureSourceCacheItem.cpp"
+#include "Services/Feature/FeatureStringFunctions.cpp"
 #include "Services/Feature/FeatureUtil.cpp"
 #include "Services/Feature/GwsConnectionPool.cpp"
 #include "Services/Feature/GwsFeatureReader.cpp"
 #include "Services/Feature/JoinFeatureReader.cpp"
 #include "Services/Feature/MgCSTrans.cpp"
 #include "Services/Feature/ProjectedFeatureReader.cpp"
+#include "Services/Feature/ProxyDataReader.cpp"
 #include "Services/Feature/RasterHelper.cpp"
 #include "Services/Feature/RdbmsFeatureSourceParams.cpp"
 #include "Services/Feature/SpatialContextCacheItem.cpp"

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/BooleanDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/BooleanDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/BooleanDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_BOOLEAN_DATA_READER_CREATOR_H
+#define MG_BOOLEAN_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgBooleanDataReaderCreator : public MgDataReaderCreator<INT16>
+{
+    DECLARE_CLASSNAME(MgBooleanDataReaderCreator)
+
+public:
+    MgBooleanDataReaderCreator()
+    {
+    }
+
+    MgBooleanDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Boolean;
+    }
+
+    ~MgBooleanDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(INT16 val)
+    {
+        return new MgBooleanProperty(m_propertyAlias, (bool)val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ByteDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ByteDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ByteDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_BYTE_DATA_READER_CREATOR_H
+#define MG_BYTE_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgByteDataReaderCreator : public MgDataReaderCreator<INT8>
+{
+    DECLARE_CLASSNAME(MgByteDataReaderCreator)
+
+public:
+    MgByteDataReaderCreator()
+    {
+    }
+
+    MgByteDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Byte;
+    }
+
+    ~MgByteDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(INT8 val)
+    {
+        return new MgByteProperty(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,170 @@
+//
+//  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_DATA_READER_CREATOR_H
+#define MG_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+#include "MgDesktop.h"
+#include "ProxyDataReader.h"
+
+template <typename T>
+class MgDataReaderCreator : public MgDisposable
+{
+public:
+
+    MgDataReader* Execute(const std::vector<double>& in)
+    {
+        // We convert to appropriate types here
+        std::vector<T> values;
+        ConvertVector(in, values);
+
+        // Use the converted vector
+        Ptr<MgPropertyDefinitionCollection> propDefCol = this->GetPropertyDefinitions();
+        Ptr<MgBatchPropertyCollection> bpCol = this->GetBatchCollection(values);
+        return new MgProxyDataReader(bpCol, propDefCol);
+    }
+
+    MgDataReader* Execute(const std::vector<INT64>& in)
+    {
+        // We convert to appropriate types here
+        std::vector<T> values;
+        ConvertVector(in, values);
+
+        // Use the converted vector
+        Ptr<MgPropertyDefinitionCollection> propDefCol = this->GetPropertyDefinitions();
+        Ptr<MgBatchPropertyCollection> bpCol = this->GetBatchCollection(values);
+        return new MgProxyDataReader(bpCol, propDefCol);
+    }
+
+    MgDataReader* Execute(const std::vector<STRING>& in)
+    {
+        Ptr<MgPropertyDefinitionCollection> propDefCol = this->GetPropertyDefinitions();
+        Ptr<MgBatchPropertyCollection> bpCol = this->GetBatchCollection(in);
+        return new MgProxyDataReader(bpCol, propDefCol);
+    }
+
+    MgDataReader* Execute(MgGeometryCollection* in)
+    {
+        Ptr<MgPropertyDefinitionCollection> propDefCol = this->GetPropertyDefinitions();
+        Ptr<MgBatchPropertyCollection> bpCol = this->GetBatchCollection(in);
+        return new MgProxyDataReader(bpCol, propDefCol);
+    }
+
+    MgPropertyDefinitionCollection* GetPropertyDefinitions()
+    {
+        // Create property definition for the type specified
+        Ptr<MgPropertyDefinition> propDef = new MgPropertyDefinition(m_propertyAlias, m_propType);
+
+        // Add to property definition collection
+        Ptr<MgPropertyDefinitionCollection> propDefCol = new MgPropertyDefinitionCollection();
+        propDefCol->Add(propDef);
+
+        return propDefCol.Detach();
+    }
+
+    MgBatchPropertyCollection* GetBatchCollection(MgGeometryCollection* in)
+    {
+        // Create collection of properties
+        Ptr<MgBatchPropertyCollection> bpCol = new MgBatchPropertyCollection();
+
+        if (in != NULL)
+        {
+            INT32 cnt = in->GetCount();
+            for (INT32 i=0; i < cnt; i++)
+            {
+                // Add one value as one Feature (PropertyCollection)
+                Ptr<MgGeometry> geom = in->GetItem(i);
+                Ptr<MgProperty> prop = this->GetProperty(geom);
+                Ptr<MgPropertyCollection> propCol = new MgPropertyCollection();
+                propCol->Add(prop);     // Feature defined
+                bpCol->Add(propCol);    //  Add to set of Batch Collection
+            }
+        }
+
+        return bpCol.Detach();
+    }
+
+    MgBatchPropertyCollection* GetBatchCollection(const std::vector<T>& in)
+    {
+        int cnt = (int)in.size();
+
+        // Create collection of properties
+        Ptr<MgBatchPropertyCollection> bpCol = new MgBatchPropertyCollection();
+        for (int i=0; i < cnt; i++)
+        {
+            // Add one value as one Feature (PropertyCollection)
+            Ptr<MgProperty> prop = this->GetProperty((T)in[i]);
+            Ptr<MgPropertyCollection> propCol = new MgPropertyCollection();
+            propCol->Add(prop);     // Feature defined
+            bpCol->Add(propCol);    //  Add to set of Batch Collection
+        }
+
+        return bpCol.Detach();
+    }
+
+    void ConvertVector(const std::vector<double>& in, std::vector<T>& values)
+    {
+        // There will always be only few values and therefore copy should be fine.
+        int cnt = (int)in.size();
+        for(int i = 0; i < cnt; i++)
+        {
+            values.push_back((T)in[i]);
+        }
+    }
+
+    void ConvertVector(const std::vector<INT64>& in, std::vector<T>& values)
+    {
+        // There will always be only few values and therefore copy should be fine.
+        int cnt = (int)in.size();
+        for(int i = 0; i < cnt; i++)
+        {
+            values.push_back((T)in[i]);
+        }
+    }
+
+    // The following GetProperty methods must be overridden by derived class
+    virtual MgProperty* GetProperty(double val)     {return NULL;}
+    virtual MgProperty* GetProperty(float val)      {return NULL;}
+    virtual MgProperty* GetProperty(INT8 val)      {return NULL;}
+    virtual MgProperty* GetProperty(INT16 val)      {return NULL;}
+    virtual MgProperty* GetProperty(INT32 val)      {return NULL;}
+    virtual MgProperty* GetProperty(INT64 val)      {return NULL;}
+    virtual MgProperty* GetProperty(CREFSTRING val) {return NULL;}
+    virtual MgProperty* GetProperty(MgGeometry* val) {return NULL;}
+
+protected:
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+    MgDataReaderCreator()
+    {
+        m_propType = MgPropertyType::Null;
+    }
+    ~MgDataReaderCreator()
+    {
+    }
+
+    STRING m_propertyAlias;
+    int m_propType;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DateTimeDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DateTimeDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DateTimeDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,58 @@
+//
+//  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_DATETIME_DATA_READER_CREATOR_H
+#define MG_DATETIME_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgDateTimeDataReaderCreator : public MgDataReaderCreator<double>
+{
+    DECLARE_CLASSNAME(MgDateTimeDataReaderCreator)
+
+public:
+    MgDateTimeDataReaderCreator()
+    {
+    }
+
+    MgDateTimeDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::DateTime;
+    }
+
+    ~MgDateTimeDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(double val)
+    {
+        Ptr<MgDateTime> dateTime = new MgDateTime(val);
+        return new MgDateTimeProperty(m_propertyAlias, dateTime);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DoubleDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DoubleDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/DoubleDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_DOUBLE_DATA_READER_CREATOR_H
+#define MG_DOUBLE_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgDoubleDataReaderCreator : public MgDataReaderCreator<double>
+{
+    DECLARE_CLASSNAME(MgDoubleDataReaderCreator)
+
+public:
+    MgDoubleDataReaderCreator()
+    {
+    }
+
+    MgDoubleDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Double;
+    }
+
+    ~MgDoubleDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(double val)
+    {
+        return new MgDoubleProperty(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.cpp	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -215,3 +215,40 @@
         FDO_SAFE_ADDREF(m_fdoConn);
     m_bCloseConnection = false;
 }
+
+bool MgFeatureConnection::IsSupportedFunction(FdoFunction* fdoFunc)
+{
+	CHECKNULL(m_fdoConn, L"MgFeatureConnection.SupportsFunction");
+
+    FdoPtr<FdoIExpressionCapabilities> fec = m_fdoConn->GetExpressionCapabilities();
+    CHECKNULL((FdoIExpressionCapabilities*)fec, L"MgFeatureConnection.SupportsFunction");
+
+    bool supports = false;
+
+    FdoPtr<FdoFunctionDefinitionCollection> ffdc = fec->GetFunctions();
+    if (NULL != (FdoFunctionDefinitionCollection*)ffdc)
+    {
+        FdoInt32 funcCnt = ffdc->GetCount();
+        for (FdoInt32 i=0; i < funcCnt; i++)
+        {
+            FdoPtr<FdoFunctionDefinition> ffd = ffdc->GetItem(i);
+            CHECKNULL((FdoFunctionDefinition*)ffd, L"MgFeatureConnection.SupportsFunction");
+
+            // TODO: Just comparing name is enough?
+            // TODO: I think, NOT, because there can be overloaded functions like one function
+            // with multiple arguments, differnet datatypes etc.
+            //
+            // Comparing argument count is not sufficient because, there can be optional arguments
+            // as well. Therefore, we should just restrict to name comparision only
+            FdoString* funcNameAllowed = ffd->GetName();
+            FdoString* funcNameSupplied = fdoFunc->GetName();
+            size_t cmp = _wcsicmp(funcNameAllowed, funcNameSupplied);
+            if (cmp == 0)
+            {
+                supports = true;
+                break;
+            }
+        }
+    }
+    return supports;
+}
\ No newline at end of file

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.h	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureConnection.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -37,6 +37,7 @@
     bool SupportsSelectOrdering();
     FdoJoinType GetJoinTypes() const;
 
+	bool IsSupportedFunction(FdoFunction* function);
     void OwnReader();
 
 private:

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,103 @@
+//
+//  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 "FeatureDefs.h"
+#include "FeatureDistribution.h"
+#include "FeatureUtil.h"
+#include "math.h"
+#include "float.h"
+#include <algorithm>
+#include "Matrix.h"
+#include "UniqueFunction.h"
+//#include "DataReaderCreator.h"
+//#include "DoubleDataReaderCreator.h"
+//#include "StringDataReaderCreator.h"
+#include "FeatureNumericFunctions.h"
+#include "FeatureGeometricFunctions.h"
+#include "FeatureStringFunctions.h"
+
+MgFeatureDistribution::MgFeatureDistribution()
+{
+}
+
+MgFeatureDistribution::~MgFeatureDistribution()
+{
+}
+
+MgFeatureDistribution* MgFeatureDistribution::CreateDistributionFunction(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    STRING propName;
+    Ptr<MgFeatureDistribution> featDist;
+
+    INT32 propType;
+    if(1 == reader->GetPropertyCount())
+    {
+        propType = MgFeatureUtil::GetPropertyDefinition(reader, propName);
+    }
+    else
+    {
+        // Only get the property needed
+        FdoPtr<FdoExpressionCollection> exprCol = customFunction->GetArguments();
+        FdoInt32 cnt = exprCol->GetCount();
+        FdoPtr<FdoExpression> expr;
+        if(cnt == 1)
+        {
+            expr = exprCol->GetItem(0);
+            FdoIdentifier* propIdentifier = dynamic_cast<FdoIdentifier*>(expr.p);
+            CHECKNULL(propIdentifier, L"MgFeatureDistribution.CreateDistributionFunction");
+            propName = propIdentifier->GetName();
+            propType = reader->GetPropertyType(propName);
+        }
+        else
+        {
+            // Throw original exception
+            propType = MgFeatureUtil::GetPropertyDefinition(reader, propName);
+        }
+    }
+
+    switch(propType)
+    {
+        case MgPropertyType::DateTime:
+        case MgPropertyType::Double:
+        case MgPropertyType::Byte:
+        case MgPropertyType::Int16:
+        case MgPropertyType::Int32:
+        case MgPropertyType::Int64:
+        case MgPropertyType::Single:
+        case MgPropertyType::Boolean:
+        {
+            featDist = new MgFeatureNumericFunctions(reader, customFunction, propertyAlias);
+            break;
+        }
+        case MgPropertyType::String:
+        {
+            featDist = new MgFeatureStringFunctions(reader, customFunction, propertyAlias);
+            break;
+        }
+        case MgPropertyType::Geometry:
+        {
+            featDist = new MgFeatureGeometricFunctions(reader, customFunction, propertyAlias);
+            break;
+        }
+        default:
+        {
+            throw new MgInvalidPropertyTypeException(
+                L"MgFeatureDistribution.CreateDistributionFunction", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+    }
+    return featDist.Detach();
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureDistribution.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,42 @@
+//
+//  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 _MGFEATUREDISTRIBUTION_H
+#define _MGFEATUREDISTRIBUTION_H
+
+class MgDisposable;
+class FdoFunction;
+class MgReader;
+
+class MgFeatureDistribution : public MgDisposable
+{
+public:
+
+    static MgFeatureDistribution* CreateDistributionFunction(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+    virtual MgReader* Execute() = 0;
+
+protected:
+
+    MgFeatureDistribution();
+    virtual ~MgFeatureDistribution();
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,300 @@
+//
+//  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 "FeatureDefs.h"
+#include "FeatureUtil.h"
+#include "FeatureDistribution.h"
+#include "FeatureGeometricFunctions.h"
+#include "DataReaderCreator.h"
+//#include "StringDataReaderCreator.h"
+#include "GeometryDataReaderCreator.h"
+#include <algorithm>
+#include "UniqueFunction.h"
+
+MgFeatureGeometricFunctions::MgFeatureGeometricFunctions()
+{
+    m_type = MgPropertyType::Null;
+    m_reader = NULL;
+    m_customFunction = NULL;
+    m_propertyAlias = L"";
+    m_extentsInitialized = false;
+}
+
+MgFeatureGeometricFunctions::MgFeatureGeometricFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    Initialize(reader, customFunction, propertyAlias); // Initialize the instance
+}
+
+void MgFeatureGeometricFunctions::Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    CHECKNULL((MgReader*)reader, L"MgFeatureGeometricFunctions.Initialize");
+    CHECKNULL((FdoFunction*)customFunction, L"MgFeatureGeometricFunctions.Initialize");
+
+    if(1 == reader->GetPropertyCount())
+    {
+        m_type = MgFeatureUtil::GetPropertyDefinition(reader, m_propertyName);
+    }
+    else
+    {
+        // Only get the property needed
+        FdoPtr<FdoExpressionCollection> exprCol = customFunction->GetArguments();
+        FdoInt32 cnt = exprCol->GetCount();
+        FdoPtr<FdoExpression> expr;
+        if(cnt == 1)
+        {
+            expr = exprCol->GetItem(0);
+            FdoIdentifier* propName = dynamic_cast<FdoIdentifier*>(expr.p);
+            CHECKNULL(propName, L"MgFeatureGeometricFunctions.Initialize");
+            m_propertyName = propName->GetName();
+            m_type = reader->GetPropertyType(m_propertyName);
+        }
+        else
+        {
+            // Throw original exception
+            m_type = MgFeatureUtil::GetPropertyDefinition(reader, m_propertyName);
+        }
+    }
+
+    // TODO: Should we really check this, may be we can ignore ??
+    // because we can only come to here if property type is numeric
+    if (!this->CheckSupportedPropertyType())
+	{
+		throw new MgInvalidPropertyTypeException(
+			L"MgFeatureGeometricFunctions.Initialize", __LINE__, __WFILE__, NULL, L"", NULL);
+	}
+
+    // We must have an property alias
+    // Though we can name a property with same name as function expression
+    // But Fdo forces to have an alias. Therefore we implement this restriction.
+    if (propertyAlias.empty())
+    {
+        STRING message = MgFeatureUtil::GetMessage(L"MgMissingPropertyAlias");
+
+        MgStringCollection arguments;
+        arguments.Add(message);
+        throw new MgFeatureServiceException(L"MgFeatureGeometricFunctions.Initialize", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    m_reader = SAFE_ADDREF(reader);
+    m_customFunction = FDO_SAFE_ADDREF(customFunction);
+    m_propertyAlias = propertyAlias;
+    m_extentsInitialized = false;
+}
+
+
+MgFeatureGeometricFunctions::~MgFeatureGeometricFunctions()
+{
+}
+
+// Execute the function
+MgReader* MgFeatureGeometricFunctions::Execute()
+{
+    CHECKNULL((MgReader*)m_reader, L"MgFeatureGeometricFunctions.Execute");
+    CHECKNULL(m_customFunction, L"MgFeatureGeometricFunctions.Execute");
+
+    Ptr<MgGeometryCollection> geomCol = new MgGeometryCollection();
+
+    MG_LOG_TRACE_ENTRY(L"MgFeatureGeometricFunctions::Execute");
+    while(m_reader->ReadNext())
+    {
+        // Get the geometry
+        Ptr<MgGeometry> val = GetValue();
+
+        // Get the envelope
+        Ptr<MgEnvelope> envl = val->Envelope();
+        Ptr<MgCoordinate> lcoord;
+        Ptr<MgCoordinate> rcoord;
+        if (envl != NULL)
+        {
+            lcoord = envl->GetLowerLeftCoordinate();
+            rcoord = envl->GetUpperRightCoordinate();
+        }
+
+        // Compare with min/max coordinates
+        ComputeExtents(lcoord, rcoord);
+    }
+
+    // Execute the operation on the collected extents
+    Ptr<MgGeometryCollection> finalResult = ExecuteOperation();
+
+    // Create FeatureReader from geometric values
+    return GetReader(finalResult);
+}
+
+void MgFeatureGeometricFunctions::ComputeExtents(MgCoordinate* lowerLeft,
+                                                    MgCoordinate* upperRight)
+{
+    CHECKNULL((MgCoordinate*)lowerLeft, L"MgFeatureGeometricFunctions.ComputeExtents");
+    CHECKNULL((MgCoordinate*)upperRight, L"MgFeatureGeometricFunctions.ComputeExtents");
+
+    if (!m_extentsInitialized)
+    {
+        m_minX = lowerLeft->GetX();
+        m_minY = lowerLeft->GetY();
+        m_minZ = lowerLeft->GetZ();
+        m_minM = lowerLeft->GetM();
+
+        m_maxX = upperRight->GetX();
+        m_maxY = upperRight->GetY();
+        m_maxZ = upperRight->GetZ();
+        m_maxM = upperRight->GetM();
+
+        m_extentsInitialized = true;
+    }
+    else
+    {
+        if (lowerLeft->GetX() < m_minX)
+            m_minX = lowerLeft->GetX();
+        if (lowerLeft->GetY() < m_minY)
+            m_minY = lowerLeft->GetY();
+        if (lowerLeft->GetZ() < m_minZ)
+            m_minZ = lowerLeft->GetZ();
+        if (lowerLeft->GetM() < m_minM)
+            m_minM = lowerLeft->GetM();
+
+        if (upperRight->GetX() > m_maxX)
+            m_maxX = upperRight->GetX();
+        if (upperRight->GetY() > m_maxY)
+            m_maxY = upperRight->GetY();
+        if (upperRight->GetZ() > m_maxZ)
+            m_maxZ = upperRight->GetZ();
+        if (upperRight->GetM() > m_maxM)
+            m_maxM = upperRight->GetM();
+    }
+}
+
+MgGeometryCollection* MgFeatureGeometricFunctions::ExecuteOperation()
+{
+    INT32 funcCode = -1;
+
+    Ptr<MgGeometryCollection> result;
+
+    // Get the arguments from the FdoFunction
+    STRING propertyName;
+    bool supported = MgFeatureUtil::FindCustomFunction(m_customFunction, funcCode);
+
+    if (supported)
+    {
+        switch(funcCode)
+        {
+            case EXTENT:
+            {
+                // Create the geometry collection for the extents
+                MgGeometryFactory factory;
+
+                // TODO: Assuming we are two dimensional for now.
+
+                //Ptr<MgCoordinate> coord1 = factory.CreateCoordinateXYZM(minX, minY, minZ, minM);
+                //Ptr<MgCoordinate> coord2 = factory.CreateCoordinateXYZM(maxX, maxY, maxZ, maxM);
+
+                Ptr<MgCoordinate> coord1 = factory.CreateCoordinateXY(m_minX, m_minY);
+                Ptr<MgCoordinate> coord2 = factory.CreateCoordinateXY(m_maxX, m_minY);
+                Ptr<MgCoordinate> coord3 = factory.CreateCoordinateXY(m_maxX, m_maxY);
+                Ptr<MgCoordinate> coord4 = factory.CreateCoordinateXY(m_minX, m_maxY);
+
+                Ptr<MgCoordinateCollection> coordCol = new MgCoordinateCollection();
+                coordCol->Add(coord1);
+                coordCol->Add(coord2);
+                coordCol->Add(coord3);
+                coordCol->Add(coord4);
+
+                Ptr<MgLinearRing> outerRing = factory.CreateLinearRing(coordCol);
+                Ptr<MgGeometry> geom = factory.CreatePolygon(outerRing, NULL);
+
+                result = new MgGeometryCollection();
+                result->Add(geom);
+
+                break;
+            }
+            default:
+            {
+                STRING message = MgFeatureUtil::GetMessage(L"MgCustomFunctionNotSupported");
+
+                MgStringCollection arguments;
+                arguments.Add(message);
+                throw new MgFeatureServiceException(
+                    L"MgFeatureGeometricFunctions.ExecuteOperation",
+                    __LINE__, __WFILE__, &arguments, L"", NULL);
+            }
+        }
+    }
+
+    return result.Detach();
+}
+
+// Check whether property type is a supported type
+bool MgFeatureGeometricFunctions::CheckSupportedPropertyType()
+{
+	return MgPropertyType::Geometry == m_type;
+}
+
+
+// Get the value of property
+MgGeometry* MgFeatureGeometricFunctions::GetValue()
+{
+    Ptr<MgGeometry> geom;
+
+    if (!m_reader->IsNull(m_propertyName))
+    {
+        switch(m_type)
+        {
+            case MgPropertyType::Geometry:
+            {
+                Ptr<MgByteReader> reader = m_reader->GetGeometry(m_propertyName);
+                if (reader != NULL)
+                {
+                    MgAgfReaderWriter agfReader;
+                    geom = agfReader.Read(reader);
+                }
+                break;
+            }
+            default:
+            {
+                throw new MgInvalidPropertyTypeException(
+                    L"MgFeatureGeometricFunctions.GetValue",
+                    __LINE__, __WFILE__, NULL, L"", NULL);
+            }
+        }
+    }
+
+    return geom.Detach();
+}
+
+
+
+
+// Create the reader for string properties
+MgReader* MgFeatureGeometricFunctions::GetReader(MgGeometryCollection* geomCol)
+{
+    Ptr<MgDataReader> dataReader;
+
+    switch(m_type)
+    {
+        case MgPropertyType::Geometry:
+        {
+            Ptr<MgGeometryDataReaderCreator> drCreator = new MgGeometryDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(geomCol);
+            break;
+        }
+        default:
+        {
+            throw new MgInvalidPropertyTypeException(
+                L"MgFeatureGeometricFunctions.GetReader", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+    }
+    return dataReader.Detach();
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureGeometricFunctions.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,91 @@
+//
+//  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_FEATURE_GEOMETRIC_FUNCTIONS_H_
+#define MG_FEATURE_GEOMETRIC_FUNCTIONS_H_
+
+class MgDisposable;
+class FdoFunction;
+class MgReader;
+class MgFeatureDistribution;
+class MgGeometry;
+class MgGeometryCollection;
+
+class MgFeatureGeometricFunctions : public MgFeatureDistribution
+{
+    DECLARE_CLASSNAME(MgFeatureGeometricFunctions)
+
+public:
+
+    MgFeatureGeometricFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+    virtual MgReader* Execute();
+
+protected:
+
+    MgFeatureGeometricFunctions();
+    virtual ~MgFeatureGeometricFunctions();
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+private:
+
+    struct CoordinateCollection
+    {
+        std::vector<double> x_coords;
+        std::vector<double> y_coords;
+        std::vector<double> z_coords;
+        std::vector<double> m_coords;
+    };
+
+    MgGeometry* GetValue();
+
+    void Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+
+    void ComputeExtents(MgCoordinate* lowerLeft, MgCoordinate* upperRight);
+    MgGeometryCollection* ExecuteOperation();
+
+    MgReader* GetReader(MgGeometryCollection* returnGeom);
+
+	//WTF: The original method was void and threw MgInvalidPropertyTypeException if not supported
+	//MSVC 2008 blows up on the linker phase with a combination of C1001 at this method and LNK1000
+	//
+	//Changing this method to return bool (supported = true) and throwing MgInvalidPropertyTypeException in
+	//the method that calls this (Initialize()) makes the problem go away. Real WTF there!
+    bool CheckSupportedPropertyType();
+
+private:
+
+    STRING m_propertyName;
+    INT16 m_type;
+    Ptr<MgReader> m_reader;
+    FdoPtr<FdoFunction> m_customFunction;
+    STRING m_propertyAlias;
+
+    bool m_extentsInitialized;
+    double m_minX;
+    double m_minY;
+    double m_minZ;
+    double m_minM;
+    double m_maxX;
+    double m_maxY;
+    double m_maxZ;
+    double m_maxM;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,1039 @@
+//
+//  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 "FeatureDefs.h"
+#include "FeatureUtil.h"
+#include "FeatureDistribution.h"
+#include "FeatureNumericFunctions.h"
+#include "math.h"
+#include "float.h"
+#include <algorithm>
+#include "Matrix.h"
+#include "UniqueFunction.h"
+#include "DataReaderCreator.h"
+#include "DoubleDataReaderCreator.h"
+#include "ByteDataReaderCreator.h"
+#include "Int16DataReaderCreator.h"
+#include "Int32DataReaderCreator.h"
+#include "Int64DataReaderCreator.h"
+#include "SingleDataReaderCreator.h"
+#include "StringDataReaderCreator.h"
+#include "DateTimeDataReaderCreator.h"
+#include "BooleanDataReaderCreator.h"
+
+MgFeatureNumericFunctions::MgFeatureNumericFunctions()
+{
+    m_type = MgPropertyType::Null;
+    m_reader = NULL;
+    m_customFunction = NULL;
+    m_propertyAlias = L"";
+}
+
+MgFeatureNumericFunctions::MgFeatureNumericFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    Initialize(reader, customFunction, propertyAlias); // Initialize the instance
+}
+
+void MgFeatureNumericFunctions::Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    CHECKNULL((MgReader*)reader, L"MgFeatureNumericFunctions.Initialize");
+    CHECKNULL((FdoFunction*)customFunction, L"MgFeatureNumericFunctions.Initialize");
+
+    if(1 == reader->GetPropertyCount())
+    {
+        m_type = MgFeatureUtil::GetPropertyDefinition(reader, m_propertyName);
+    }
+    else
+    {
+        // Only get the property needed
+        FdoPtr<FdoExpressionCollection> exprCol = customFunction->GetArguments();
+        FdoInt32 cnt = exprCol->GetCount();
+        FdoPtr<FdoExpression> expr;
+        if(cnt == 1)
+        {
+            expr = exprCol->GetItem(0);
+            FdoIdentifier* propName = dynamic_cast<FdoIdentifier*>(expr.p);
+            CHECKNULL(propName, L"MgFeatureNumericFunctions.Initialize");
+            m_propertyName = propName->GetName();
+            m_type = reader->GetPropertyType(m_propertyName);
+        }
+        else
+        {
+            // Throw original exception
+            m_type = MgFeatureUtil::GetPropertyDefinition(reader, m_propertyName);
+        }
+    }
+
+    // TODO: Should we really check this, may be we can ignore ??
+    // because we can only come to here if property type is numeric
+    this->CheckSupportedPropertyType();
+
+    // We must have an property alias
+    // Though we can name a property with same name as function expression
+    // But Fdo forces to have an alias. Therefore we implement this restriction.
+    if (propertyAlias.empty())
+    {
+        STRING message = MgFeatureUtil::GetMessage(L"MgMissingPropertyAlias");
+
+        MgStringCollection arguments;
+        arguments.Add(message);
+        throw new MgFeatureServiceException(L"MgFeatureDistribution.Initialize", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    m_reader = SAFE_ADDREF(reader);
+    m_customFunction = FDO_SAFE_ADDREF(customFunction);
+    m_propertyAlias = propertyAlias;
+}
+
+MgFeatureNumericFunctions::~MgFeatureNumericFunctions()
+{
+}
+
+MgReader* MgFeatureNumericFunctions::Execute()
+{
+    CHECKNULL((MgReader*)m_reader, L"MgFeatureNumericFunctions.Execute");
+    CHECKNULL(m_customFunction, L"MgFeatureNumericFunctions.Execute");
+
+    Ptr<MgReader> reader;
+    MG_LOG_TRACE_ENTRY(L"MgFeatureNumericFunctions::Execute");
+    // TODO: Can this be optimized to process them as they are read?
+    // TODO: Should we put a limit on double buffer
+    INT32 funcCode = -1;
+    bool supported = MgFeatureUtil::FindCustomFunction(m_customFunction, funcCode);
+    if (supported)
+    {
+        // In case we have int64 but is a custom function use double to evaluate it.
+        // Since we don't have a type which can make operations with big numbers we will fix only Unique/Min/Max functions
+        // Even if we treat int64 different from double we don't solve the issue with truncation error.
+        // If we emulate SUM adding two big numbers we will get overflow even we use int64, e.g.:
+        // Int64 val1 = 9223372036854775806;
+        // Int64 val2 = 9223372036854775807;
+        // Int64 sum = val1 + val2; // the sum value will be -3 so is overflow error
+        // In the future we will need to implement a type which can handle int64 numbers without getting overflow a sum/avg is calculated.
+        // Since all other functions calculate a sum we will use double, at least to be able to get the right result for small numbers.
+        if (!(m_type == MgPropertyType::Int64 && (funcCode == MINIMUM || funcCode == MAXIMUM || funcCode == UNIQUE)))
+        {
+            VECTOR values, distValues;
+            while(m_reader->ReadNext())
+            {
+                // TODO: Add support for Geometry extents
+                double val = GetValue();
+                values.push_back(val);
+            }
+            // Calulate the distribution on the collected values
+            CalculateDistribution(values, distValues);
+
+            // Create FeatureReader from distribution values
+            reader = GetReader(distValues);
+        }
+        else
+        {
+            VECTOR_INT64 values, distValues;
+            while(m_reader->ReadNext())
+            {
+                INT64 int64Val = 0;
+                if (!m_reader->IsNull(m_propertyName))
+                    int64Val = m_reader->GetInt64(m_propertyName);
+                values.push_back(int64Val);
+            }
+
+            // Calulate the distribution on the collected values
+            CalculateDistribution(values, distValues);
+
+            // Create FeatureReader from distribution values
+            Ptr<MgInt64DataReaderCreator> drCreator = new MgInt64DataReaderCreator(m_propertyAlias);
+            reader = drCreator->Execute(distValues);
+        }
+    }
+    else
+    {
+        // just return an emty reader
+        VECTOR distValues;
+        reader = GetReader(distValues);
+    }
+
+    return reader.Detach();
+}
+
+// Check whether property type is a supported type
+void MgFeatureNumericFunctions::CheckSupportedPropertyType()
+{
+    bool supported = false;
+    switch(m_type)
+    {
+        case MgPropertyType::DateTime:
+        case MgPropertyType::Double:
+        case MgPropertyType::Byte:
+        case MgPropertyType::Int16:
+        case MgPropertyType::Int32:
+        case MgPropertyType::Int64:
+        case MgPropertyType::Single:
+        case MgPropertyType::Boolean:
+        {
+            supported = true;
+            break;
+        }
+        default:
+        {
+            throw new MgInvalidPropertyTypeException(L"MgFeatureNumericFunctions.CheckSupportedPropertyType",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+    }
+    return;
+}
+
+// Get the value of property
+double MgFeatureNumericFunctions::GetValue()
+{
+    double val = 0;
+
+    if (!m_reader->IsNull(m_propertyName))
+    {
+        switch(m_type)
+        {
+            case MgPropertyType::Double:
+            {
+                val = (double)m_reader->GetDouble(m_propertyName);
+                break;
+            }
+            case MgPropertyType::Byte:
+            {
+                val = (double)m_reader->GetByte(m_propertyName);
+                break;
+            }
+            case MgPropertyType::Int16:
+            {
+                val = (double)m_reader->GetInt16(m_propertyName);
+                break;
+            }
+            case MgPropertyType::Int32:
+            {
+                val = (double)m_reader->GetInt32(m_propertyName);
+                break;
+            }
+            case MgPropertyType::Int64:
+            {
+                val = (double)m_reader->GetInt64(m_propertyName);
+                break;
+            }
+            case MgPropertyType::Single:
+            {
+                val = (double)m_reader->GetSingle(m_propertyName);
+                break;
+            }
+            case MgPropertyType::DateTime:
+            {
+                Ptr<MgDateTime> dateTime = m_reader->GetDateTime(m_propertyName);
+                val = dateTime->ToNumber();
+                break;
+            }
+            case MgPropertyType::Boolean:
+            {
+                val = (double)m_reader->GetBoolean(m_propertyName);
+                break;
+            }
+            default:
+            {
+                throw new MgInvalidPropertyTypeException(L"MgFeatureNumericFunctions.CheckSupportedPropertyType",
+                    __LINE__, __WFILE__, NULL, L"", NULL);
+            }
+        }
+    }
+    return val;
+}
+
+// Calculate equal categories
+void MgFeatureNumericFunctions::GetEqualCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues)
+{
+    // Expected categories should be more than zero
+    if (numCats <= 0)
+    {
+        STRING message = MgFeatureUtil::GetMessage(L"MgInvalidComputedProperty");
+
+        MgStringCollection arguments;
+        arguments.Add(message);
+        throw new MgFeatureServiceException(L"MgServerSelectFeatures.GetEqualCategories", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    // find the range of the data values
+    double min = DoubleMaxValue;
+    double max = -DoubleMaxValue;
+
+    int cnt = (int)values.size();
+    if (cnt <= 0) { return; } // Nothing to do, we just send back Property Definition to clients from reader
+
+    for (int i=0; i < cnt; i++)
+    {
+        double val = values[i];
+
+        if (val > max)
+            max = val;
+        if (val < min)
+            min = val;
+    }
+
+    // expand the range a little to account for numerical instability
+    double delta = 0.0001 * (max - min);
+    min -= delta;
+    max += delta;
+    // but don't let the values extend beyond the data min/max
+    if (min < dataMin)
+        min = dataMin;
+    if (max > dataMax)
+        max = dataMax;
+
+    // This method ignores dataMin and dataMax.  A different "Equal" distribution
+    // might ignore the actual data values and create categories based on dataMin
+    // and dataMax when those values are not +/- infinity.
+
+    // fill in the categories
+    distValues.push_back(min);
+    delta = (max - min) / (double)numCats;
+    for (int i=1; i<numCats; i++)
+    {
+        double nextval = distValues[i-1] + delta;
+        distValues.push_back(nextval);
+    }
+    distValues.push_back(max);
+}
+
+
+void MgFeatureNumericFunctions::GetMinimum(VECTOR &values, VECTOR &distValues)
+{
+    // TODO: Change this algorithm to take reader directly instead of vector
+
+    // find the range of the data values
+    distValues.push_back(MgFeatureUtil::Minimum(values));
+}
+
+
+void MgFeatureNumericFunctions::GetMinimum(VECTOR_INT64 &values, VECTOR_INT64 &distValues)
+{
+    // TODO: Change this algorithm to take reader directly instead of vector
+
+    // find the range of the data values
+    distValues.push_back(MgFeatureUtil::Minimum(values));
+}
+
+
+void MgFeatureNumericFunctions::GetMaximum(VECTOR &values, VECTOR &distValues)
+{
+    // TODO: Change this algorithm to take reader directly instead of vector
+
+    // find the range of the data values
+    distValues.push_back(MgFeatureUtil::Maximum(values));
+}
+
+
+void MgFeatureNumericFunctions::GetMaximum(VECTOR_INT64 &values, VECTOR_INT64 &distValues)
+{
+    // TODO: Change this algorithm to take reader directly instead of vector
+
+    // find the range of the data values
+    distValues.push_back(MgFeatureUtil::Maximum(values));
+}
+
+
+void MgFeatureNumericFunctions::CalculateDistribution(VECTOR& values, VECTOR& distValues)
+{
+    STRING funcName;
+    int numCats;
+    double dataMin, dataMax;
+    INT32 funcCode = -1;
+
+    // Get the arguments from the FdoFunction
+    STRING propertyName;
+    bool supported = MgFeatureUtil::FindCustomFunction(m_customFunction, funcCode);
+
+    if (supported)
+    {
+        switch(funcCode)
+        {
+            case EQUAL_CATEGORY: // Equal Category
+            {
+                MgFeatureUtil::GetArguments(m_customFunction, propertyName, numCats, dataMin, dataMax, m_type);
+                GetEqualCategories(values, numCats, dataMin, dataMax, distValues);
+                break;
+            }
+            case STDEV_CATEGORY: // StdDev Category
+            {
+                MgFeatureUtil::GetArguments(m_customFunction, propertyName, numCats, dataMin, dataMax, m_type);
+                GetStandardDeviationCategories(values, numCats, dataMin, dataMax, distValues);
+                break;
+            }
+            case QUANTILE_CATEGORY: // Quantile Category
+            {
+                MgFeatureUtil::GetArguments(m_customFunction, propertyName, numCats, dataMin, dataMax, m_type);
+                GetQuantileCategories(values, numCats, dataMin, dataMax, distValues);
+                break;
+            }
+            case JENK_CATEGORY: // Jenk Category
+            {
+                MgFeatureUtil::GetArguments(m_customFunction, propertyName, numCats, dataMin, dataMax, m_type);
+                GetJenksCategories(values, numCats, dataMin, dataMax, distValues);
+                break;
+            }
+            case MINIMUM:
+            {
+                GetMinimum(values,distValues);
+                break;
+            }
+            case MAXIMUM:
+            {
+                GetMaximum(values,distValues);
+                break;
+            }
+            case MEAN:
+            {
+                GetMeanValue(values,distValues);
+                break;
+            }
+            case STANDARD_DEV:
+            {
+                GetStandardDeviation(values,distValues);
+                break;
+            }
+            case UNIQUE:
+            {
+                MgUniqueFunction<double>::Execute(values, distValues);
+                break;
+            }
+        }
+    }
+}
+
+void MgFeatureNumericFunctions::CalculateDistribution(VECTOR_INT64& values, VECTOR_INT64& distValues)
+{
+    INT32 funcCode = -1;
+    // Get the arguments from the FdoFunction
+    bool supported = MgFeatureUtil::FindCustomFunction(m_customFunction, funcCode);
+
+    if (supported)
+    {
+        switch(funcCode)
+        {
+            case MINIMUM:
+            {
+                GetMinimum(values, distValues);
+                break;
+            }
+            case MAXIMUM:
+            {
+                GetMaximum(values, distValues);
+                break;
+            }
+            case UNIQUE:
+            {
+                MgUniqueFunction<INT64>::Execute(values, distValues);
+                break;
+            }
+        }
+    }
+}
+
+MgReader* MgFeatureNumericFunctions::GetReader(VECTOR& distValues)
+{
+    Ptr<MgDataReader> dataReader;
+
+    switch(m_type)
+    {
+        case MgPropertyType::Double:
+        {
+            Ptr<MgDoubleDataReaderCreator> drCreator = new MgDoubleDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::Byte:
+        {
+            Ptr<MgByteDataReaderCreator> drCreator = new MgByteDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::Int16:
+        {
+            Ptr<MgInt16DataReaderCreator> drCreator = new MgInt16DataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::Int32:
+        {
+            Ptr<MgInt32DataReaderCreator> drCreator = new MgInt32DataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::Int64:
+        {
+            Ptr<MgInt64DataReaderCreator> drCreator = new MgInt64DataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::Single:
+        {
+            Ptr<MgSingleDataReaderCreator> drCreator = new MgSingleDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::DateTime:
+        {
+            Ptr<MgDateTimeDataReaderCreator> drCreator = new MgDateTimeDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        case MgPropertyType::Boolean:
+        {
+            Ptr<MgBooleanDataReaderCreator> drCreator = new MgBooleanDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        default:
+        {
+            throw new MgInvalidPropertyTypeException(L"MgFeatureNumericFunctions.CheckSupportedPropertyType",
+                __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+    }
+    return dataReader.Detach();
+}
+
+//MgDataReader* MgFeatureNumericFunctions::GetStringReader(std::vector<STRING>& distValues)
+//{
+//    MgDoubleDataReaderCreator* drCreator = new MgDoubleDataReaderCreator(m_propertyAlias);
+//    Ptr<MgDataReader> dataReader = drCreator->Execute(distValues);
+//    delete drCreator;
+//
+//    return dataReader.Detach();
+//}
+
+// Calculate Standard Deviation for the values
+void MgFeatureNumericFunctions::GetStandardDeviationCategories( VECTOR &values, int numCats,
+                                                                double dataMin, double dataMax,
+                                                                VECTOR &distValues)
+{
+    // Expected categories should be more than zero
+    if (numCats <= 0)
+    {
+        STRING message = MgFeatureUtil::GetMessage(L"MgInvalidComputedProperty");
+
+        MgStringCollection arguments;
+        arguments.Add(message);
+        throw new MgFeatureServiceException(L"MgServerSelectFeatures.GetEqualCategories", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    // collect information about the data values
+    double min = DoubleMaxValue;
+    double max = -DoubleMaxValue;
+    double mean = 0;
+
+    int cnt = (int)values.size();
+    if (cnt <= 0) { return; } // Nothing to do, we just send back Property Definition to clients from reader
+
+    for (int i=0; i < cnt; i++)
+    {
+        double val = values[i];
+
+        if (val > max)
+            max = val;
+        if (val < min)
+            min = val;
+        mean += val;
+    }
+
+    // expand min and max a little to account for numerical instability
+    double delta = 0.0001 * (max - min);
+    min -= delta;
+    max += delta;
+
+    // compute the mean, variance and standard deviation
+    double count = (double)cnt;  // (guaranteed to be > 0)
+    mean /= count;
+    double variance = 0;
+
+    for (int i=0; i < cnt; i++)
+    {
+        double val = values[i];
+        variance += (val - mean) * (val - mean);
+    }
+
+    double deviation = sqrt(variance / count);
+
+    // fill in the middle category/categories
+    double* cats = new double[numCats+1];
+    int midCat, highMidCat;
+    if (numCats % 2 == 0)
+    {
+        midCat = numCats / 2;
+        highMidCat = midCat;
+        cats[midCat] = mean;
+    }
+    else
+    {
+        midCat = (numCats - 1) / 2;
+        highMidCat = midCat + 1;
+        cats[midCat] = mean - 0.5 * deviation;
+        cats[highMidCat] = mean + 0.5 * deviation;
+    }
+
+    // fill in the other categories
+    for (int i=midCat-1; i>=0; i--)
+        cats[i] = cats[i+1] - deviation;
+
+    for (int i=highMidCat; i<=numCats; i++)
+        cats[i] = cats[i-1] + deviation;
+
+    // if the data method specifies strict a strict min and/or max, use them
+    if (!IsInf(dataMin) && !IsNan(dataMin) && (dataMin != -DoubleMaxValue))
+        min = dataMin;
+    if (!IsInf(dataMax) && !IsNan(dataMax) && (dataMax != DoubleMaxValue))
+        max = dataMax;
+
+    // flatten/clip any categories that extend beyond the min/max range
+    for (int i=0; i<=numCats; i++)
+    {
+        if (cats[i] < min)
+            cats[i] = min;
+        else if (cats[i] > max)
+            cats[i] = max;
+    }
+
+    for (int kk = 0; kk < numCats+1; kk++)
+    {
+        distValues.push_back(cats[kk]);
+    }
+
+    delete[] cats; // Delete the memory allocated before
+}
+
+
+// Calculate Quantile Distribution for the values
+void MgFeatureNumericFunctions::GetQuantileCategories(  VECTOR &values, int numCats,
+                                                    double dataMin, double dataMax,
+                                                    VECTOR &distValues )
+{
+    // Expected categories should be more than zero
+    if (numCats <= 0)
+    {
+        STRING message = MgFeatureUtil::GetMessage(L"MgInvalidComputedProperty");
+
+        MgStringCollection arguments;
+        arguments.Add(message);
+        throw new MgFeatureServiceException(L"MgServerSelectFeatures.GetEqualCategories", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    int count = (int)values.size();
+    if (count <= 0) { return; } // Nothing to do, we just send back Property Definition to clients from reader
+
+    // Sort the data values in ascending order
+    std::sort(values.begin(), values.end());
+
+    // How many go into each full bucket?
+
+    int perBucket = ROUND((double)count/(double)numCats);
+    if (perBucket * numCats > count)
+        perBucket--;
+
+    // How many buckets are full, and how many are missing one?
+    int nearlyFullBuckets = numCats - (count - perBucket * numCats);
+    int fullBuckets = numCats - nearlyFullBuckets;
+
+    // expand min and max a little to account for numerical instability
+    double delta = 0.0001 * (values[count-1] - values[0]);
+    double* categories = new double[numCats+1];
+
+    // the first and last categories are limited by the data method limits
+    categories[0] = values[0] - delta;
+    if (categories[0] < dataMin)
+        categories[0] = dataMin;
+
+    categories[numCats] = values[count-1] + delta;
+    if (categories[numCats] > dataMax)
+        categories[numCats] = dataMax;
+
+    // Mix full and nearly-full buckets to fill in the categories between the ends.
+    int indexOfLast = -1;
+    for ( int i = 1; i<numCats; i++)
+    {
+        bool doingSmallBucket = (nearlyFullBuckets > fullBuckets);
+        // find the index of the last element we want in this bucket
+        indexOfLast += (doingSmallBucket ? perBucket : perBucket + 1);
+        // make category value be halfway between that element and the next
+        categories[i] = 0.5 * (values[indexOfLast] + values[indexOfLast+1]);
+
+        // Decrement count of correct bucket type.
+        if (doingSmallBucket)
+            nearlyFullBuckets--;
+        else
+            fullBuckets--;
+    }
+
+    for (int kk = 0; kk < numCats+1; kk++)
+    {
+        distValues.push_back(categories[kk]);
+    }
+
+    delete[] categories; // Delete the memory allocated before
+}
+
+
+bool MgFeatureNumericFunctions::IsInf(double x)
+{
+    bool isInfinity = false;
+#ifdef _WIN32
+    int code = _fpclass(x);
+    if ((code == _FPCLASS_NINF) || (code == _FPCLASS_PINF))
+    {
+        isInfinity = true;
+    }
+#else
+    isInfinity = isinf(x);
+#endif
+
+    return isInfinity;
+}
+
+bool MgFeatureNumericFunctions::IsNan(double x)
+{
+    bool isNan = false;
+#ifdef _WIN32
+    isNan = _isnan(x);
+#else
+    isNan = isnan(x);
+#endif
+    return isNan;
+}
+
+// Calculate Standard Deviation for the values
+void MgFeatureNumericFunctions::GetStandardDeviation(VECTOR &values, VECTOR &distValues)
+{
+    double mean = 0;
+
+    int cnt = (int)values.size();
+    if (cnt <= 0) { return; } // Nothing to do, we just send back Property Definition to clients from reader
+
+    double min = DoubleMaxValue;
+    double max = -DoubleMaxValue;
+
+    for (int i=0; i < cnt; i++)
+    {
+        double val = values[i];
+
+        if (val > max)
+            max = val;
+
+        if (val < min)
+            min = val;
+
+        mean += val;
+    }
+
+    // expand min and max a little to account for numerical instability
+    double delta = 0.0001 * (max - min);
+    min -= delta;
+    max += delta;
+
+    // compute the mean, variance and standard deviation
+    double count = (double)cnt;  // (guaranteed to be > 0)
+    mean /= count;
+    double variance = 0;
+
+    for (int i=0; i < cnt; i++)
+    {
+        variance += (values[i] - mean) * (values[i] - mean);
+    }
+
+    double deviation = sqrt((double)(variance / count));
+
+    // Set the base date as min date
+    if (m_type == MgPropertyType::DateTime)
+    {
+        deviation += min;
+    }
+
+    distValues.push_back(deviation);
+
+    return;
+}
+
+// Calculate average
+void MgFeatureNumericFunctions::GetMeanValue(VECTOR &values, VECTOR &distValues)
+{
+    double mean = 0;
+
+    int cnt = (int)values.size();
+    if (cnt <= 0) { return; } // Nothing to do, we just send back Property Definition to clients from reader
+
+    for (int i=0; i < cnt; i++)
+    {
+        double val = values[i];
+        mean += val;
+    }
+
+    // compute the mean, variance and standard deviation
+    double count = (double)cnt;  // (guaranteed to be > 0)
+    mean /= count;
+
+    distValues.push_back(mean);
+
+    return;
+}
+
+// Calculate average
+void MgFeatureNumericFunctions::GetUniqueValue(VECTOR &values, VECTOR &distValues)
+{
+    MgUniqueFunction<double>::Execute(values, distValues);
+}
+
+void MgFeatureNumericFunctions::GetUniqueValue(VECTOR_INT64 &values, VECTOR_INT64 &distValues)
+{
+    MgUniqueFunction<INT64>::Execute(values, distValues);
+}
+
+//-------------------------------------------------------------------------
+// Jenks' Optimization Method
+//
+//-------------------------------------------------------------------------
+void MgFeatureNumericFunctions::GetJenksCategories(  VECTOR &inputData, int numPartsRequested,
+                                                 double dataMin, double dataMax,
+                                                 VECTOR &distValues )
+{
+    // numPartsRequested // 2 - 10; 5 is good
+    int i = 0;  // index for numObservations (may be very large)
+    int j = 0;  // index for numPartsRequested (about 4-8)
+    int k = 0;
+
+    // Sort the data values in ascending order
+    std::sort(inputData.begin(), inputData.end());
+
+    int numObservations = (int)inputData.size();  // may be very large
+    // Possible improvement: Rework the code to use normal 0 based arrays.
+    // Actually it doesn't matter much since we have to create two
+    // matrices that themselves use more memory than the local copy
+    // of inputData.
+    //
+    // In order to ease the use of original FORTRAN and the later BASIC
+    // code, I will use 1 origin arrays and copy the inputData into
+    // a local array;
+    // I'll dimension the arrays one larger than necessary and use the
+    // index values from the original code.
+    //
+    // The algorithm must calculate with floating point values.
+    // If more optimization is attempted in the future, be aware of
+    // problems with calculations using mixed numeric types.
+
+    std::vector<double> data;
+    data.push_back(0);  // dummy value at index 0
+    std::copy(inputData.begin(), inputData.end(), std::back_inserter(data));
+    // copy from parameter inputData so that data index starts from 1
+
+    // Note that the Matrix constructors initialize all values to 0.
+    // mat1 contains integer values used for indices into data
+    // mat2 contains floating point values of data and bigNum
+    MgMatrix<int>     mat1(numObservations + 1, numPartsRequested + 1);
+    MgMatrix<double>  mat2(numObservations + 1, numPartsRequested + 1);
+
+//  const double bigNum = 1e+14; // from original BASIC code;
+//  const double bigNum = std::numeric_limits<double>::max();
+    const double bigNum = DBL_MAX;   // compiler's float.h
+
+    for (i = 1; i <= numPartsRequested; ++i)
+    {
+        mat1.Set(1, i, 1);
+        for (j = 2; j <= numObservations; ++j)
+        {
+            mat2.Set(j, i, bigNum);
+        }
+    }
+
+    std::vector<int> classBounds;
+    classBounds.push_back(-2);  // dummy value
+    for (i = 1; i <= numPartsRequested; ++i)
+    {
+        classBounds.push_back(-1);
+    }
+
+    for (int L = 2; L <= numObservations; ++L)
+    {
+        double s1 = 0;
+        double s2 = 0;
+        double v = 0;
+        int w = 0;
+
+        for (int m = 1; m <= L; ++m)
+        {
+            int i3 = L - m + 1;
+            double val = data[i3];
+            s2 += (double(val) * double(val));
+            // if datatype of val is ever allowed to be same as template
+            // parameter T, make sure multiplication is done in double.
+            s1 += val;
+            ++w;
+            v = s2 - ((s1 * s1) / w);
+            int i4 = i3 - 1;
+
+            if (i4 > 0)
+            {
+                for (j = 2; j <= numPartsRequested; ++j)
+                {
+                    double tempnum = v + mat2.Get(i4, j - 1);
+                    if (double(mat2.Get(L, j)) >= tempnum)
+                    {
+                        mat1.Set(L, j, i3);
+                        mat2.Set(L, j, tempnum);
+                    }
+                }
+            }
+        }
+
+        mat1.Set(L, 1, 1);
+        mat2.Set(L, 1, v);
+    }
+
+    k = numObservations;
+    for (j = numPartsRequested; j >= 1; --j)
+    {
+        if (k >= 0 && k <= numObservations)
+        {
+            classBounds[j] = mat1.Get(k, j);
+            k = mat1.Get(k, j) - 1;
+        }
+    }
+
+    std::vector<int> indices;
+
+    indices.push_back(0);
+    for (i = 2; i <= numPartsRequested; ++i)
+    {
+        int index = classBounds[i] - 1;
+        if (index > indices.back())
+        {
+            indices.push_back(index);
+        }
+    }
+
+    FixGroups(inputData, indices);
+
+    double val = 0.0;
+    int index = 0;
+    int totIndex = (int)indices.size();
+
+    for (int i = 1; i < totIndex; ++i)
+    {
+        index = indices[i] - 1;
+
+        val = inputData[index];
+        distValues.push_back(val);
+    }
+
+    index = numObservations - 1;
+    val = inputData[index];
+    distValues.push_back(val);
+
+    int retCnt = (int)distValues.size();
+    int inCnt = (int)inputData.size();
+
+    if (retCnt > 0 && inCnt > 0)
+    {
+        if (!doubles_equal(distValues[0],inputData[0]))
+        {
+            distValues.insert(distValues.begin(), inputData[0]);
+        }
+    }
+
+    return;
+}
+
+//-----------------------------------------------------------------------------
+// FixGroups
+// If the algorithm generated empty groups, then adjust the number of groups
+// and the indices.
+// Return true if adjustments we made;
+// Return false if no changes were made.
+bool MgFeatureNumericFunctions::FixGroups(const std::vector<double>& data, std::vector<int>& indices)
+{
+    bool changed1 = FixDuplicateIndices(indices);
+    bool changed2 = FixIndicesByValue(data, indices);
+
+    return changed1 || changed2;
+}
+
+
+//-----------------------------------------------------------------------------
+bool MgFeatureNumericFunctions::FixDuplicateIndices(std::vector<int>& indices)
+{
+    if (indices.size() <= 1)
+    {
+        return false;
+    }
+
+    // We will create a new vector of indices that is possibly adjusted,
+    // then replace the original vector with the new.  Since these vectors
+    // have typically less than 10 entries, we won't deal with making the
+    // adjustments in place.
+    std::vector<int> newIndices;
+
+    newIndices.push_back(indices[0]);
+
+    for (unsigned int i = 1; i < indices.size(); ++i)
+    {
+        if (indices[i] != indices[i - 1])
+            newIndices.push_back(indices[i]);
+    }
+
+    bool changed = (newIndices.size() != indices.size());
+    indices.clear();
+    indices = newIndices;
+
+    return changed;
+}
+
+
+//-----------------------------------------------------------------------------
+// Examine the values specified by the indices.  If any of the values
+// are identical, then toss out the higher index.
+bool MgFeatureNumericFunctions::FixIndicesByValue(const std::vector<double>& data, std::vector<int>& indices)
+{
+    if (indices.size() <= 1)
+    {
+        return false;
+    }
+
+    // We will create a new vector of indices that is possibly adjusted,
+    // then replace the original vector with the new.  Since these vectors
+    // have typically less than 10 entries, we won't deal with making the
+    // adjustments in place.
+    std::vector<int> newIndices;
+
+    newIndices.push_back(indices[0]);
+
+    for (unsigned int i = 1; i < indices.size(); ++i)
+    {
+        if ( ! doubles_equal(data[indices[i]], data[indices[i - 1]]) )
+            newIndices.push_back(indices[i]);
+    }
+
+    bool changed = (newIndices.size() != indices.size());
+    indices.clear();
+    indices = newIndices;
+
+    return changed;
+}
+
+bool MgFeatureNumericFunctions::doubles_equal(double d1, double d2)
+{
+    // We are doing our comparisons with a specific precision.
+    const double epsilon = 1.0e-12;  // very small
+    double d = fabs(d2 - d1);
+    return (d < epsilon);  // absolute value of difference less than tolerance
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureNumericFunctions.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,92 @@
+//
+//  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_FEATURE_NUMERIC_FUNCTIONS_H_
+#define MG_FEATURE_NUMERIC_FUNCTIONS_H_
+
+class MgDisposable;
+class FdoFunction;
+class MgReader;
+class MgFeatureDistribution;
+
+class MgFeatureNumericFunctions : public MgFeatureDistribution
+{
+    DECLARE_CLASSNAME(MgFeatureNumericFunctions)
+
+public:
+
+    MgFeatureNumericFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+    virtual ~MgFeatureNumericFunctions();
+    virtual MgReader* Execute();
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+protected:
+
+    MgFeatureNumericFunctions();
+
+private:
+
+    void Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+
+    void CalculateDistribution(VECTOR& values, VECTOR& distValues);
+    // do not call this method for other functions than MINIMUM, MAXIMUM, UNIQUE
+    void CalculateDistribution(VECTOR_INT64& values, VECTOR_INT64& distValues);
+    MgReader* GetReader(VECTOR& distValues);
+
+
+    // Distribution methods
+    void GetEqualCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues);
+    void GetStandardDeviationCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues);
+    void GetQuantileCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues );
+
+    // Jenk methods
+    void GetJenksCategories(VECTOR &inputData, int numPartsRequested, double dataMin, double dataMax, VECTOR &distValues);
+    bool FixGroups(const std::vector<double>& data, std::vector<int>& indices);
+    bool FixDuplicateIndices(std::vector<int>& indices);
+    bool FixIndicesByValue(const std::vector<double>& data, std::vector<int>& indices);
+    bool doubles_equal(double d1, double d2);
+
+    // Single row methods
+    void GetMeanValue(VECTOR &values, VECTOR &distValues);
+    void GetStandardDeviation(VECTOR &values, VECTOR &distValues);
+    void GetUniqueValue(VECTOR &values, VECTOR &distValues);
+    void GetUniqueValue(VECTOR_INT64 &values, VECTOR_INT64 &distValues);
+    void GetMinimum(VECTOR &values, VECTOR &distValues);
+    void GetMinimum(VECTOR_INT64 &values, VECTOR_INT64 &distValues);
+    void GetMaximum(VECTOR &values, VECTOR &distValues);
+    void GetMaximum(VECTOR_INT64 &values, VECTOR_INT64 &distValues);
+
+    // Utility methods
+    bool IsInf(double x);
+    bool IsNan(double x);
+
+    void CheckSupportedPropertyType();
+    double GetValue();
+
+private:
+
+    STRING m_propertyName;
+    INT16 m_type;
+    Ptr<MgReader> m_reader;
+    FdoPtr<FdoFunction> m_customFunction;
+    STRING m_propertyAlias;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,216 @@
+//
+//  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"
+#include "FeatureDefs.h"
+#include "FeatureUtil.h"
+#include "FeatureDistribution.h"
+#include "FeatureStringFunctions.h"
+#include "DataReaderCreator.h"
+#include "StringDataReaderCreator.h"
+#include <algorithm>
+#include "UniqueFunction.h"
+
+MgFeatureStringFunctions::MgFeatureStringFunctions()
+{
+    m_type = MgPropertyType::Null;
+    m_reader = NULL;
+    m_customFunction = NULL;
+    m_propertyAlias = L"";
+}
+
+MgFeatureStringFunctions::MgFeatureStringFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    Initialize(reader, customFunction, propertyAlias); // Initialize the instance
+}
+
+void MgFeatureStringFunctions::Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias)
+{
+    CHECKNULL((MgReader*)reader, L"MgFeatureStringFunctions.Initialize");
+    CHECKNULL((FdoFunction*)customFunction, L"MgFeatureStringFunctions.Initialize");
+
+    if(1 == reader->GetPropertyCount())
+    {
+        m_type = MgFeatureUtil::GetPropertyDefinition(reader, m_propertyName);
+    }
+    else
+    {
+        // Only get the property needed
+        FdoPtr<FdoExpressionCollection> exprCol = customFunction->GetArguments();
+        FdoInt32 cnt = exprCol->GetCount();
+        FdoPtr<FdoExpression> expr;
+        if(cnt == 1)
+        {
+            expr = exprCol->GetItem(0);
+            FdoIdentifier* propName = dynamic_cast<FdoIdentifier*>(expr.p);
+            CHECKNULL(propName, L"MgFeatureStringFunctions.Initialize");
+            m_propertyName = propName->GetName();
+            m_type = reader->GetPropertyType(m_propertyName);
+        }
+        else
+        {
+            // Throw original exception
+            m_type = MgFeatureUtil::GetPropertyDefinition(reader, m_propertyName);
+        }
+    }
+
+    // TODO: Should we really check this, may be we can ignore ??
+    // because we can only come to here if property type is numeric
+	if (!this->CheckSupportedPropertyType()) 
+	{
+		throw new MgInvalidPropertyTypeException(
+            L"MgFeatureStringFunctions.Initialize", __LINE__, __WFILE__, NULL, L"", NULL);
+	}
+    // We must have an property alias
+    // Though we can name a property with same name as function expression
+    // But Fdo forces to have an alias. Therefore we implement this restriction.
+    if (propertyAlias.empty())
+    {
+        STRING message = MgFeatureUtil::GetMessage(L"MgMissingPropertyAlias");
+
+        MgStringCollection arguments;
+        arguments.Add(message);
+        throw new MgFeatureServiceException(L"MgFeatureStringFunctions.Initialize", __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    m_reader = SAFE_ADDREF(reader);
+    m_customFunction = FDO_SAFE_ADDREF(customFunction);
+    m_propertyAlias = propertyAlias;
+}
+
+
+MgFeatureStringFunctions::~MgFeatureStringFunctions()
+{
+}
+
+// Execute the function
+MgReader* MgFeatureStringFunctions::Execute()
+{
+    CHECKNULL((MgReader*)m_reader, L"MgFeatureStringFunctions.Execute");
+    CHECKNULL(m_customFunction, L"MgFeatureStringFunctions.Execute");
+
+    std::vector<STRING> v2;
+
+    MG_LOG_TRACE_ENTRY(L"MgFeatureStringFunctions::Execute");
+    // TODO: Should we put a limit on double buffer
+
+    std::map<STRING, char> mMap;
+    typedef std::pair<STRING, char> String_Pair;
+
+    while(m_reader->ReadNext())
+    {
+        STRING val = L"";
+
+        // Get the value
+        GetValue(val);
+
+        // Insert the value into the std::map
+        mMap.insert( String_Pair(val, '7') );  // 7 is just arbitrary placeholder
+    }
+
+    // Execute the operation on the collected values
+    ExecuteOperation(mMap, v2);
+
+    // Create FeatureReader from distribution values
+    return GetReader(v2);
+}
+
+
+// Check whether property type is a supported type
+bool MgFeatureStringFunctions::CheckSupportedPropertyType()
+{
+    return (MgPropertyType::String == m_type);
+}
+
+
+// Get the value of property
+void MgFeatureStringFunctions::GetValue(REFSTRING val)
+{
+    if (!m_reader->IsNull(m_propertyName))
+    {
+        switch(m_type)
+        {
+            case MgPropertyType::String:
+            {
+                val = m_reader->GetString(m_propertyName);
+                break;
+            }
+            default:
+            {
+                throw new MgInvalidPropertyTypeException(
+                    L"MgFeatureStringFunctions.GetValue", __LINE__, __WFILE__, NULL, L"", NULL);
+            }
+        }
+    }
+}
+
+
+// Execute the function
+void MgFeatureStringFunctions::ExecuteOperation(std::map<STRING, char>& values, std::vector<STRING>& distValues)
+{
+   INT32 funcCode = -1;
+
+    // Get the arguments from the FdoFunction
+    STRING propertyName;
+    bool supported = MgFeatureUtil::FindCustomFunction(m_customFunction, funcCode);
+
+    if (supported)
+    {
+        switch(funcCode)
+        {
+            case UNIQUE:
+            {
+                distValues.reserve(values.size());
+                std::map<STRING, char>::iterator iter2;
+                for (iter2 = values.begin(); iter2 != values.end(); iter2++)
+                    distValues.push_back(iter2->first);
+                break;
+            }
+            default:
+            {
+                STRING message = MgFeatureUtil::GetMessage(L"MgCustomFunctionNotSupported");
+
+                MgStringCollection arguments;
+                arguments.Add(message);
+                throw new MgFeatureServiceException(
+                    L"MgServerSelectFeatures.ExecuteOperation", __LINE__, __WFILE__, &arguments, L"", NULL);
+            }
+        }
+    }
+}
+
+// Create the reader for string properties
+MgReader* MgFeatureStringFunctions::GetReader(std::vector<STRING>& distValues)
+{
+    Ptr<MgDataReader> dataReader;
+
+    switch(m_type)
+    {
+        case MgPropertyType::String:
+        {
+            Ptr<MgStringDataReaderCreator> drCreator = new MgStringDataReaderCreator(m_propertyAlias);
+            dataReader = drCreator->Execute(distValues);
+            break;
+        }
+        default:
+        {
+            throw new MgInvalidPropertyTypeException(
+                L"MgFeatureStringFunctions.GetReader", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+    }
+    return dataReader.Detach();
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeatureStringFunctions.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,68 @@
+//
+//  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_FEATURE_STRING_FUNCTIONS_H_
+#define MG_FEATURE_STRING_FUNCTIONS_H_
+
+class MgDisposable;
+class FdoFunction;
+class MgReader;
+class MgFeatureDistribution;
+
+class MgFeatureStringFunctions : public MgFeatureDistribution
+{
+    DECLARE_CLASSNAME(MgFeatureStringFunctions)
+
+public:
+
+    MgFeatureStringFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+    virtual MgReader* Execute();
+
+protected:
+
+    MgFeatureStringFunctions();
+    virtual ~MgFeatureStringFunctions();
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+private:
+
+    void GetValue(REFSTRING val);
+    void Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+
+    void ExecuteOperation(std::map<STRING, char>& values, std::vector<STRING>& distValues);
+    MgReader* GetReader(std::vector<STRING>& distValues);
+
+	//WTF: The original method was void and threw MgInvalidPropertyTypeException if not supported
+	//MSVC 2008 blows up on the linker phase with a combination of C1001 at this method and LNK1000
+	//
+	//Changing this method to return bool (supported = true) and throwing MgInvalidPropertyTypeException in
+	//the method that calls this (Initialize()) makes the problem go away. Real WTF there!
+    bool CheckSupportedPropertyType();
+
+private:
+
+    STRING m_propertyName;
+    INT16 m_type;
+    Ptr<MgReader> m_reader;
+    FdoPtr<FdoFunction> m_customFunction;
+    STRING m_propertyAlias;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeautreNumericFunctions.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeautreNumericFunctions.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/FeautreNumericFunctions.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,92 @@
+//
+//  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_FEATURE_NUMERIC_FUNCTIONS_H_
+#define MG_FEATURE_NUMERIC_FUNCTIONS_H_
+
+class MgDisposable;
+class FdoFunction;
+class MgReader;
+class MgFeatureDistribution;
+
+class MgFeatureNumericFunctions : public MgFeatureDistribution
+{
+    DECLARE_CLASSNAME(MgFeatureNumericFunctions)
+
+public:
+
+    MgFeatureNumericFunctions(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+    virtual ~MgFeatureNumericFunctions();
+    virtual MgReader* Execute();
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+protected:
+
+    MgFeatureNumericFunctions();
+
+private:
+
+    void Initialize(MgReader* reader, FdoFunction* customFunction, CREFSTRING propertyAlias);
+
+    void CalculateDistribution(VECTOR& values, VECTOR& distValues);
+    // do not call this method for other functions than MINIMUM, MAXIMUM, UNIQUE
+    void CalculateDistribution(VECTOR_INT64& values, VECTOR_INT64& distValues);
+    MgReader* GetReader(VECTOR& distValues);
+
+
+    // Distribution methods
+    void GetEqualCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues);
+    void GetStandardDeviationCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues);
+    void GetQuantileCategories(VECTOR &values, int numCats, double dataMin, double dataMax, VECTOR &distValues );
+
+    // Jenk methods
+    void GetJenksCategories(VECTOR &inputData, int numPartsRequested, double dataMin, double dataMax, VECTOR &distValues);
+    bool FixGroups(const std::vector<double>& data, std::vector<int>& indices);
+    bool FixDuplicateIndices(std::vector<int>& indices);
+    bool FixIndicesByValue(const std::vector<double>& data, std::vector<int>& indices);
+    bool doubles_equal(double d1, double d2);
+
+    // Single row methods
+    void GetMeanValue(VECTOR &values, VECTOR &distValues);
+    void GetStandardDeviation(VECTOR &values, VECTOR &distValues);
+    void GetUniqueValue(VECTOR &values, VECTOR &distValues);
+    void GetUniqueValue(VECTOR_INT64 &values, VECTOR_INT64 &distValues);
+    void GetMinimum(VECTOR &values, VECTOR &distValues);
+    void GetMinimum(VECTOR_INT64 &values, VECTOR_INT64 &distValues);
+    void GetMaximum(VECTOR &values, VECTOR &distValues);
+    void GetMaximum(VECTOR_INT64 &values, VECTOR_INT64 &distValues);
+
+    // Utility methods
+    bool IsInf(double x);
+    bool IsNan(double x);
+
+    void CheckSupportedPropertyType();
+    double GetValue();
+
+private:
+
+    STRING m_propertyName;
+    INT16 m_type;
+    Ptr<MgReader> m_reader;
+    FdoPtr<FdoFunction> m_customFunction;
+    STRING m_propertyAlias;
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GeometryDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GeometryDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/GeometryDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,61 @@
+//
+//  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_GEOMETRY_DATA_READER_CREATOR_H
+#define MG_GEOMETRY_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgGeometryDataReaderCreator : public MgDataReaderCreator<MgGeometry*>
+{
+    DECLARE_CLASSNAME(MgGeometryDataReaderCreator)
+
+public:
+    MgGeometryDataReaderCreator()
+    {
+    }
+
+    MgGeometryDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Geometry;
+    }
+
+    ~MgGeometryDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(MgGeometry* val)
+    {
+        // Convert Geometry to AGF
+        MgAgfReaderWriter agfWriter;
+        Ptr<MgByteReader> reader = agfWriter.Write(val);
+
+        // Create Geometry property
+        return new MgGeometryProperty(m_propertyAlias, reader);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int16DataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int16DataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int16DataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_INT16_DATA_READER_CREATOR_H
+#define MG_INT16_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgInt16DataReaderCreator : public MgDataReaderCreator<INT16>
+{
+    DECLARE_CLASSNAME(MgInt16DataReaderCreator)
+
+public:
+    MgInt16DataReaderCreator()
+    {
+    }
+
+    MgInt16DataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Int16;
+    }
+
+    ~MgInt16DataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(INT16 val)
+    {
+        return new MgInt16Property(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int32DataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int32DataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int32DataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_INT32_DATA_READER_CREATOR_H
+#define MG_INT32_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgInt32DataReaderCreator : public MgDataReaderCreator<INT32>
+{
+    DECLARE_CLASSNAME(MgInt32DataReaderCreator)
+
+public:
+    MgInt32DataReaderCreator()
+    {
+    }
+
+    MgInt32DataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Int32;
+    }
+
+    ~MgInt32DataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(INT32 val)
+    {
+        return new MgInt32Property(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int64DataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int64DataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Int64DataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_INT64_DATA_READER_CREATOR_H
+#define MG_INT64_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgInt64DataReaderCreator : public MgDataReaderCreator<INT64>
+{
+    DECLARE_CLASSNAME(MgInt64DataReaderCreator)
+
+public:
+    MgInt64DataReaderCreator()
+    {
+    }
+
+    MgInt64DataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Int64;
+    }
+
+    ~MgInt64DataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(INT64 val)
+    {
+        return new MgInt64Property(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Matrix.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Matrix.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/Matrix.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,104 @@
+//
+//  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_MATRIX_H
+#define MG_MATRIX_H
+
+#include <assert.h>
+#include <iostream>
+
+//=============================================================================
+//  This matrix template is designed to be used with built-in arithmetic types.
+//  It is of fixed size; it is constructed with one memory allocation.
+template <typename T>
+class MgMatrix
+{
+    public:
+        MgMatrix(int dim1, int dim2)
+        {
+            assert(dim1 > 0);
+            assert(dim2 > 0);
+            m_dim1 = dim1;
+            m_dim2 = dim2;
+            m_pData = new T [ dim1 * dim2 ];
+            assert(m_pData);
+            Clear();
+        }
+
+        ~MgMatrix()
+        {
+            delete [] m_pData;
+        }
+
+        void Set(int i, int j, T val)
+        {
+            *Ptr(i, j) = val;
+        }
+
+        T Get(int i, int j)
+        {
+            return *Ptr(i, j);
+        }
+
+        void Clear()
+        {
+            int bytes = sizeof(T) * m_dim1 * m_dim2;
+            memset(m_pData, 0, bytes);
+        }
+
+        void Fill(T val)
+        {
+            for (T* p = &m_pData[0]; p < (m_pData + (m_dim1 * m_dim2)); ++p)
+            {
+                *p = val;
+            }
+        }
+
+        void Dump(std::ostream& o)
+        {
+            for (int i = 0; i < m_dim1; ++i)
+            {
+                for (int j = 0; j < m_dim2; ++j)
+                {
+                    T d = Get(i, j);
+                    o << /*NOXLATE*/"matrix(" << i <<
+                      /*NOXLATE*/", " << j <<
+                      /*NOXLATE*/") = " << d <<
+                      /*NOXLATE*/"\n";
+                }
+            }
+        }
+
+    private:
+        T* Ptr(int i , int j)
+        {
+            // I've had some strange experiences with complex asserts inside
+            // template classes, so I'm doing each test individually.
+            assert(i >= 0);
+            assert(i < m_dim1);
+            assert(j >= 0);
+            assert(j < m_dim2);
+            return &m_pData[(i * m_dim2) + j];
+        }
+
+    private:
+        T*  m_pData;
+        int m_dim1;
+        int m_dim2;
+};
+
+#endif  // DM_MATRIX_H

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.cpp	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,885 @@
+//
+//  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 "ProxyDataReader.h"
+
+MG_IMPL_DYNCREATE(MgProxyDataReader);
+
+//////////////////////////////////////////////////////////////////
+///<summary>
+/// Construct an uninitialized MgProxyDataReader object
+///</summary>
+///
+MgProxyDataReader::MgProxyDataReader()
+{
+    m_currRecord = 0;
+    m_serverDataReader = L"";
+    m_service = NULL;
+    m_set = NULL;
+    m_propDefCol = NULL;
+}
+
+MgProxyDataReader::MgProxyDataReader(MgBatchPropertyCollection* batchCol, MgPropertyDefinitionCollection* propDefCol)
+{
+    m_currRecord = 0;
+    m_serverDataReader = L"";
+    m_service = NULL;
+    m_set = SAFE_ADDREF(batchCol);
+    m_propDefCol = SAFE_ADDREF(propDefCol);
+}
+
+//////////////////////////////////////////////////////////////////
+///<summary>
+/// Destruct a MgProxyDataReader object
+///</summary>
+///
+MgProxyDataReader::~MgProxyDataReader()
+{
+    Close();
+    SAFE_RELEASE(m_service);
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Advances the reader to the next item and returns true if there is
+/// another object to read or false if reading is complete. The default
+/// position of the reader is prior to the first item. Thus you must
+/// call ReadNext to begin accessing any data.
+/// </summary>
+/// <returns>
+/// Returns true if there is a next item.
+/// </returns>
+bool MgProxyDataReader::ReadNext()
+{
+    CHECKNULL(m_set, L"MgProxyDataReader.ReadNext");
+
+    bool foundNextFeature = false;
+
+    INT32 cnt = m_set->GetCount();
+
+    if ( m_currRecord < cnt )
+    {
+        m_currRecord++;
+        foundNextFeature = true;
+    }
+    else
+    {
+        // Fetch next set of records from server
+        try
+        {
+            m_currRecord = 0;
+            if (m_serverDataReader != L"")
+            {
+                Ptr<MgBatchPropertyCollection> bpCol = m_service->GetDataRows(m_serverDataReader);
+
+                if ((((MgBatchPropertyCollection*)bpCol) != NULL) && (bpCol->GetCount() > 0))
+                {
+                    UpdateCurrentSet(bpCol);
+                    foundNextFeature = true;
+                    m_currRecord++;
+                }
+            }
+        }
+        catch (MgException* me)
+        {
+            SAFE_RELEASE(me);
+        }
+    }
+
+    return foundNextFeature;
+}
+
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the number of properties in the result set.
+/// </summary>
+/// <returns>Returns the number of properties.</returns>
+INT32 MgProxyDataReader::GetPropertyCount()
+{
+    CHECKNULL(m_propDefCol, L"MgProxyDataReader.GetPropertyCount");
+
+    return m_propDefCol->GetCount();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the name of the property at the given ordinal position.
+/// </summary>
+/// <param name="index">Input the position of the property.</param>
+/// <returns>Returns the property name</returns>
+STRING MgProxyDataReader::GetPropertyName(INT32 index)
+{
+    CHECKNULL(m_propDefCol, L"MgProxyDataReader.GetPropertyName");
+
+    Ptr<MgPropertyDefinition> propDef = m_propDefCol->GetItem(index);
+    return propDef->GetName();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the index of the property with the specified name.
+/// </summary>
+/// <param name="propertyName">Input the name of the property.</param>
+/// <returns>Returns the property index</returns>
+INT32 MgProxyDataReader::GetPropertyIndex(CREFSTRING propertyName)
+{
+    CHECKNULL(m_propDefCol, L"MgProxyDataReader.GetPropertyIndex");
+
+    return m_propDefCol->IndexOf(propertyName);
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the data type of the property with the specified name.
+/// </summary>
+/// <param name="propertyName">Input the property name.</param>
+/// <returns>Returns the type of the property.</returns>
+INT32 MgProxyDataReader::GetPropertyType(CREFSTRING propertyName)
+{
+    CHECKNULL(m_propDefCol, L"MgProxyDataReader.GetPropertyType");
+
+    Ptr<MgPropertyDefinition> propDef = m_propDefCol->GetItem(propertyName);
+    CHECKNULL((MgPropertyDefinition*)propDef, L"MgProxyDataReader.GetPropertyType");
+
+    return propDef->GetPropertyType();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the data type of the property at the specified index.
+/// </summary>
+/// <param name="index">Input the property index.</param>
+/// <returns>Returns the type of the property.</returns>
+INT32 MgProxyDataReader::GetPropertyType(INT32 index)
+{
+    CHECKNULL(m_propDefCol, L"MgProxyDataReader.GetPropertyType");
+
+    Ptr<MgPropertyDefinition> propDef = m_propDefCol->GetItem(index);
+    CHECKNULL((MgPropertyDefinition*)propDef, L"MgProxyDataReader.GetPropertyType");
+
+    return propDef->GetPropertyType();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+///  Returns true if the value of the specified property is null.
+/// </summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns true if the value is null.</returns>
+bool MgProxyDataReader::IsNull(CREFSTRING propertyName)
+{
+    bool isNull = false;
+
+    Ptr<MgNullableProperty> ptrProp = (MgNullableProperty*)GetProperty(propertyName);
+
+    if (ptrProp != NULL)
+    {
+        isNull = ptrProp->IsNull();
+    }
+
+    return isNull;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+///  Returns true if the value of the specified property is null.
+/// </summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns true if the value is null.</returns>
+bool MgProxyDataReader::IsNull(INT32 index)
+{
+    bool isNull = false;
+
+    Ptr<MgNullableProperty> ptrProp = (MgNullableProperty*)GetProperty(index);
+
+    if (ptrProp != NULL)
+    {
+        isNull = ptrProp->IsNull();
+    }
+
+    return isNull;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Boolean value of the specified property. No conversion is
+/// performed, thus the property must be a of boolean type the result
+/// is undertermined</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the Boolean value.</returns>
+bool MgProxyDataReader::GetBoolean(CREFSTRING propertyName)
+{
+    bool retVal = false;
+
+    Ptr<MgBooleanProperty> ptrProp = (MgBooleanProperty*)GetProperty(propertyName, MgPropertyType::Boolean);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Boolean value of the specified property. No conversion is
+/// performed, thus the property must be a of boolean type the result
+/// is undertermined</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the Boolean value.</returns>
+bool MgProxyDataReader::GetBoolean(INT32 index)
+{
+    bool retVal = false;
+
+    Ptr<MgBooleanProperty> ptrProp = (MgBooleanProperty*)GetProperty(index, MgPropertyType::Boolean);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Byte value of the specified property. No conversion is
+/// performed, thus the property must be a of byte type or the result
+/// is undertermined</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the Byte value.</returns>
+BYTE MgProxyDataReader::GetByte(CREFSTRING propertyName)
+{
+    BYTE retVal = 0;
+
+    Ptr<MgByteProperty> ptrProp = (MgByteProperty*)GetProperty(propertyName, MgPropertyType::Byte);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Byte value of the specified property. No conversion is
+/// performed, thus the property must be a of byte type or the result
+/// is undertermined</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the Byte value.</returns>
+BYTE MgProxyDataReader::GetByte(INT32 index)
+{
+    BYTE retVal = 0;
+
+    Ptr<MgByteProperty> ptrProp = (MgByteProperty*)GetProperty(index, MgPropertyType::Byte);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the DTime value of the specified property. No conversion is
+/// performed, thus the property must be a of date type or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the DTime value.</returns>
+MgDateTime* MgProxyDataReader::GetDateTime(CREFSTRING propertyName)
+{
+    Ptr<MgDateTimeProperty> ptrProp = (MgDateTimeProperty*)GetProperty(propertyName, MgPropertyType::DateTime);
+    Ptr<MgDateTime> retVal = ptrProp->GetValue();
+
+    return SAFE_ADDREF((MgDateTime*)retVal);
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the DTime value of the specified property. No conversion is
+/// performed, thus the property must be a of date type or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the DTime value.</returns>
+MgDateTime* MgProxyDataReader::GetDateTime(INT32 index)
+{
+    Ptr<MgDateTimeProperty> ptrProp = (MgDateTimeProperty*)GetProperty(index, MgPropertyType::DateTime);
+    Ptr<MgDateTime> retVal = ptrProp->GetValue();
+
+    return SAFE_ADDREF((MgDateTime*)retVal);
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Single value of the specified property. No conversion is
+/// performed, thus the property must be a of type single or the result
+/// is undetermined</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the single value.</returns>
+float MgProxyDataReader::GetSingle(CREFSTRING propertyName)
+{
+    float retVal = 0;
+
+    Ptr<MgSingleProperty> ptrProp = (MgSingleProperty*)GetProperty(propertyName, MgPropertyType::Single);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Single value of the specified property. No conversion is
+/// performed, thus the property must be a of type single or the result
+/// is undetermined</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the single value.</returns>
+float MgProxyDataReader::GetSingle(INT32 index)
+{
+    float retVal = 0;
+
+    Ptr<MgSingleProperty> ptrProp = (MgSingleProperty*)GetProperty(index, MgPropertyType::Single);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Double value of the specified property. No conversion is
+/// performed, thus the property must be a of type double or the result
+/// is undetermined</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the double value.</returns>
+double MgProxyDataReader::GetDouble(CREFSTRING propertyName)
+{
+    double retVal = 0;
+
+    Ptr<MgDoubleProperty> ptrProp = (MgDoubleProperty*)GetProperty(propertyName, MgPropertyType::Double);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Double value of the specified property. No conversion is
+/// performed, thus the property must be a of type double or the result
+/// is undetermined</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the double value.</returns>
+double MgProxyDataReader::GetDouble(INT32 index)
+{
+    double retVal = 0;
+
+    Ptr<MgDoubleProperty> ptrProp = (MgDoubleProperty*)GetProperty(index, MgPropertyType::Double);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the integer 16 bits value of the specified property. No conversion is
+/// performed, thus the property must be a of type integer 16 bits or the result
+/// is undetermined</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the integer 16 bits value.</returns>
+INT16 MgProxyDataReader::GetInt16(CREFSTRING propertyName)
+{
+    INT16 retVal = 0;
+
+    Ptr<MgInt16Property> ptrProp = (MgInt16Property*)GetProperty(propertyName, MgPropertyType::Int16);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the integer 16 bits value of the specified property. No conversion is
+/// performed, thus the property must be a of type integer 16 bits or the result
+/// is undetermined</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the integer 16 bits value.</returns>
+INT16 MgProxyDataReader::GetInt16(INT32 index)
+{
+    INT16 retVal = 0;
+
+    Ptr<MgInt16Property> ptrProp = (MgInt16Property*)GetProperty(index, MgPropertyType::Int16);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the integer 32 bits value of the specified property. No conversion is
+/// performed, thus the property must be a of type integer 32 bits or the result
+/// is undetermined</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the integer 32 bits value.</returns>
+INT32 MgProxyDataReader::GetInt32(CREFSTRING propertyName)
+{
+    INT32 retVal = 0;
+
+    Ptr<MgInt32Property> ptrProp = (MgInt32Property*)GetProperty(propertyName, MgPropertyType::Int32);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the integer 32 bits value of the specified property. No conversion is
+/// performed, thus the property must be a of type integer 32 bits or the result
+/// is undetermined</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the integer 32 bits value.</returns>
+INT32 MgProxyDataReader::GetInt32(INT32 index)
+{
+    INT32 retVal = 0;
+
+    Ptr<MgInt32Property> ptrProp = (MgInt32Property*)GetProperty(index, MgPropertyType::Int32);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the integer 64 bits value of the specified property. No conversion is
+/// performed, thus the property must be a of type integer 64 bits or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the integer 64 bits value.
+/// Note: INT64 is actually a pointer to an Integer64 object
+///</returns>
+INT64 MgProxyDataReader::GetInt64(CREFSTRING propertyName)
+{
+    INT64 retVal = 0;
+
+    Ptr<MgInt64Property> ptrProp = (MgInt64Property*)GetProperty(propertyName, MgPropertyType::Int64);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the integer 64 bits value of the specified property. No conversion is
+/// performed, thus the property must be a of type integer 64 bits or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the integer 64 bits value.
+/// Note: INT64 is actually a pointer to an Integer64 object
+///</returns>
+INT64 MgProxyDataReader::GetInt64(INT32 index)
+{
+    INT64 retVal = 0;
+
+    Ptr<MgInt64Property> ptrProp = (MgInt64Property*)GetProperty(index, MgPropertyType::Int64);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the string value of the specified property. No conversion is
+/// performed, thus the property must be a of type string or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the string value.</returns>
+STRING MgProxyDataReader::GetString(CREFSTRING propertyName)
+{
+    STRING retVal = L"";
+
+    Ptr<MgStringProperty> ptrProp = (MgStringProperty*)GetProperty(propertyName, MgPropertyType::String);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the string value of the specified property. No conversion is
+/// performed, thus the property must be a of type string or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the string value.</returns>
+STRING MgProxyDataReader::GetString(INT32 index)
+{
+    STRING retVal = L"";
+
+    Ptr<MgStringProperty> ptrProp = (MgStringProperty*)GetProperty(index, MgPropertyType::String);
+    retVal = ptrProp->GetValue();
+
+    return retVal;
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the BLOB value of the specified property. No conversion is
+/// performed, thus the property must be a of type BLOBs or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the BLOB value.</returns>
+MgByteReader* MgProxyDataReader::GetBLOB(CREFSTRING propertyName)
+{
+    Ptr<MgBlobProperty> ptrProp = (MgBlobProperty*)GetProperty(propertyName, MgPropertyType::Blob);
+    return ptrProp->GetValue();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the BLOB value of the specified property. No conversion is
+/// performed, thus the property must be a of type BLOBs or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the BLOB value.</returns>
+MgByteReader* MgProxyDataReader::GetBLOB(INT32 index)
+{
+    Ptr<MgBlobProperty> ptrProp = (MgBlobProperty*)GetProperty(index, MgPropertyType::Blob);
+    return ptrProp->GetValue();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the CLOB value of the specified property. No conversion is
+/// performed, thus the property must be a of type CLOB or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the CLOB value.</returns>
+MgByteReader* MgProxyDataReader::GetCLOB(CREFSTRING propertyName)
+{
+    Ptr<MgClobProperty> ptrProp = (MgClobProperty*)GetProperty(propertyName, MgPropertyType::Clob);
+    return ptrProp->GetValue();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the CLOB value of the specified property. No conversion is
+/// performed, thus the property must be a of type CLOB or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the CLOB value.</returns>
+MgByteReader* MgProxyDataReader::GetCLOB(INT32 index)
+{
+    Ptr<MgClobProperty> ptrProp = (MgClobProperty*)GetProperty(index, MgPropertyType::Clob);
+    return ptrProp->GetValue();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Geometry for the specified property. No conversion is
+/// performed, thus the property must be a of type Geometry or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns a ByteReader object</returns>
+MgByteReader* MgProxyDataReader::GetGeometry(CREFSTRING propertyName)
+{
+    Ptr<MgGeometryProperty> ptrProp = (MgGeometryProperty*)GetProperty(propertyName, MgPropertyType::Geometry);
+    return ptrProp->GetValue();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the Geometry for the specified property. No conversion is
+/// performed, thus the property must be a of type Geometry or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns a ByteReader object</returns>
+MgByteReader* MgProxyDataReader::GetGeometry(INT32 index)
+{
+    Ptr<MgGeometryProperty> ptrProp = (MgGeometryProperty*)GetProperty(index, MgPropertyType::Geometry);
+    return ptrProp->GetValue();
+}
+
+//////////////////////////////////////////////////////////////////
+///<summary>
+/// Serialize data to TCP/IP stream
+///</summary>
+///<param name="stream">
+/// Stream
+///</param>
+
+void MgProxyDataReader::Serialize(MgStream* stream)
+{
+    bool operationCompleted = true;
+    stream->WriteBoolean(operationCompleted);
+
+    if (operationCompleted)
+    {
+        stream->WriteString(m_serverDataReader);                        // Write the reader ID so we can retrieve it for later use
+        stream->WriteString(m_providerName);
+        stream->WriteObject(m_propDefCol);                              // Write the property definition
+        stream->WriteObject(m_set);                                     // Write the property data
+    }
+}
+
+//////////////////////////////////////////////////////////////////
+///<summary>
+/// Deserialize data from TCP/IP stream
+///</summary>
+///<param name="stream">
+/// Stream
+///</param>
+
+void MgProxyDataReader::Deserialize(MgStream* stream)
+{
+    bool operationCompleted = false;
+
+    stream->GetBoolean(operationCompleted);
+
+    if (operationCompleted)
+    {
+        stream->GetString(m_serverDataReader);                                  // Get the reader ID so we can retrieve it for later use
+        stream->GetString(m_providerName);
+        m_propDefCol = (MgPropertyDefinitionCollection*)stream->GetObject();    // Get the property definition
+        m_set = (MgBatchPropertyCollection*)stream->GetObject();                // Get the property data
+    }
+    else
+    {
+        MgException* exp = (MgException*)stream->GetObject();
+        exp->Raise();
+    }
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Serializes all features into an XML.
+/// XML is serialized from the current position of feature reader in the order
+/// data are retrieved.
+/// <returns>MgByteReader holding XML.</returns>
+MgByteReader* MgProxyDataReader::ToXml()
+{
+    string xmlStr;
+    this->ToXml(xmlStr);
+
+    Ptr<MgByteSource> byteSource = new MgByteSource((BYTE_ARRAY_IN)xmlStr.c_str(), (INT32)xmlStr.length());
+    byteSource->SetMimeType(MgMimeType::Xml);
+
+    return byteSource->GetReader();
+}
+
+void MgProxyDataReader::ToXml(string &str)
+{
+    CHECKNULL((MgBatchPropertyCollection*)m_set, L"MgProxyDataReader.ToXml");
+    CHECKNULL((MgPropertyDefinitionCollection*)m_propDefCol, L"MgProxyDataReader.ToXml");
+
+    // this XML follows the SelectAggregate-1.0.0.xsd schema
+    str += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+    str += "<PropertySet>";
+    m_propDefCol->ToXml(str);
+    str += "<Properties>";
+    while ( this->ReadNext() )
+    {
+        Ptr<MgPropertyCollection> propCol = m_set->GetItem(m_currRecord-1);
+        INT32 cnt = propCol->GetCount();
+        if (propCol != NULL && cnt > 0)
+        {
+            str += "<PropertyCollection>";
+            propCol->ToXml(str,false);
+            str += "</PropertyCollection>";
+        }
+    }
+    str += "</Properties>";
+    str += "</PropertySet>";
+}
+
+void MgProxyDataReader::SetService(MgFeatureService* service)
+{
+    CHECKNULL(service, L"MgProxyDataReader.SetService");
+
+    if (m_service == NULL)
+    {
+        m_service = SAFE_ADDREF(service);
+    }
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Releases all the resources of feature reader.
+/// This must be called when user is done with Feature Reader
+/// <returns>Nothing</returns>
+void MgProxyDataReader::Close()
+{
+    if (m_serverDataReader != L"")
+    {
+        MG_TRY()
+
+        m_service->CloseDataReader(m_serverDataReader);
+        m_serverDataReader = L"";
+
+        MG_CATCH(L"MgProxyDataReader.Close")
+
+        // We do not rethrow the exception while destructing the object. Even if we had problem
+        // disposing this feature reader, it will automatically get collected after time out.
+    }
+}
+
+
+// Get the property for the specified name
+MgProperty* MgProxyDataReader::GetProperty(CREFSTRING propertyName, INT16 expectedType)
+{
+    Ptr<MgNullableProperty> ptrProp = (MgNullableProperty*)this->GetProperty(propertyName);
+    CHECKNULL(ptrProp, L"MgProxyDataReader.GetProperty");
+
+    if (ptrProp->IsNull())
+    {
+        MgStringCollection arguments;
+        arguments.Add(propertyName);
+
+        throw new MgNullPropertyValueException(L"MgProxyDataReader.GetProperty",
+            __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    INT16 propType = ptrProp->GetPropertyType();
+    MG_CHECK_PROPERTY_TYPE(propType, expectedType, L"MgProxyDataReader.GetProperty");
+
+    return SAFE_ADDREF((MgProperty*)ptrProp);
+}
+
+// Get the property for the specified name
+MgProperty* MgProxyDataReader::GetProperty(CREFSTRING propertyName)
+{
+    CHECKNULL(m_set, L"MgProxyDataReader.GetProperty");
+    MG_CHECK_FEATURE_SET_COUNT(m_set, L"MgProxyDataReader.GetProperty");
+
+    Ptr<MgPropertyCollection> ptrCol = m_set->GetItem(m_currRecord-1);
+    CHECKNULL(ptrCol, L"MgProxyDataReader.GetProperty");
+
+    Ptr<MgProperty> ptrProp = ptrCol->GetItem(propertyName);
+    CHECKNULL(ptrProp, L"MgProxyDataReader.GetProperty");
+
+    return SAFE_ADDREF((MgProperty*)ptrProp);
+}
+
+// Get the property for the specified name
+MgProperty* MgProxyDataReader::GetProperty(INT32 index, INT16 expectedType)
+{
+    Ptr<MgNullableProperty> ptrProp = (MgNullableProperty*)this->GetProperty(index);
+    CHECKNULL(ptrProp, L"MgProxyDataReader.GetProperty");
+
+    if (ptrProp->IsNull())
+    {
+        STRING buffer;
+        MgUtil::Int32ToString(index, buffer);
+
+        MgStringCollection arguments;
+        arguments.Add(buffer);
+
+        throw new MgNullPropertyValueException(L"MgProxyDataReader.GetProperty",
+            __LINE__, __WFILE__, &arguments, L"", NULL);
+    }
+
+    INT16 propType = ptrProp->GetPropertyType();
+    MG_CHECK_PROPERTY_TYPE(propType, expectedType, L"MgProxyDataReader.GetProperty");
+
+    return SAFE_ADDREF((MgProperty*)ptrProp);
+}
+
+// Get the property for the specified index
+MgProperty* MgProxyDataReader::GetProperty(INT32 index)
+{
+    CHECKNULL(m_set, L"MgProxyDataReader.GetProperty");
+    MG_CHECK_FEATURE_SET_COUNT(m_set, L"MgProxyDataReader.GetProperty");
+
+    Ptr<MgPropertyCollection> ptrCol = m_set->GetItem(m_currRecord-1);
+    CHECKNULL(ptrCol, L"MgProxyDataReader.GetProperty");
+
+    Ptr<MgProperty> ptrProp = ptrCol->GetItem(index);
+    CHECKNULL(ptrProp, L"MgProxyDataReader.GetProperty");
+
+    return SAFE_ADDREF((MgProperty*)ptrProp);
+}
+
+void MgProxyDataReader::UpdateCurrentSet(MgBatchPropertyCollection* bpCol)
+{
+    CHECKNULL((MgBatchPropertyCollection*)m_set, L"MgProxyDataReader.UpdateCurrentSet");
+    CHECKNULL((MgBatchPropertyCollection*)bpCol, L"MgProxyDataReader.UpdateCurrentSet");
+
+    m_set->Clear();
+
+    // It is only reference copy
+    INT32 cnt = bpCol->GetCount();
+    for (INT32 i=0; i < cnt; i++)
+    {
+        Ptr<MgPropertyCollection> propCol = bpCol->GetItem(i);
+        m_set->Add(propCol);
+    }
+}
+
+/// <summary>Gets the raster object of the specified property.
+/// the property must be of Raster type; otherwise, an exception is thrown.
+/// </summary>
+/// <param name="propertyName">Input the property name.</param>
+/// <returns>Returns the raster object.</returns>
+MgRaster* MgProxyDataReader::GetRaster(CREFSTRING propertyName)
+{
+    Ptr<MgRasterProperty> ptrProp = (MgRasterProperty*)GetProperty(propertyName, MgPropertyType::Raster);
+    Ptr<MgRaster> retVal = ptrProp->GetValue();
+    retVal->SetMgService(m_service);
+    retVal->SetHandle(m_serverDataReader);
+
+    return SAFE_ADDREF((MgRaster*)retVal);
+}
+
+/// <summary>Gets the raster object of the specified property.
+/// the property must be of Raster type; otherwise, an exception is thrown.
+/// </summary>
+/// <param name="index">Input the property index.</param>
+/// <returns>Returns the raster object.</returns>
+MgRaster* MgProxyDataReader::GetRaster(INT32 index)
+{
+    Ptr<MgRasterProperty> ptrProp = (MgRasterProperty*)GetProperty(index, MgPropertyType::Raster);
+    Ptr<MgRaster> retVal = ptrProp->GetValue();
+    retVal->SetMgService(m_service);
+    retVal->SetHandle(m_serverDataReader);
+
+    return SAFE_ADDREF((MgRaster*)retVal);
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the string value of the specified property. No conversion is
+/// performed, thus the property must be a of type string or the result
+/// is NULL</summary>
+/// <param name="propertyName">Property name.</param>
+/// <returns>Returns the string value.</returns>
+const wchar_t* MgProxyDataReader::GetString(CREFSTRING propertyName, INT32& length)
+{
+    STRING str = this->GetString(propertyName);
+    length = (INT32)str.size();
+
+    return str.c_str();
+}
+
+//////////////////////////////////////////////////////////////////
+/// <summary>
+/// Gets the string value of the specified property. No conversion is
+/// performed, thus the property must be a of type string or the result
+/// is NULL</summary>
+/// <param name="index">Property index.</param>
+/// <returns>Returns the string value.</returns>
+const wchar_t* MgProxyDataReader::GetString(INT32 index, INT32& length)
+{
+    STRING str = this->GetString(index);
+    length = (INT32)str.size();
+
+    return str.c_str();
+}

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/ProxyDataReader.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,610 @@
+//
+//  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_PROXY_DATA_READER_H
+#define _MG_PROXY_DATA_READER_H
+
+#include "MgDesktop.h"
+
+class MgDataReader;
+
+class MgProxyDataReader;
+template class MG_DESKTOP_API Ptr<MgProxyDataReader>;
+
+/// \cond INTERNAL
+/////////////////////////////////////////////////////////////////
+/// \brief
+/// The SqlReader interface provides a forward-only, read-only
+/// iterator for reading relational table data.
+///
+/// \remarks
+/// The initial position of the SqlReader interface is prior to the first item.
+/// Thus, you must call ReadNext to begin accessing any data.
+class MG_DESKTOP_API  MgProxyDataReader : public MgDataReader
+{
+    MG_DECL_DYNCREATE();
+    DECLARE_CLASSNAME(MgProxyDataReader)
+
+EXTERNAL_API:
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Advances the reader to the next item and returns true if there is
+    /// another object to read or false if reading is complete. The default
+    /// position of the reader is prior to the first item. Thus you must
+    /// call ReadNext to begin accessing any data.
+    ///
+    /// \return
+    /// Returns true if there is a next item.
+    ///
+    bool ReadNext();
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the number of properties in the result set.
+    ///
+    /// \return
+    /// Returns the number of properties.
+    ///
+    INT32 GetPropertyCount();
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the name of the property at the given ordinal position.
+    ///
+    /// \param index
+    /// Input the position of the property.
+    ///
+    /// \return
+    /// Returns the property name
+    ///
+    STRING GetPropertyName(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the index of the property with the specified name.
+    ///
+    /// \param propertyName
+    /// Input the name of the property.
+    ///
+    /// \return
+    /// Returns the property index
+    ///
+    INT32 GetPropertyIndex(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the data type of the property with the specified name.
+    ///
+    /// \param propertyName
+    /// Input the property name.
+    ///
+    /// \return
+    /// Returns the type of the property.
+    ///
+    INT32 GetPropertyType(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the data type of the property at the specified index.
+    ///
+    /// \param index
+    /// Input the property index.
+    ///
+    /// \return
+    /// Returns the type of the property.
+    ///
+    INT32 GetPropertyType(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    ///  Returns true if the value of the specified property is null.
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns true if the value is null.
+    ///
+    bool IsNull(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Boolean value of the specified property. No conversion is
+    /// performed, thus the property must be a of boolean type the result
+    /// is undetermined
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the Boolean value.
+    ///
+    bool GetBoolean(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Byte value of the specified property. No conversion is
+    /// performed, thus the property must be a of byte type or the result
+    /// is undetermined
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the Byte value.
+    ///
+    BYTE GetByte(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the DTime value of the specified property. No conversion is
+    /// performed, thus the property must be a of date type or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the DTime value.
+    ///
+    MgDateTime* GetDateTime(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Single value of the specified property. No conversion is
+    /// performed, thus the property must be a of type single or the result
+    /// is undetermined
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the single value.
+    ///
+    float GetSingle(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Double value of the specified property. No conversion is
+    /// performed, thus the property must be a of type double or the result
+    /// is undetermined
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the double value.
+    ///
+    double GetDouble(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the integer 16 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 16 bits or the result
+    /// is undetermined
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the integer 16 bits value.
+    ///
+    INT16 GetInt16(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the integer 32 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 32 bits or the result
+    /// is undetermined
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the integer 32 bits value.
+    ///
+    INT32 GetInt32(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the integer 64 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 64 bits or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the integer 64 bits value.
+    /// Note: INT64 is actually a pointer to an Integer64 object
+    ///
+    INT64 GetInt64(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the string value of the specified property. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the string value.
+    ///
+    STRING GetString(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the BLOB value of the specified property. No conversion is
+    /// performed, thus the property must be a of type BLOBs or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the BLOB value.
+    ///
+    MgByteReader* GetBLOB(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the CLOB value of the specified property. No conversion is
+    /// performed, thus the property must be a of type CLOB or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the CLOB value.
+    ///
+    MgByteReader* GetCLOB(CREFSTRING propertyName);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Geometry for the specified property. No conversion is
+    /// performed, thus the property must be a of type Geometry or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns a ByteReader object
+    ///
+    MgByteReader* GetGeometry(CREFSTRING propertyName);
+
+    /// \brief
+    /// Gets the raster object of the specified property.
+    /// the property must be of Raster type; otherwise, an exception is thrown.
+    ///
+    /// \param propertyName
+    /// Input the property name.
+    ///
+    /// \return
+    /// Returns the raster object.
+    ///
+    MgRaster* GetRaster(CREFSTRING propertyName);
+
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    ///  Returns true if the value of the specified property is null.
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns true if the value is null.
+    ///
+    bool IsNull(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Boolean value of the specified property. No conversion is
+    /// performed, thus the property must be a of boolean type the result
+    /// is undetermined
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the Boolean value.
+    ///
+    bool GetBoolean(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Byte value of the specified property. No conversion is
+    /// performed, thus the property must be a of byte type or the result
+    /// is undetermined
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the Byte value.
+    ///
+    BYTE GetByte(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the DTime value of the specified property. No conversion is
+    /// performed, thus the property must be a of date type or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the DTime value.
+    ///
+    MgDateTime* GetDateTime(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Single value of the specified property. No conversion is
+    /// performed, thus the property must be a of type single or the result
+    /// is undetermined
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the single value.
+    ///
+    float GetSingle(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Double value of the specified property. No conversion is
+    /// performed, thus the property must be a of type double or the result
+    /// is undetermined
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the double value.
+    ///
+    double GetDouble(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the integer 16 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 16 bits or the result
+    /// is undetermined
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the integer 16 bits value.
+    ///
+    INT16 GetInt16(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the integer 32 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 32 bits or the result
+    /// is undetermined
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the integer 32 bits value.
+    ///
+    INT32 GetInt32(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the integer 64 bits value of the specified property. No conversion is
+    /// performed, thus the property must be a of type integer 64 bits or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the integer 64 bits value.
+    /// Note: INT64 is actually a pointer to an Integer64 object
+    ///
+    INT64 GetInt64(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the string value of the specified property. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the string value.
+    ///
+    STRING GetString(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the BLOB value of the specified property. No conversion is
+    /// performed, thus the property must be a of type BLOBs or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the BLOB value.
+    ///
+    MgByteReader* GetBLOB(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the CLOB value of the specified property. No conversion is
+    /// performed, thus the property must be a of type CLOB or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the CLOB value.
+    ///
+    MgByteReader* GetCLOB(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the Geometry for the specified property. No conversion is
+    /// performed, thus the property must be a of type Geometry or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns a ByteReader object
+    ///
+    MgByteReader* GetGeometry(INT32 index);
+
+    /// \brief
+    /// Gets the raster object of the specified property.
+    /// the property must be of Raster type; otherwise, an exception is thrown.
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the raster object.
+    ///
+    MgRaster* GetRaster(INT32 index);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Closes the FeatureReader object, freeing any resources it may be holding.
+    ///
+    void Close();
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Serializes all features into an XML.
+    /// XML is serialized from the current position of feature reader in the order
+    /// data are retrieved.
+    ///
+    /// \return
+    /// MgByteReader holding XML.
+    ///
+    MgByteReader* ToXml();
+
+INTERNAL_API:
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the string value of the specified property. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL
+    ///
+    /// \param propertyName
+    /// Property name.
+    ///
+    /// \return
+    /// Returns the string value.
+    ///
+    const wchar_t* GetString(CREFSTRING propertyName, INT32& length);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Gets the string value of the specified property. No conversion is
+    /// performed, thus the property must be a of type string or the result
+    /// is NULL
+    ///
+    /// \param index
+    /// Property index.
+    ///
+    /// \return
+    /// Returns the string value.
+    ///
+    const wchar_t* GetString(INT32 index, INT32& length);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Serialize data to TCP/IP stream
+    ///
+    /// \param stream
+    /// Stream
+    ///
+    virtual void Serialize(MgStream* stream);
+
+    //////////////////////////////////////////////////////////////////
+    /// \brief
+    /// Deserialize data from TCP/IP stream
+    ///
+    /// \param stream
+    /// Stream
+    ///
+    virtual void Deserialize(MgStream* stream);
+
+    void ToXml(string &str);
+
+    void SetService(MgFeatureService* service);
+
+    virtual INT32 GetClassId()
+    {
+        return m_cls_id;
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+
+    MgProxyDataReader(MgBatchPropertyCollection* batchCol, MgPropertyDefinitionCollection* propDefCol);
+
+    MgProxyDataReader();
+    ~MgProxyDataReader();
+
+private:
+
+    MgProperty* GetProperty(CREFSTRING propertyName, INT16 expectedType);
+    /// Get the property for the specified name
+    MgProperty* GetProperty(CREFSTRING propertyName);
+
+    MgProperty* GetProperty(INT32 index, INT16 expectedType);
+    /// Get the property for the specified index.
+    MgProperty* GetProperty(INT32 index);
+
+    void UpdateCurrentSet(MgBatchPropertyCollection* bpCol);
+
+    Ptr<MgBatchPropertyCollection> m_set;
+    Ptr<MgPropertyDefinitionCollection> m_propDefCol;
+
+    STRING m_providerName;
+    INT32 m_currRecord;
+    STRING m_serverDataReader;
+    MgFeatureService* m_service; // Do not want to implement a default constructor
+
+CLASS_ID:
+    static const INT32 m_cls_id = PlatformBase_FeatureService_DataReader;
+
+};
+/// \endcond
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/SingleDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/SingleDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/SingleDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_SINGLE_DATA_READER_CREATOR_H
+#define MG_SINGLE_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgSingleDataReaderCreator : public MgDataReaderCreator<float>
+{
+    DECLARE_CLASSNAME(MgSingleDataReaderCreator)
+
+public:
+    MgSingleDataReaderCreator()
+    {
+    }
+
+    MgSingleDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::Single;
+    }
+
+    ~MgSingleDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(float val)
+    {
+        return new MgSingleProperty(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/StringDataReaderCreator.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/StringDataReaderCreator.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/StringDataReaderCreator.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,56 @@
+//
+//  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_STRING_DATA_READER_CREATOR_H
+#define MG_STRING_DATA_READER_CREATOR_H
+
+using namespace std;
+
+#include <vector>
+
+class MgStringDataReaderCreator : public MgDataReaderCreator<STRING>
+{
+    DECLARE_CLASSNAME(MgStringDataReaderCreator)
+
+public:
+    MgStringDataReaderCreator()
+    {
+    }
+
+    MgStringDataReaderCreator(CREFSTRING propertyAlias)
+    {
+        m_propertyAlias = propertyAlias;
+        m_propType = MgPropertyType::String;
+    }
+
+    ~MgStringDataReaderCreator()
+    {
+    }
+
+    //
+    MgProperty* GetProperty(CREFSTRING val)
+    {
+        return new MgStringProperty(m_propertyAlias, val);
+    }
+
+    virtual void Dispose()
+    {
+        delete this;
+    }
+};
+
+#endif

Added: branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/UniqueFunction.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/UniqueFunction.h	                        (rev 0)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/Feature/UniqueFunction.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -0,0 +1,50 @@
+//
+//  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_UNIQUE_FUNCTION_H
+#define MG_UNIQUE_FUNCTION_H
+
+#include <vector>
+#include <map>
+using namespace std;
+
+//=============================================================================
+//  This matrix template is designed to be used with built-in arithmetic types.
+//  It is of fixed size; it is constructed with one memory allocation.
+template <typename T>
+class MgUniqueFunction
+{
+    public:
+        MgUniqueFunction() {}
+        ~MgUniqueFunction() {}
+
+        static void Execute(const std::vector<T>& in, std::vector<T>& out)
+        {
+            int cnt = (int)in.size();
+            if (cnt <= 0) { return; } // Nothing to do, we just send back Property Definition to clients from reader
+
+            std::map<T, char> mMap;
+            for (int i=0; i<cnt; i++) mMap[in[i]] = '7'; //7 is just arbitrary placeholder
+
+            out.reserve(mMap.size());
+            typename std::map<T, char>::iterator iter2;
+            for (iter2 = mMap.begin(); iter2 != mMap.end(); iter2++)
+                out.push_back(iter2->first);
+        }
+};
+
+#endif  // DM_MATRIX_H

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.cpp	2012-05-13 02:45:17 UTC (rev 6644)
@@ -18,6 +18,7 @@
 #include "DataReader.h"
 #include "SqlReader.h"
 
+#include "Services/Feature/FeatureDistribution.h"
 #include "Services/Feature/ProjectedFeatureReader.h"
 #include "Services/Feature/GwsFeatureReader.h"
 #include "Services/Feature/GwsConnectionPool.h"
@@ -3294,6 +3295,10 @@
 
         INT32 propCount = props->GetCount();
         INT32 compCount = computed->GetCount();
+		
+		bool bCustomPropertyFound = false;
+		FdoFunction* customFunc = NULL;
+		STRING customPropName;
 
         FdoPtr<FdoIdentifierCollection> fdoProps = select->GetPropertyNames();
         if (propCount > 0)
@@ -3309,10 +3314,60 @@
 	        for (INT32 i = 0; i < compCount; i++)
 	        {
 		        Ptr<MgStringProperty> comp = computed->GetItem(i);
+				STRING aliasName = comp->GetName();
 		        FdoPtr<FdoExpression> expr = FdoExpression::Parse(comp->GetValue().c_str());
-		        FdoPtr<FdoComputedIdentifier> name= FdoComputedIdentifier::Create(comp->GetName().c_str(), expr);
+		        
+				if (ContainsUdf(connWrap, expr))
+				{
+					// If property is already found, two custom properties are not supported and therefore throw exception
+					if (bCustomPropertyFound)
+					{
+						STRING message = MgFeatureUtil::GetMessage(L"MgOnlyOnePropertyAllowed");
 
-		        fdoProps->Add(name);
+						MgStringCollection arguments;
+						arguments.Add(message);
+						throw new MgFeatureServiceException(L"MgdFeatureService::SelectAggregate", __LINE__, __WFILE__, &arguments, L"", NULL);
+					}
+
+					// Downcast to FdoFunction
+					FdoFunction* function = dynamic_cast<FdoFunction*>(expr.p);
+
+					if (function != NULL)
+					{
+						FdoString* expName = aliasName.c_str();
+						if (expName != NULL)
+						{
+							FdoPtr<FdoExpressionCollection> exprCol = function->GetArguments();
+							FdoInt32 cnt = exprCol->GetCount();
+							FdoPtr<FdoExpression> expr;
+							if (cnt > 0)
+							{
+								expr = exprCol->GetItem(0);   // Property Name
+							}
+
+							// Just pass in the property name
+							// FdoPtr<FdoComputedIdentifier> fdoIden = FdoComputedIdentifier::Create(expName, expr);
+
+							// NOTE: Each provider has its own rule for supporting computed properties, select and select aggregate
+							// functionality. Therefore we just work with simple select command, fetch the property and do the needed
+							// calculations. Therefore, we are not adding them as computed properties.
+
+							FdoIdentifier* propName = dynamic_cast<FdoIdentifier*>(expr.p);
+
+							if (propName != NULL)
+								fdoProps->Add(propName);
+
+							customPropName = aliasName;
+							bCustomPropertyFound = true;
+							customFunc = FDO_SAFE_ADDREF(function);
+						}
+					}
+				}
+				else
+				{
+					FdoPtr<FdoComputedIdentifier> name = FdoComputedIdentifier::Create(comp->GetName().c_str(), expr);
+					fdoProps->Add(name);
+				}
 	        }
         }
 
@@ -3339,7 +3394,17 @@
         }
 
         FdoPtr<FdoIDataReader> fdoReader = select->Execute();
-        reader = new MgdDataReader(connWrap, fdoReader);
+		if (bCustomPropertyFound) 
+		{
+			Ptr<MgReader> origReader = new MgdDataReader(connWrap, fdoReader);
+			Ptr<MgDataReader> customReader = dynamic_cast<MgDataReader*>(this->GetCustomReader(origReader, customFunc, customPropName));
+			origReader->Close();
+			reader = customReader;
+		}
+		else
+		{
+			reader = new MgdDataReader(connWrap, fdoReader);
+		}
     }
 
     MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(resource, L"MgdFeatureService::SelectAggregate")
@@ -3347,6 +3412,60 @@
 	return reader.Detach();
 }
 
+// Convert reader into a custom MgDataReader
+MgReader* MgdFeatureService::GetCustomReader(MgReader* reader, FdoFunction* customFunc, CREFSTRING propertyName)
+{
+    Ptr<MgReader> distReader;
+    Ptr<MgFeatureDistribution> featureDist =
+        MgFeatureDistribution::CreateDistributionFunction(reader, customFunc, propertyName);
+
+    distReader = featureDist->Execute();
+    return distReader.Detach();
+}
+
+bool MgdFeatureService::ContainsUdf(MgFeatureConnection* conn, FdoExpression* expression)
+{
+    bool isUdf = false;
+    bool fdoSupported = false;
+
+    // Downcast to FdoFunction
+    FdoFunction* function = dynamic_cast<FdoFunction*>(expression);
+
+    // If we are unable to downcast, it means it is not a function, it is just
+    // an expression. We do not do anything with this. We just pass it to FDO
+    if (function != NULL)
+    {
+        if (conn != NULL)
+        {
+            // Check if FDO supports this function, if so, let FDO handle it
+            fdoSupported = conn->IsSupportedFunction(function);
+        }
+
+        if (!fdoSupported)
+        {
+            // If function is not supported, then check if it is a custom function.
+            isUdf = IsCustomFunction(function);
+        }
+    }
+
+    return isUdf;
+}
+
+
+bool MgdFeatureService::IsCustomFunction(FdoFunction* fdoFunc)
+{
+    bool customFunc = false;
+
+    FdoString* funcNameAllowed = fdoFunc->GetName();
+    if (funcNameAllowed != NULL)
+    {
+        INT32 funcIndex = -1;
+        customFunc = MgFeatureUtil::FindCustomFunction(STRING(funcNameAllowed),funcIndex);
+    }
+
+    return customFunc;
+}
+
 MgPropertyCollection* MgdFeatureService::UpdateFeatures(MgResourceIdentifier* resource,
                                                         MgFeatureCommandCollection* commands,
                                                         bool useTransaction) 

Modified: branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h
===================================================================
--- branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h	2012-05-11 01:41:17 UTC (rev 6643)
+++ branches/2.4/MgDev/Desktop/MgDesktop/Services/FeatureService.h	2012-05-13 02:45:17 UTC (rev 6644)
@@ -273,6 +273,10 @@
 											bool withLock,
                                             bool asScrollable);
 	
+	bool ContainsUdf(MgFeatureConnection* conn, FdoExpression* expression);
+	bool IsCustomFunction(FdoFunction* fdoFunc);
+	MgReader* GetCustomReader(MgReader* reader, FdoFunction* customFunc, CREFSTRING propertyName);
+
     static MgSpatialContextData* GetSpatialContextData(FdoISpatialContextReader* spatialReader, MgSpatialContextInfo* spatialContextInfo);
 
     // Methods for describe schema



More information about the mapguide-commits mailing list