[mapguide-commits] r8454 - in trunk/Tools/Maestro: Maestro.Base/Commands/SiteExplorer Maestro.Editors Maestro.Editors/Common Maestro.Editors/Preview OSGeo.MapGuide.MaestroAPI OSGeo.MapGuide.MaestroAPI/Resource OSGeo.MapGuide.MaestroAPI/Resource/Preview OSGeo.MapGuide.MaestroAPI.Http OSGeo.MapGuide.MaestroAPI.Http/Resources

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Nov 20 17:27:04 PST 2014


Author: jng
Date: 2014-11-20 17:27:04 -0800 (Thu, 20 Nov 2014)
New Revision: 8454

Added:
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.Designer.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.resx
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpResourcePreviewUrlGenerator.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Resources/
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Resources/TextWatermark.txt
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.Designer.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.resx
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/IResourcePreviewUrlGenerator.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/ResourcePreviewUrlGenerator.cs
Modified:
   trunk/Tools/Maestro/Maestro.Base/Commands/SiteExplorer/TestResourceCompatibilityCommand.cs
   trunk/Tools/Maestro/Maestro.Editors/Common/EditorWindow.cs
   trunk/Tools/Maestro/Maestro.Editors/Preview/DefaultResourcePreviewer.cs
   trunk/Tools/Maestro/Maestro.Editors/Preview/LocalMapPreviewer.cs
   trunk/Tools/Maestro/Maestro.Editors/Preview/ResourcePreviewEngine.cs
   trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs
   trunk/Tools/Maestro/Maestro.Editors/Strings.resx
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/IServerConnection.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Utility.cs
Log:
#2506: Refactor the resource previewing mechanism so that each connection provider can implement its own URL generation

Modified: trunk/Tools/Maestro/Maestro.Base/Commands/SiteExplorer/TestResourceCompatibilityCommand.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Commands/SiteExplorer/TestResourceCompatibilityCommand.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Base/Commands/SiteExplorer/TestResourceCompatibilityCommand.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -307,5 +307,10 @@
         {
             throw new NotImplementedException();
         }
+
+        public OSGeo.MapGuide.MaestroAPI.Resource.Preview.IResourcePreviewUrlGenerator GetPreviewUrlGenerator()
+        {
+            throw new NotImplementedException();
+        }
     }
 }

Modified: trunk/Tools/Maestro/Maestro.Editors/Common/EditorWindow.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Common/EditorWindow.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Editors/Common/EditorWindow.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -123,7 +123,8 @@
             _svc = new DefaultResourceEditorService(resourceId, conn);
             _svc.DirtyStateChanged += OnDirtyStateChanged;
             _ed.Dock = DockStyle.Fill;
-            btnPreview.Enabled = ResourcePreviewEngine.IsPreviewableType(ResourceIdentifier.GetResourceTypeAsString(resourceId));
+            var previewer = conn.GetPreviewUrlGenerator();
+            btnPreview.Enabled = (previewer != null && previewer.IsPreviewableType(ResourceIdentifier.GetResourceTypeAsString(resourceId)));
             this.Controls.Add(_ed);
             _ed.Bind(_svc);
             _ed.ReadyForEditing();

Modified: trunk/Tools/Maestro/Maestro.Editors/Preview/DefaultResourcePreviewer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Preview/DefaultResourcePreviewer.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Editors/Preview/DefaultResourcePreviewer.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -103,7 +103,7 @@
                 else
                 {
                     //Now feed it to the preview engine
-                    var url = new ResourcePreviewEngine(mapguideRootUrl, edSvc).GeneratePreviewUrl(previewCopy, locale);
+                    var url = new ResourcePreviewEngine(edSvc).GeneratePreviewUrl(previewCopy, locale);
                     return new UrlPreviewResult() { Url = url };
                 }
             };
@@ -185,7 +185,8 @@
                 }
                 else
                 {
-                    bool bPreviewable = ResourcePreviewEngine.IsPreviewableType(rt);
+                    var previewer = res.CurrentConnection.GetPreviewUrlGenerator();
+                    bool bPreviewable = (previewer != null && previewer.IsPreviewableType(rt));
                     //A Map Definition can be saved directly and referenced by a Web Layout
                     //An Web Layout and Application Definition can be saved directly and
                     //passed straight to the AJAX/Fusion viewers.

Modified: trunk/Tools/Maestro/Maestro.Editors/Preview/LocalMapPreviewer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Preview/LocalMapPreviewer.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Editors/Preview/LocalMapPreviewer.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -129,7 +129,7 @@
                             break;
                         case "WatermarkDefinition":
                             {
-                                previewMdf = ResourcePreviewEngine.CreateWatermarkPreviewMapDefinition((IWatermarkDefinition)res);
+                                previewMdf = Utility.CreateWatermarkPreviewMapDefinition((IWatermarkDefinition)res);
                             }
                             break;
                         case "MapDefinition":

Modified: trunk/Tools/Maestro/Maestro.Editors/Preview/ResourcePreviewEngine.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Preview/ResourcePreviewEngine.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Editors/Preview/ResourcePreviewEngine.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -19,6 +19,7 @@
 #endregion
 using OSGeo.MapGuide.MaestroAPI;
 using OSGeo.MapGuide.MaestroAPI.Resource;
+using OSGeo.MapGuide.MaestroAPI.Resource.Preview;
 using OSGeo.MapGuide.MaestroAPI.Schema;
 using OSGeo.MapGuide.ObjectModels;
 using OSGeo.MapGuide.ObjectModels.ApplicationDefinition;
@@ -37,87 +38,36 @@
     /// <summary>
     /// Performs any necessary setup required to preview a given resource in a web browser
     /// </summary>
-    public class ResourcePreviewEngine
+    internal class ResourcePreviewEngine
     {
-        private string _rootUrl;
         private IEditorService _edSvc;
 
         /// <summary>
         /// Initializes a new instance of the ResourcePreviewEngine class
         /// </summary>
-        /// <param name="rootUrl"></param>
         /// <param name="edSvc"></param>
-        public ResourcePreviewEngine(string rootUrl, IEditorService edSvc)
+        public ResourcePreviewEngine(IEditorService edSvc)
         {
-            _rootUrl = rootUrl;
             _edSvc = edSvc;
         }
 
-        static string GetLocale(string locale)
+        /// <summary>
+        /// Generates the appropriate viewer URL to preview the given resource under the given locale
+        /// </summary>
+        /// <param name="res"></param>
+        /// <param name="locale"></param>
+        /// <returns></returns>
+        public string GeneratePreviewUrl(IResource res, string locale)
         {
-            return string.IsNullOrEmpty(locale) ? "en" : locale; //NOXLATE
-        }
-
-        private string GenerateFeatureSourcePreviewUrl(IResource res, string locale)
-        {
-            string url = _rootUrl;
-            if (!url.EndsWith("/")) //NOXLATE
-                url += "/"; //NOXLATE
-
-            var resId = res.ResourceID;
-            var sessionId = _edSvc.SessionID;
-            url += "schemareport/describeschema.php?viewer=basic&schemaName=&className=&resId=" + resId + "&sessionId=" + sessionId + "&locale=" + GetLocale(locale); //NOXLATE
-
-            return url;
-        }
-
-        private string GenerateLayerPreviewUrl(IResource res, string locale)
-        {
-            string url = _rootUrl;
-            if (!url.EndsWith("/")) //NOXLATE
-                url += "/"; //NOXLATE
-
-            var ldf = (ILayerDefinition)res;
-            var sessionId = _edSvc.SessionID;
             var conn = res.CurrentConnection;
-
-            string layerName = string.Empty;
-            //Use feature source as name/label if new and unsaved
-            if (_edSvc.IsNew)
-                layerName = ResourceIdentifier.GetName(ldf.SubLayer.ResourceId);
-            else
-                layerName = ResourceIdentifier.GetName(_edSvc.ResourceID);
-
-            var mdf = CreateLayerPreviewMapDefinition(ldf, sessionId, layerName, conn);
-            //if (PropertyService.Get(ConfigProperties.PreviewViewerType, "AJAX").Equals("AJAX")) //NOXLATE
-            if (PreviewSettings.UseAjaxViewer)
-            {
-                //Create temp web layout to house this map
-                var wl = ObjectFactory.CreateWebLayout(_edSvc.GetEditedResource().CurrentConnection, new Version(1, 0, 0), mdf.ResourceID);
-
-                //Add a custom zoom command (to assist previews of layers that aren't [0, infinity] scale)
-                AttachPreviewCommands(wl);
-
-                var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".WebLayout"; //NOXLATE
-
-                conn.ResourceService.SaveResourceAs(wl, resId);
-                url += "mapviewerajax/?WEBLAYOUT=" + resId + "&SESSION=" + sessionId + "&LOCALE=" + GetLocale(locale); //NOXLATE
-            }
-            else
-            {
-                throw new NotImplementedException();
-                ////Create temp flex layout
-                //var appDef = ObjectFactory.CreatePreviewFlexLayout(conn);
-                //var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".ApplicationDefinition"; //NOXLATE
-                //appDef.AddMapGroup("previewmap", true, mdfId); //NOXLATE
-
-                //conn.ResourceService.SaveResourceAs(appDef, resId);
-                //url += "fusion/templates/mapguide/preview/index.html?Session=" + sessionId + "&ApplicationDefinition=" + resId; //NOXLATE
-            }
-
-            return url;
+            var previewer = conn.GetPreviewUrlGenerator();
+            previewer.AddDebugWatermark = PreviewSettings.AddDebugWatermark;
+            previewer.UseAjaxViewer = PreviewSettings.UseAjaxViewer;
+            return previewer.GeneratePreviewUrl(res, locale, _edSvc.IsNew, _edSvc.SessionID);
         }
 
+        #region Preview helper code
+
         static string CreateDebugWatermark(IMapDefinition2 mdf, IServerConnection conn, string layerSc)
         {
             //Tidy up the CS WKT so that it can display nicely in a watermark
@@ -169,240 +119,20 @@
             if (extent == null)
                 throw new ApplicationException(Strings.FailedToCalculateFeatureSourceExtents);
 
-            string layerSc = GetLayerSpatialContext(ldf);
+            string layerSc = Utility.GetLayerSpatialContext(ldf);
 
             //TODO: Based on the visible scales in this layer, size this extents accordingly
             var mdf = ObjectFactory.CreateMapDefinition(conn, Strings.PreviewMap, csWkt, extent);
             IMapDefinition2 mdf2 = mdf as IMapDefinition2;
             if (mdf2 != null && PreviewSettings.AddDebugWatermark)
                 CreateDebugWatermark(mdf2, conn, layerSc);
-            
+
             var layer = mdf.AddLayer(null, layerName, ldf.ResourceID);
             conn.ResourceService.SaveResourceAs(mdf, mdfId);
             mdf.ResourceID = mdfId;
             return mdf;
         }
 
-        private static string GetLayerSpatialContext(ILayerDefinition ldf)
-        {
-            var conn = ldf.CurrentConnection;
-            var rl = ldf.SubLayer as IRasterLayerDefinition;
-            var vl = ldf.SubLayer as IVectorLayerDefinition;
-            if (vl != null)
-            {
-                var cls = conn.FeatureService.GetClassDefinition(vl.ResourceId, vl.FeatureName);
-                var gp = cls.FindProperty(vl.Geometry) as GeometricPropertyDefinition;
-                if (gp != null)
-                    return gp.SpatialContextAssociation;
-            }
-            else if (rl != null)
-            {
-                var cls = conn.FeatureService.GetClassDefinition(rl.ResourceId, rl.FeatureName);
-                var rp = cls.FindProperty(rl.Geometry) as RasterPropertyDefinition;
-                if (rp != null)
-                    return rp.SpatialContextAssociation;
-            }
-            return null;
-        }
-
-        private static void AttachPreviewCommands(IWebLayout wl)
-        {
-            var cmd = wl.CreateInvokeScriptCommand();
-            cmd.Name = "ZoomScale"; //NOXLATE
-            cmd.Label = Strings.Label_ZoomToScale;
-            cmd.Tooltip = Strings.Desc_ZoomToScale;
-            cmd.Script = @"
-                var map = parent.parent.GetMapFrame();
-                var center = map.GetCenter();
-                var scale = parseFloat(prompt('Enter the scale:'));
-                map.ZoomToView(center.X, center.Y, scale, true);
-                "; //NOXLATE
-
-            cmd.TargetViewer = TargetViewerType.Ajax;
-            cmd.ImageURL = "../stdicons/icon_zoom.gif"; //NOXLATE
-
-            wl.CommandSet.AddCommand(cmd);
-
-            var cmd2 = wl.CreateInvokeScriptCommand();
-            cmd2.Name = "GetMapKml"; //NOXLATE
-            cmd2.Label = Strings.Label_GetMapKml;
-            cmd2.Description = Strings.Desc_GetMapKml;
-            cmd2.Tooltip = Strings.Desc_GetMapKml;
-
-            cmd2.Script = @"
-                var map = parent.parent.GetMapFrame();
-                var url = ""../mapagent/mapagent.fcgi?OPERATION=GETMAPKML&VERSION=1.0.0&FORMAT=KML&DISPLAYDPI=96&MAPDEFINITION=" + wl.Map.ResourceId + @""";
-                url += ""&SESSION="" + map.GetSessionId();
-                window.open(url);"; //NOXLATE
-
-            cmd2.TargetViewer = TargetViewerType.Ajax;
-            cmd2.ImageURL = "../stdicons/icon_invokescript.gif"; //NOXLATE
-
-            wl.CommandSet.AddCommand(cmd2);
-
-            var cmd3 = wl.CreateInvokeScriptCommand();
-            cmd3.Name = "GetExtents"; //NOXLATE
-            cmd3.Label = Strings.Label_GetExtents;
-            cmd3.Description = Strings.Desc_GetExtents;
-            cmd3.Tooltip = Strings.Desc_GetExtents;
-
-            cmd3.Script = @"
-                var map = parent.parent.GetMapFrame();
-                alert('Map Extents\n\nLower Left: ' + map.extX1 + ', ' + map.extY2 + '\nUpper Right: ' + map.extX2 + ', ' + map.extY1);
-                "; //NOXLATE
-
-            cmd3.TargetViewer = TargetViewerType.Ajax;
-            cmd3.ImageURL = "../stdicons/icon_invokescript.gif"; //NOXLATE
-
-            wl.CommandSet.AddCommand(cmd3);
-
-            var zoomScale = wl.CreateCommandItem(cmd.Name);
-            var menu = wl.CreateFlyout(Strings.Label_Tools, Strings.Label_Tools, Strings.Label_ExtraTools, string.Empty, string.Empty,
-                wl.CreateCommandItem("ZoomScale"), //NOXLATE
-                wl.CreateCommandItem("GetMapKml"), //NOXLATE
-                wl.CreateCommandItem("GetExtents") //NOXLATE
-            );
-            wl.ToolBar.AddItem(menu);
-        }
-
-        private string GenerateWatermarkPreviewUrl(IWatermarkDefinition wmd, string locale)
-        {
-            //We demand a 2.3.0 Map Definition or higher
-            if (wmd.CurrentConnection.SiteVersion < new Version(2, 3))
-                throw new InvalidOperationException(Strings.SiteVersionDoesntSupportWatermarks);
-
-            IMapDefinition2 map = CreateWatermarkPreviewMapDefinition(wmd);
-            return GenerateMapPreviewUrl(map, locale);
-        }
-
-        internal static IMapDefinition2 CreateWatermarkPreviewMapDefinition(IWatermarkDefinition wmd)
-        {
-            IMapDefinition2 map = (IMapDefinition2)ObjectFactory.CreateMapDefinition(wmd.CurrentConnection, wmd.SupportedMapDefinitionVersion, "Watermark Definition Preview"); //NOXLATE
-            map.CoordinateSystem = @"LOCAL_CS[""*XY-M*"", LOCAL_DATUM[""*X-Y*"", 10000], UNIT[""Meter"", 1], AXIS[""X"", EAST], AXIS[""Y"", NORTH]]"; //NOXLATE
-            map.Extents = ObjectFactory.CreateEnvelope(-1000000, -1000000, 1000000, 1000000);
-            map.AddWatermark(wmd);
-            return map;
-        }
-
-        private string GenerateMapPreviewUrl(IResource res, string locale)
-        {
-            string url = _rootUrl;
-            if (!url.EndsWith("/")) //NOXLATE
-                url += "/"; //NOXLATE
-
-            var sessionId = _edSvc.SessionID;
-            var mdfId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".MapDefinition"; //NOXLATE
-            var conn = res.CurrentConnection;
-            var mdf = res as IMapDefinition;
-            if (mdf != null)
-            {
-                IMapDefinition2 mdf2 = mdf as IMapDefinition2;
-                if (mdf2 != null && PreviewSettings.AddDebugWatermark)
-                    CreateDebugWatermark(mdf2, conn, null);
-            }
-            conn.ResourceService.SaveResourceAs(res, mdfId);
-            //if (PropertyService.Get(ConfigProperties.PreviewViewerType, "AJAX").Equals("AJAX")) //NOXLATE
-            if (PreviewSettings.UseAjaxViewer)
-            {
-                //Create temp web layout to house this map
-                var wl = ObjectFactory.CreateWebLayout(_edSvc.GetEditedResource().CurrentConnection, new Version(1, 0, 0), mdfId);
-
-                //Add a custom zoom command (to assist previews of layers that aren't [0, infinity] scale)
-                AttachPreviewCommands(wl);
-
-                var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".WebLayout"; //NOXLATE
-
-                conn.ResourceService.SaveResourceAs(wl, resId);
-                url += "mapviewerajax/?WEBLAYOUT=" + resId + "&SESSION=" + sessionId + "&LOCALE=" + GetLocale(locale); //NOXLATE
-            }
-            else
-            {
-                throw new NotImplementedException();
-                ////Create temp flex layout
-                //var appDef = ObjectFactory.CreateFlexibleLayout(conn);
-                //var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".ApplicationDefinition"; //NOXLATE
-                //appDef.AddMapGroup("previewmap", true, mdfId); //NOXLATE
-
-                //conn.ResourceService.SaveResourceAs(appDef, resId);
-                //url += "fusion/templates/mapguide/preview/index.html?Session=" + sessionId + "&ApplicationDefinition=" + resId; //NOXLATE
-            }
-
-            return url;
-        }
-
-        private string GenerateWebLayoutPreviewUrl(IResource res, string locale)
-        {
-            string url = _rootUrl;
-            if (!url.EndsWith("/")) //NOXLATE
-                url += "/"; //NOXLATE
-
-            var sessionId = _edSvc.SessionID;
-            var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".WebLayout"; //NOXLATE
-            var conn = res.CurrentConnection;
-
-            conn.ResourceService.SaveResourceAs(res, resId);
-            url += "mapviewerajax/?WEBLAYOUT=" + resId + "&SESSION=" + sessionId + "&LOCALE=" + GetLocale(locale); //NOXLATE
-
-            return url;
-        }
-
-        private string GenerateFlexLayoutPreviewUrl(IResource res, string locale)
-        {
-            string url = _rootUrl;
-            if (!url.EndsWith("/")) //NOXLATE
-                url += "/"; //NOXLATE
-
-            //Create temp flex layout
-            var sessionId = _edSvc.SessionID;
-            var appDef = (IApplicationDefinition)res;
-            var conn = appDef.CurrentConnection;
-            var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".ApplicationDefinition"; //NOXLATE
-
-            conn.ResourceService.SaveResourceAs(appDef, resId);
-            url += appDef.TemplateUrl + "?Session=" + sessionId + "&ApplicationDefinition=" + resId + "&locale=" + GetLocale(locale); //NOXLATE
-            return url;
-        }
-
-        /// <summary>
-        /// Generates the appropriate viewer URL to preview the given resource under the given locale
-        /// </summary>
-        /// <param name="res"></param>
-        /// <param name="locale"></param>
-        /// <returns></returns>
-        public string GeneratePreviewUrl(IResource res, string locale)
-        {
-            switch (res.ResourceType)
-            {
-                case "FeatureSource":
-                    return GenerateFeatureSourcePreviewUrl(res, locale);
-                case "ApplicationDefinition":
-                    return GenerateFlexLayoutPreviewUrl(res, locale);
-                case "LayerDefinition":
-                    return GenerateLayerPreviewUrl(res, locale);
-                case "MapDefinition":
-                    return GenerateMapPreviewUrl(res, locale);
-                case "WebLayout":
-                    return GenerateWebLayoutPreviewUrl(res, locale);
-                case "WatermarkDefinition":
-                    return GenerateWatermarkPreviewUrl((IWatermarkDefinition)res, locale);
-                default:
-                    throw new InvalidOperationException(Strings.UnpreviewableResourceType);
-            }
-        }
-
-        private static string[] PREVIEWABLE_RESOURCE_TYPES = new string[] 
-        {
-            ResourceTypes.FeatureSource.ToString(),
-            ResourceTypes.ApplicationDefinition.ToString(),
-            ResourceTypes.LayerDefinition.ToString(),
-            ResourceTypes.MapDefinition.ToString(),
-            ResourceTypes.WebLayout.ToString(),
-            ResourceTypes.WatermarkDefinition.ToString()
-        };
-
-        internal static bool IsPreviewableType(string rt)
-        {
-            return Array.IndexOf(PREVIEWABLE_RESOURCE_TYPES, rt) >= 0;
-        }
+        #endregion
     }
 }

Modified: trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -511,33 +511,6 @@
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Displays the current map extents.
-        /// </summary>
-        internal static string Desc_GetExtents {
-            get {
-                return ResourceManager.GetString("Desc_GetExtents", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Gets the current map as a KML document.
-        /// </summary>
-        internal static string Desc_GetMapKml {
-            get {
-                return ResourceManager.GetString("Desc_GetMapKml", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Zoom to a specified scale.
-        /// </summary>
-        internal static string Desc_ZoomToScale {
-            get {
-                return ResourceManager.GetString("Desc_ZoomToScale", resourceCulture);
-            }
-        }
-        
-        /// <summary>
         ///   Looks up a localized string similar to Diverging.
         /// </summary>
         internal static string DivergingName {
@@ -1490,51 +1463,6 @@
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to Extra Tools.
-        /// </summary>
-        internal static string Label_ExtraTools {
-            get {
-                return ResourceManager.GetString("Label_ExtraTools", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Get Extents.
-        /// </summary>
-        internal static string Label_GetExtents {
-            get {
-                return ResourceManager.GetString("Label_GetExtents", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Get KML.
-        /// </summary>
-        internal static string Label_GetMapKml {
-            get {
-                return ResourceManager.GetString("Label_GetMapKml", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Tools.
-        /// </summary>
-        internal static string Label_Tools {
-            get {
-                return ResourceManager.GetString("Label_Tools", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Zoom to Scale.
-        /// </summary>
-        internal static string Label_ZoomToScale {
-            get {
-                return ResourceManager.GetString("Label_ZoomToScale", resourceCulture);
-            }
-        }
-        
-        /// <summary>
         ///   Looks up a localized string similar to Last Updated: .
         /// </summary>
         internal static string LastUpdated {
@@ -2929,15 +2857,6 @@
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to The resource type cannot be previewed.
-        /// </summary>
-        internal static string UnpreviewableResourceType {
-            get {
-                return ResourceManager.GetString("UnpreviewableResourceType", resourceCulture);
-            }
-        }
-        
-        /// <summary>
         ///   Looks up a localized string similar to Invoking MgCooker is not supported for this connection type: {0}.
         /// </summary>
         internal static string UnsupportedConnectionType {

Modified: trunk/Tools/Maestro/Maestro.Editors/Strings.resx
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Strings.resx	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/Maestro.Editors/Strings.resx	2014-11-21 01:27:04 UTC (rev 8454)
@@ -1472,33 +1472,9 @@
   <data name="LoadingFeatureClasses" xml:space="preserve">
     <value>Loading Feature Classes</value>
   </data>
-  <data name="Desc_GetExtents" xml:space="preserve">
-    <value>Displays the current map extents</value>
-  </data>
-  <data name="Desc_GetMapKml" xml:space="preserve">
-    <value>Gets the current map as a KML document</value>
-  </data>
-  <data name="Desc_ZoomToScale" xml:space="preserve">
-    <value>Zoom to a specified scale</value>
-  </data>
   <data name="FailedToCalculateFeatureSourceExtents" xml:space="preserve">
     <value>Could not calculate the extents of the Feature Source. Preview is not possible</value>
   </data>
-  <data name="Label_ExtraTools" xml:space="preserve">
-    <value>Extra Tools</value>
-  </data>
-  <data name="Label_GetExtents" xml:space="preserve">
-    <value>Get Extents</value>
-  </data>
-  <data name="Label_GetMapKml" xml:space="preserve">
-    <value>Get KML</value>
-  </data>
-  <data name="Label_Tools" xml:space="preserve">
-    <value>Tools</value>
-  </data>
-  <data name="Label_ZoomToScale" xml:space="preserve">
-    <value>Zoom to Scale</value>
-  </data>
   <data name="PreviewMap" xml:space="preserve">
     <value>Preview Map</value>
   </data>
@@ -1508,9 +1484,6 @@
   <data name="SiteVersionDoesntSupportWatermarks" xml:space="preserve">
     <value>The site version of this current connection is not known to support watermarks</value>
   </data>
-  <data name="UnpreviewableResourceType" xml:space="preserve">
-    <value>The resource type cannot be previewed</value>
-  </data>
   <data name="NoRegisteredPreviewerForProvider" xml:space="preserve">
     <value>No registered previewer for connection: {0}</value>
   </data>
@@ -1562,12 +1535,6 @@
   <data name="ThemePrimaryKeyPropertyNotSelected" xml:space="preserve">
     <value>Property not selected. Please select the Property which connects to the selected Key Property in the external class</value>
   </data>
-  <data name="DebugWatermarkMessage" xml:space="preserve">
-    <value>MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}</value>
-  </data>
-  <data name="DebugWatermarkMessageLayer" xml:space="preserve">
-    <value>MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}\nLayer Spatial Context: {5}</value>
-  </data>
   <data name="UpdatingStylePreviews" xml:space="preserve">
     <value>Updating Style Previews</value>
   </data>
@@ -1637,4 +1604,10 @@
   <data name="None" xml:space="preserve">
     <value>None</value>
   </data>
+  <data name="DebugWatermarkMessage" xml:space="preserve">
+    <value>MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}</value>
+  </data>
+  <data name="DebugWatermarkMessageLayer" xml:space="preserve">
+    <value>MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}\nLayer Spatial Context: {5}</value>
+  </data>
 </root>
\ No newline at end of file

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/IServerConnection.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/IServerConnection.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/IServerConnection.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -57,6 +57,13 @@
     public interface IServerConnection
     {
         /// <summary>
+        /// Gets the preview URL generator.
+        /// </summary>
+        /// <remarks>Each call will return a new instance</remarks>
+        /// <returns>The preview URL generator. Returns null if this connection does not support browser-based resource previews</returns>
+        Resource.Preview.IResourcePreviewUrlGenerator GetPreviewUrlGenerator();
+
+        /// <summary>
         /// Gets the name of the provider of this implementation
         /// </summary>
         string ProviderName { get; }

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/OSGeo.MapGuide.MaestroAPI.csproj	2014-11-21 01:27:04 UTC (rev 8454)
@@ -277,6 +277,8 @@
     <Compile Include="Resource\Conversion\ImageSymbolConverter.cs" />
     <Compile Include="Resource\Conversion\NsDoc.cs" />
     <Compile Include="Resource\NsDoc.cs" />
+    <Compile Include="Resource\Preview\IResourcePreviewUrlGenerator.cs" />
+    <Compile Include="Resource\Preview\ResourcePreviewUrlGenerator.cs" />
     <Compile Include="Resource\Validation\BaseMapDefinitionValidator.cs" />
     <Compile Include="Resource\Validation\BaseSymbolDefinitionValidator.cs" />
     <Compile Include="Resource\Validation\NsDoc.cs" />

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/PlatformConnectionBase.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -243,6 +243,12 @@
         #endregion
 
         /// <summary>
+        /// Gets the preview URL generator.
+        /// </summary>
+        /// <returns>The preview URL generator. Returns null if this connection does not support browser-based resource previews</returns>
+        public virtual OSGeo.MapGuide.MaestroAPI.Resource.Preview.IResourcePreviewUrlGenerator GetPreviewUrlGenerator() { return null; }
+
+        /// <summary>
         /// Gets the name of the provider of this implementation
         /// </summary>
         public abstract string ProviderName { get; }

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/IResourcePreviewUrlGenerator.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/IResourcePreviewUrlGenerator.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/IResourcePreviewUrlGenerator.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,32 @@
+#region Disclaimer / License
+// Copyright (C) 2014, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+
+namespace OSGeo.MapGuide.MaestroAPI.Resource.Preview
+{
+    public interface IResourcePreviewUrlGenerator
+    {
+        bool UseAjaxViewer { get; set; }
+        bool AddDebugWatermark { get; set; }
+
+        string GeneratePreviewUrl(OSGeo.MapGuide.MaestroAPI.Resource.IResource res, string locale, bool isNew, string sessionID);
+        bool IsPreviewableType(string resourceType);
+    }
+}

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/ResourcePreviewUrlGenerator.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/ResourcePreviewUrlGenerator.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Preview/ResourcePreviewUrlGenerator.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,94 @@
+#region Disclaimer / License
+// Copyright (C) 2014, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using OSGeo.MapGuide.ObjectModels.WatermarkDefinition;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace OSGeo.MapGuide.MaestroAPI.Resource.Preview
+{
+    public abstract class ResourcePreviewUrlGenerator : IResourcePreviewUrlGenerator
+    {
+        protected ResourcePreviewUrlGenerator()
+        {
+            this.AddDebugWatermark = true;
+            this.UseAjaxViewer = true;
+        }
+
+        protected static string GetLocale(string locale)
+        {
+            return string.IsNullOrEmpty(locale) ? "en" : locale; //NOXLATE
+        }
+
+        /// <summary>
+        /// Generates the appropriate viewer URL to preview the given resource under the given locale
+        /// </summary>
+        /// <param name="res"></param>
+        /// <param name="locale"></param>
+        /// <returns></returns>
+        public string GeneratePreviewUrl(IResource res, string locale, bool isNew, string sessionID)
+        {
+            switch (res.ResourceType)
+            {
+                case "FeatureSource":
+                    return GenerateFeatureSourcePreviewUrl(res, locale, isNew, sessionID);
+                case "ApplicationDefinition":
+                    return GenerateFlexLayoutPreviewUrl(res, locale, isNew, sessionID);
+                case "LayerDefinition":
+                    return GenerateLayerPreviewUrl(res, locale, isNew, sessionID);
+                case "MapDefinition":
+                    return GenerateMapPreviewUrl(res, locale, isNew, sessionID);
+                case "WebLayout":
+                    return GenerateWebLayoutPreviewUrl(res, locale, isNew, sessionID);
+                case "WatermarkDefinition":
+                    return GenerateWatermarkPreviewUrl((IWatermarkDefinition)res, locale, isNew, sessionID);
+                default:
+                    throw new InvalidOperationException(Strings.UnpreviewableResourceType);
+            }
+        }
+
+        protected abstract string GenerateWatermarkPreviewUrl(IWatermarkDefinition watermarkDefinition, string locale, bool isNew, string sessionID);
+
+        protected abstract string GenerateWebLayoutPreviewUrl(IResource res, string locale, bool isNew, string sessionID);
+
+        protected abstract string GenerateMapPreviewUrl(IResource res, string locale, bool isNew, string sessionID);
+
+        protected abstract string GenerateLayerPreviewUrl(IResource res, string locale, bool isNew, string sessionID);
+
+        protected abstract string GenerateFlexLayoutPreviewUrl(IResource res, string locale, bool isNew, string sessionID);
+
+        protected abstract string GenerateFeatureSourcePreviewUrl(IResource res, string locale, bool isNew, string sessionID);
+
+        public abstract bool IsPreviewableType(string resourceType);
+
+        public bool UseAjaxViewer
+        {
+            get;
+            set;
+        }
+
+        public bool AddDebugWatermark
+        {
+            get;
+            set;
+        }
+    }
+}

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -1,7 +1,7 @@
 //------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
-//     Runtime Version:4.0.30319.18444
+//     Runtime Version:4.0.30319.34209
 //
 //     Changes to this file may cause incorrect behavior and will be lost if
 //     the code is regenerated.
@@ -2610,6 +2610,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to The resource type cannot be previewed.
+        /// </summary>
+        public static string UnpreviewableResourceType {
+            get {
+                return ResourceManager.GetString("UnpreviewableResourceType", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Unsupported Load Procedure Type.
         /// </summary>
         public static string UnsupportedLoadProcedureType {

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx	2014-11-21 01:27:04 UTC (rev 8454)
@@ -3435,4 +3435,7 @@
   <data name="MDF_UnselectableLayer" xml:space="preserve">
     <value>Layer {0} is marked as selectable but its feature class {1} in ({2}) has no identity properties. This layer will not be selectable.</value>
   </data>
+  <data name="UnpreviewableResourceType" xml:space="preserve">
+    <value>The resource type cannot be previewed</value>
+  </data>
 </root>
\ No newline at end of file

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Utility.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Utility.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Utility.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -36,6 +36,8 @@
 using System.ComponentModel;
 using System.Xml.Serialization;
 using System.IO;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.WatermarkDefinition;
 
 namespace OSGeo.MapGuide.MaestroAPI
 {
@@ -1500,6 +1502,47 @@
         }
 
         /// <summary>
+        /// Gets the name of the active spatial context used by the given layer definition
+        /// </summary>
+        /// <param name="ldf"></param>
+        /// <returns></returns>
+        public static string GetLayerSpatialContext(ILayerDefinition ldf)
+        {
+            var conn = ldf.CurrentConnection;
+            var rl = ldf.SubLayer as IRasterLayerDefinition;
+            var vl = ldf.SubLayer as IVectorLayerDefinition;
+            if (vl != null)
+            {
+                var cls = conn.FeatureService.GetClassDefinition(vl.ResourceId, vl.FeatureName);
+                var gp = cls.FindProperty(vl.Geometry) as GeometricPropertyDefinition;
+                if (gp != null)
+                    return gp.SpatialContextAssociation;
+            }
+            else if (rl != null)
+            {
+                var cls = conn.FeatureService.GetClassDefinition(rl.ResourceId, rl.FeatureName);
+                var rp = cls.FindProperty(rl.Geometry) as RasterPropertyDefinition;
+                if (rp != null)
+                    return rp.SpatialContextAssociation;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Creates a preview map definition for the given watermark
+        /// </summary>
+        /// <param name="wmd"></param>
+        /// <returns></returns>
+        public static IMapDefinition2 CreateWatermarkPreviewMapDefinition(IWatermarkDefinition wmd)
+        {
+            IMapDefinition2 map = (IMapDefinition2)ObjectFactory.CreateMapDefinition(wmd.CurrentConnection, wmd.SupportedMapDefinitionVersion, "Watermark Definition Preview"); //NOXLATE
+            map.CoordinateSystem = @"LOCAL_CS[""*XY-M*"", LOCAL_DATUM[""*X-Y*"", 10000], UNIT[""Meter"", 1], AXIS[""X"", EAST], AXIS[""Y"", NORTH]]"; //NOXLATE
+            map.Extents = ObjectFactory.CreateEnvelope(-1000000, -1000000, 1000000, 1000000);
+            map.AddWatermark(wmd);
+            return map;
+        }
+
+        /// <summary>
         /// Replaces all references of the given resource id.
         /// </summary>
         /// <param name="doc">A resource document. Any replacements will modify the XmlDocument that is passed in</param>

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.Designer.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.Designer.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.Designer.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,84 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.34209
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace OSGeo.MapGuide.MaestroAPI.Http {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Files {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Files() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OSGeo.MapGuide.MaestroAPI.Http.Files", typeof(Files).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to <?xml version="1.0"?>
+        ///<WatermarkDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="2.4.0" xsi:noNamespaceSchemaLocation="WatermarkDefinition-2.4.0.xsd">
+        ///  <Content>
+        ///    <SimpleSymbolDefinition>
+        ///      <Name />
+        ///      <Description />
+        ///      <Graphics>
+        ///        <Text>
+        ///          <Content>'{0}'</Content>
+        ///          <FontName>'Arial'</FontName>
+        ///          <Height>3</Height>
+        ///          <Justification>'Left'</Justification>
+        ///          <TextCol [rest of string was truncated]";.
+        /// </summary>
+        internal static string TextWatermark {
+            get {
+                return ResourceManager.GetString("TextWatermark", resourceCulture);
+            }
+        }
+    }
+}

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.resx
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.resx	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Files.resx	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,124 @@
+<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="TextWatermark" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\TextWatermark.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;Windows-1252</value>
+  </data>
+</root>
\ No newline at end of file

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpResourcePreviewUrlGenerator.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpResourcePreviewUrlGenerator.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpResourcePreviewUrlGenerator.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,329 @@
+#region Disclaimer / License
+// Copyright (C) 2014, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using OSGeo.MapGuide.MaestroAPI.Resource;
+using OSGeo.MapGuide.MaestroAPI.Resource.Preview;
+using OSGeo.MapGuide.ObjectModels;
+using OSGeo.MapGuide.ObjectModels.ApplicationDefinition;
+using OSGeo.MapGuide.ObjectModels.LayerDefinition;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.WatermarkDefinition;
+using OSGeo.MapGuide.ObjectModels.WebLayout;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace OSGeo.MapGuide.MaestroAPI.Http
+{
+    class HttpResourcePreviewUrlGenerator : ResourcePreviewUrlGenerator
+    {
+        private string _rootUrl;
+
+        public HttpResourcePreviewUrlGenerator(string rootUrl)
+        {
+            _rootUrl = rootUrl;
+        }
+
+        protected override string GenerateWatermarkPreviewUrl(ObjectModels.WatermarkDefinition.IWatermarkDefinition wmd, string locale, bool isNew, string sessionID)
+        {
+            //We demand a 2.3.0 Map Definition or higher
+            if (wmd.CurrentConnection.SiteVersion < new Version(2, 3))
+                throw new InvalidOperationException(Strings.SiteVersionDoesntSupportWatermarks);
+
+            IMapDefinition2 map = Utility.CreateWatermarkPreviewMapDefinition(wmd);
+            return GenerateMapPreviewUrl(map, locale, isNew, sessionID);
+        }
+
+        protected string GetRootUrl()
+        {
+            string url = _rootUrl;
+            if (url.EndsWith("mapagent.fcgi"))
+            {
+                string[] tokens = url.Split('/');
+                url = string.Join("/", tokens.Take(tokens.Length - 2).ToArray());
+            }
+            if (!url.EndsWith("/")) //NOXLATE
+                url += "/"; //NOXLATE
+
+            return url;
+        }
+
+        protected override string GenerateWebLayoutPreviewUrl(Resource.IResource res, string locale, bool isNew, string sessionID)
+        {
+            string url = GetRootUrl();
+
+            var resId = "Session:" + sessionID + "//" + Guid.NewGuid() + ".WebLayout"; //NOXLATE
+            var conn = res.CurrentConnection;
+
+            conn.ResourceService.SaveResourceAs(res, resId);
+            url += "mapviewerajax/?WEBLAYOUT=" + resId + "&SESSION=" + sessionID + "&LOCALE=" + GetLocale(locale); //NOXLATE
+
+            return url;
+        }
+
+        protected override string GenerateMapPreviewUrl(Resource.IResource res, string locale, bool isNew, string sessionID)
+        {
+            string url = GetRootUrl();
+
+            var mdfId = "Session:" + sessionID + "//" + Guid.NewGuid() + ".MapDefinition"; //NOXLATE
+            var conn = res.CurrentConnection;
+            var mdf = res as IMapDefinition;
+            if (mdf != null)
+            {
+                IMapDefinition2 mdf2 = mdf as IMapDefinition2;
+                if (mdf2 != null && this.AddDebugWatermark)
+                    CreateDebugWatermark(mdf2, conn, null);
+            }
+            conn.ResourceService.SaveResourceAs(res, mdfId);
+            //if (PropertyService.Get(ConfigProperties.PreviewViewerType, "AJAX").Equals("AJAX")) //NOXLATE
+            if (this.UseAjaxViewer)
+            {
+                //Create temp web layout to house this map
+                var wl = ObjectFactory.CreateWebLayout(conn, new Version(1, 0, 0), mdfId);
+
+                //Add a custom zoom command (to assist previews of layers that aren't [0, infinity] scale)
+                AttachPreviewCommands(wl);
+
+                var resId = "Session:" + sessionID + "//" + Guid.NewGuid() + ".WebLayout"; //NOXLATE
+
+                conn.ResourceService.SaveResourceAs(wl, resId);
+                url += "mapviewerajax/?WEBLAYOUT=" + resId + "&SESSION=" + sessionID + "&LOCALE=" + GetLocale(locale); //NOXLATE
+            }
+            else
+            {
+                throw new NotImplementedException();
+                ////Create temp flex layout
+                //var appDef = ObjectFactory.CreateFlexibleLayout(conn);
+                //var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".ApplicationDefinition"; //NOXLATE
+                //appDef.AddMapGroup("previewmap", true, mdfId); //NOXLATE
+
+                //conn.ResourceService.SaveResourceAs(appDef, resId);
+                //url += "fusion/templates/mapguide/preview/index.html?Session=" + sessionId + "&ApplicationDefinition=" + resId; //NOXLATE
+            }
+
+            return url;
+        }
+
+        private IMapDefinition CreateLayerPreviewMapDefinition(ILayerDefinition ldf, string sessionId, string layerName, IServerConnection conn)
+        {
+            //Create temp map definition to house our current layer
+            var mdfId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".MapDefinition"; //NOXLATE
+            string csWkt;
+            var extent = ldf.GetSpatialExtent(true, out csWkt);
+            if (extent == null)
+                throw new ApplicationException(Strings.FailedToCalculateFeatureSourceExtents);
+
+            string layerSc = Utility.GetLayerSpatialContext(ldf);
+
+            //TODO: Based on the visible scales in this layer, size this extents accordingly
+            var mdf = ObjectFactory.CreateMapDefinition(conn, Strings.PreviewMap, csWkt, extent);
+            IMapDefinition2 mdf2 = mdf as IMapDefinition2;
+            if (mdf2 != null && this.AddDebugWatermark)
+                CreateDebugWatermark(mdf2, conn, layerSc);
+
+            var layer = mdf.AddLayer(null, layerName, ldf.ResourceID);
+            conn.ResourceService.SaveResourceAs(mdf, mdfId);
+            mdf.ResourceID = mdfId;
+            return mdf;
+        }
+
+        protected override string GenerateLayerPreviewUrl(Resource.IResource res, string locale, bool isNew, string sessionID)
+        {
+            string url = GetRootUrl();
+
+            var ldf = (ILayerDefinition)res;
+            var conn = res.CurrentConnection;
+
+            //Use feature source as name/label
+            string layerName = ResourceIdentifier.GetName(ldf.SubLayer.ResourceId);
+
+            var mdf = CreateLayerPreviewMapDefinition(ldf, sessionID, layerName, conn);
+            //if (PropertyService.Get(ConfigProperties.PreviewViewerType, "AJAX").Equals("AJAX")) //NOXLATE
+            if (this.UseAjaxViewer)
+            {
+                //Create temp web layout to house this map
+                var wl = ObjectFactory.CreateWebLayout(conn, new Version(1, 0, 0), mdf.ResourceID);
+
+                //Add a custom zoom command (to assist previews of layers that aren't [0, infinity] scale)
+                AttachPreviewCommands(wl);
+
+                var resId = "Session:" + sessionID + "//" + Guid.NewGuid() + ".WebLayout"; //NOXLATE
+
+                conn.ResourceService.SaveResourceAs(wl, resId);
+                url += "mapviewerajax/?WEBLAYOUT=" + resId + "&SESSION=" + sessionID + "&LOCALE=" + GetLocale(locale); //NOXLATE
+            }
+            else
+            {
+                throw new NotImplementedException();
+                ////Create temp flex layout
+                //var appDef = ObjectFactory.CreatePreviewFlexLayout(conn);
+                //var resId = "Session:" + sessionId + "//" + Guid.NewGuid() + ".ApplicationDefinition"; //NOXLATE
+                //appDef.AddMapGroup("previewmap", true, mdfId); //NOXLATE
+
+                //conn.ResourceService.SaveResourceAs(appDef, resId);
+                //url += "fusion/templates/mapguide/preview/index.html?Session=" + sessionId + "&ApplicationDefinition=" + resId; //NOXLATE
+            }
+
+            return url;
+        }
+
+        protected override string GenerateFlexLayoutPreviewUrl(Resource.IResource res, string locale, bool isNew, string sessionID)
+        {
+            string url = GetRootUrl();
+
+            //Create temp flex layout
+            var appDef = (IApplicationDefinition)res;
+            var conn = appDef.CurrentConnection;
+            var resId = "Session:" + sessionID + "//" + Guid.NewGuid() + ".ApplicationDefinition"; //NOXLATE
+
+            conn.ResourceService.SaveResourceAs(appDef, resId);
+            url += appDef.TemplateUrl + "?Session=" + sessionID + "&ApplicationDefinition=" + resId + "&locale=" + GetLocale(locale); //NOXLATE
+            return url;
+        }
+
+        protected override string GenerateFeatureSourcePreviewUrl(Resource.IResource res, string locale, bool isNew, string sessionID)
+        {
+            string url = GetRootUrl();
+            
+            var resId = res.ResourceID;
+            url += "schemareport/describeschema.php?viewer=basic&schemaName=&className=&resId=" + resId + "&sessionId=" + sessionID + "&locale=" + GetLocale(locale); //NOXLATE
+
+            return url;
+        }
+
+        private static string[] PREVIEWABLE_RESOURCE_TYPES = new string[] 
+        {
+            ResourceTypes.FeatureSource.ToString(),
+            ResourceTypes.ApplicationDefinition.ToString(),
+            ResourceTypes.LayerDefinition.ToString(),
+            ResourceTypes.MapDefinition.ToString(),
+            ResourceTypes.WebLayout.ToString(),
+            ResourceTypes.WatermarkDefinition.ToString()
+        };
+
+        public override bool IsPreviewableType(string resourceType)
+        {
+            return Array.IndexOf(PREVIEWABLE_RESOURCE_TYPES, resourceType) >= 0;
+        }
+
+        static void AttachPreviewCommands(IWebLayout wl)
+        {
+            var cmd = wl.CreateInvokeScriptCommand();
+            cmd.Name = "ZoomScale"; //NOXLATE
+            cmd.Label = Strings.Label_ZoomToScale;
+            cmd.Tooltip = Strings.Desc_ZoomToScale;
+            cmd.Script = @"
+                var map = parent.parent.GetMapFrame();
+                var center = map.GetCenter();
+                var scale = parseFloat(prompt('Enter the scale:'));
+                map.ZoomToView(center.X, center.Y, scale, true);
+                "; //NOXLATE
+
+            cmd.TargetViewer = TargetViewerType.Ajax;
+            cmd.ImageURL = "../stdicons/icon_zoom.gif"; //NOXLATE
+
+            wl.CommandSet.AddCommand(cmd);
+
+            var cmd2 = wl.CreateInvokeScriptCommand();
+            cmd2.Name = "GetMapKml"; //NOXLATE
+            cmd2.Label = Strings.Label_GetMapKml;
+            cmd2.Description = Strings.Desc_GetMapKml;
+            cmd2.Tooltip = Strings.Desc_GetMapKml;
+
+            cmd2.Script = @"
+                var map = parent.parent.GetMapFrame();
+                var url = ""../mapagent/mapagent.fcgi?OPERATION=GETMAPKML&VERSION=1.0.0&FORMAT=KML&DISPLAYDPI=96&MAPDEFINITION=" + wl.Map.ResourceId + @""";
+                url += ""&SESSION="" + map.GetSessionId();
+                window.open(url);"; //NOXLATE
+
+            cmd2.TargetViewer = TargetViewerType.Ajax;
+            cmd2.ImageURL = "../stdicons/icon_invokescript.gif"; //NOXLATE
+
+            wl.CommandSet.AddCommand(cmd2);
+
+            var cmd3 = wl.CreateInvokeScriptCommand();
+            cmd3.Name = "GetExtents"; //NOXLATE
+            cmd3.Label = Strings.Label_GetExtents;
+            cmd3.Description = Strings.Desc_GetExtents;
+            cmd3.Tooltip = Strings.Desc_GetExtents;
+
+            cmd3.Script = @"
+                var map = parent.parent.GetMapFrame();
+                alert('Map Extents\n\nLower Left: ' + map.extX1 + ', ' + map.extY2 + '\nUpper Right: ' + map.extX2 + ', ' + map.extY1);
+                "; //NOXLATE
+
+            cmd3.TargetViewer = TargetViewerType.Ajax;
+            cmd3.ImageURL = "../stdicons/icon_invokescript.gif"; //NOXLATE
+
+            wl.CommandSet.AddCommand(cmd3);
+
+            var zoomScale = wl.CreateCommandItem(cmd.Name);
+            var menu = wl.CreateFlyout(Strings.Label_Tools, Strings.Label_Tools, Strings.Label_ExtraTools, string.Empty, string.Empty,
+                wl.CreateCommandItem("ZoomScale"), //NOXLATE
+                wl.CreateCommandItem("GetMapKml"), //NOXLATE
+                wl.CreateCommandItem("GetExtents") //NOXLATE
+            );
+            wl.ToolBar.AddItem(menu);
+        }
+
+        static string CreateDebugWatermark(IMapDefinition2 mdf, IServerConnection conn, string layerSc)
+        {
+            //Tidy up the CS WKT so that it can display nicely in a watermark
+            StringBuilder cleanCs = new StringBuilder(mdf.CoordinateSystem);
+            cleanCs.Replace("[", "[\n");
+            cleanCs.Replace("],", "],\n");
+
+            string message = null;
+
+            if (!string.IsNullOrEmpty(layerSc))
+            {
+                message = string.Format(Strings.DebugWatermarkMessageLayer,
+                    mdf.Extents.MinX,
+                    mdf.Extents.MinY,
+                    mdf.Extents.MaxX,
+                    mdf.Extents.MaxY,
+                    cleanCs.ToString(),
+                    layerSc);
+            }
+            else
+            {
+                message = string.Format(Strings.DebugWatermarkMessage,
+                    mdf.Extents.MinX,
+                    mdf.Extents.MinY,
+                    mdf.Extents.MaxX,
+                    mdf.Extents.MaxY,
+                    cleanCs.ToString());
+            }
+            string watermarkXml = string.Format(Files.TextWatermark, message);
+            string resId = "Session:" + conn.SessionID + "//Debug.WatermarkDefinition";
+            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(watermarkXml)))
+            {
+                conn.ResourceService.SetResourceXmlData(resId, ms);
+            }
+
+            //Add watermark to Map Definition
+            var wmd = (IWatermarkDefinition)conn.ResourceService.GetResource(resId);
+            mdf.AddWatermark(wmd);
+
+            return resId;
+        }
+    }
+}

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/HttpServerConnection.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -2006,5 +2006,10 @@
                 return info;
             }
         }
+
+        public override Resource.Preview.IResourcePreviewUrlGenerator GetPreviewUrlGenerator()
+        {
+            return new HttpResourcePreviewUrlGenerator(m_reqBuilder.HostURI);
+        }
     }
 }

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj	2014-11-21 01:05:28 UTC (rev 8453)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/OSGeo.MapGuide.MaestroAPI.Http.csproj	2014-11-21 01:27:04 UTC (rev 8454)
@@ -77,14 +77,25 @@
     <Compile Include="Commands\HttpCreateRuntimeMap.cs" />
     <Compile Include="Commands\HttpDescribeRuntimeMap.cs" />
     <Compile Include="Commands\HttpGetFdoCacheInfo.cs" />
+    <Compile Include="Files.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Files.resx</DependentUpon>
+    </Compile>
     <Compile Include="HttpCapabilities.cs" />
     <Compile Include="HttpCoordinateSystem.cs" />
     <Compile Include="HttpCoordinateSystemCatalog.cs" />
     <Compile Include="HttpCoordinateSystemCategory.cs" />
+    <Compile Include="HttpResourcePreviewUrlGenerator.cs" />
     <Compile Include="HttpServerConnection.cs" />
     <Compile Include="Commands\HttpGetResourceContents.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RequestBuilder.cs" />
+    <Compile Include="Strings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Strings.resx</DependentUpon>
+    </Compile>
     <Compile Include="XmlDataReader.cs" />
     <Compile Include="XmlFeatureReader.cs" />
     <Compile Include="XmlReaderBase.cs" />
@@ -113,6 +124,19 @@
       <Install>true</Install>
     </BootstrapperPackage>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Files.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Files.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Strings.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\TextWatermark.txt" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Resources/TextWatermark.txt
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Resources/TextWatermark.txt	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Resources/TextWatermark.txt	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,38 @@
+<?xml version="1.0"?>
+<WatermarkDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" version="2.4.0" xsi:noNamespaceSchemaLocation="WatermarkDefinition-2.4.0.xsd">
+  <Content>
+    <SimpleSymbolDefinition>
+      <Name />
+      <Description />
+      <Graphics>
+        <Text>
+          <Content>'{0}'</Content>
+          <FontName>'Arial'</FontName>
+          <Height>3</Height>
+          <Justification>'Left'</Justification>
+          <TextColor>FF000000</TextColor>
+          <Frame>
+            <FillColor>CCFFFFFF</FillColor>
+          </Frame>
+        </Text>
+      </Graphics>
+      <PointUsage />
+      <ParameterDefinition />
+    </SimpleSymbolDefinition>
+  </Content>
+  <Appearance />
+  <Position>
+    <XYPosition>
+      <XPosition>
+        <Offset>10</Offset>
+        <Unit>Points</Unit>
+        <Alignment>Left</Alignment>
+      </XPosition>
+      <YPosition>
+        <Offset>10</Offset>
+        <Unit>Points</Unit>
+        <Alignment>Top</Alignment>
+      </YPosition>
+    </XYPosition>
+  </Position>
+</WatermarkDefinition>
\ No newline at end of file

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.Designer.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.Designer.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.Designer.cs	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,180 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.34209
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace OSGeo.MapGuide.MaestroAPI.Http {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Strings {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Strings() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("OSGeo.MapGuide.MaestroAPI.Http.Strings", typeof(Strings).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}.
+        /// </summary>
+        internal static string DebugWatermarkMessage {
+            get {
+                return ResourceManager.GetString("DebugWatermarkMessage", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}\nLayer Spatial Context: {5}.
+        /// </summary>
+        internal static string DebugWatermarkMessageLayer {
+            get {
+                return ResourceManager.GetString("DebugWatermarkMessageLayer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Displays the current map extents.
+        /// </summary>
+        internal static string Desc_GetExtents {
+            get {
+                return ResourceManager.GetString("Desc_GetExtents", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Gets the current map as a KML document.
+        /// </summary>
+        internal static string Desc_GetMapKml {
+            get {
+                return ResourceManager.GetString("Desc_GetMapKml", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Zoom to a specified scale.
+        /// </summary>
+        internal static string Desc_ZoomToScale {
+            get {
+                return ResourceManager.GetString("Desc_ZoomToScale", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Could not calculate the extents of the Feature Source. Preview is not possible.
+        /// </summary>
+        internal static string FailedToCalculateFeatureSourceExtents {
+            get {
+                return ResourceManager.GetString("FailedToCalculateFeatureSourceExtents", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Extra Tools.
+        /// </summary>
+        internal static string Label_ExtraTools {
+            get {
+                return ResourceManager.GetString("Label_ExtraTools", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Get Extents.
+        /// </summary>
+        internal static string Label_GetExtents {
+            get {
+                return ResourceManager.GetString("Label_GetExtents", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Get KML.
+        /// </summary>
+        internal static string Label_GetMapKml {
+            get {
+                return ResourceManager.GetString("Label_GetMapKml", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Tools.
+        /// </summary>
+        internal static string Label_Tools {
+            get {
+                return ResourceManager.GetString("Label_Tools", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Zoom to Scale.
+        /// </summary>
+        internal static string Label_ZoomToScale {
+            get {
+                return ResourceManager.GetString("Label_ZoomToScale", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to Preview Map.
+        /// </summary>
+        internal static string PreviewMap {
+            get {
+                return ResourceManager.GetString("PreviewMap", resourceCulture);
+            }
+        }
+        
+        /// <summary>
+        ///   Looks up a localized string similar to The site version of this current connection is not known to support watermarks.
+        /// </summary>
+        internal static string SiteVersionDoesntSupportWatermarks {
+            get {
+                return ResourceManager.GetString("SiteVersionDoesntSupportWatermarks", resourceCulture);
+            }
+        }
+    }
+}

Added: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.resx
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.resx	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Http/Strings.resx	2014-11-21 01:27:04 UTC (rev 8454)
@@ -0,0 +1,159 @@
+<?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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <data name="DebugWatermarkMessage" xml:space="preserve">
+    <value>MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}</value>
+  </data>
+  <data name="DebugWatermarkMessageLayer" xml:space="preserve">
+    <value>MapGuide Debugging Information\n==============================\n\nMap Extents Min: ({0}, {1})\nMap Extents Max: ({2}, {3})\nMap Coordinate System: \n{4}\nLayer Spatial Context: {5}</value>
+  </data>
+  <data name="Desc_GetExtents" xml:space="preserve">
+    <value>Displays the current map extents</value>
+  </data>
+  <data name="Desc_GetMapKml" xml:space="preserve">
+    <value>Gets the current map as a KML document</value>
+  </data>
+  <data name="Desc_ZoomToScale" xml:space="preserve">
+    <value>Zoom to a specified scale</value>
+  </data>
+  <data name="FailedToCalculateFeatureSourceExtents" xml:space="preserve">
+    <value>Could not calculate the extents of the Feature Source. Preview is not possible</value>
+  </data>
+  <data name="Label_ExtraTools" xml:space="preserve">
+    <value>Extra Tools</value>
+  </data>
+  <data name="Label_GetExtents" xml:space="preserve">
+    <value>Get Extents</value>
+  </data>
+  <data name="Label_GetMapKml" xml:space="preserve">
+    <value>Get KML</value>
+  </data>
+  <data name="Label_Tools" xml:space="preserve">
+    <value>Tools</value>
+  </data>
+  <data name="Label_ZoomToScale" xml:space="preserve">
+    <value>Zoom to Scale</value>
+  </data>
+  <data name="PreviewMap" xml:space="preserve">
+    <value>Preview Map</value>
+  </data>
+  <data name="SiteVersionDoesntSupportWatermarks" xml:space="preserve">
+    <value>The site version of this current connection is not known to support watermarks</value>
+  </data>
+</root>
\ No newline at end of file



More information about the mapguide-commits mailing list