[mapguide-commits] r8546 - in trunk/Tools/Maestro: Maestro.Base/Editor Maestro.Editors Maestro.Editors/MapDefinition Maestro.Editors/TileSetDefinition Maestro.LiveMapEditor MgCooker OSGeo.MapGuide.MaestroAPI/Mapping OSGeo.MapGuide.MaestroAPI/Resource/Validation OSGeo.MapGuide.MaestroAPI/Tile OSGeo.MapGuide.MaestroAPI.Tests/Mapping OSGeo.MapGuide.ObjectModel.Tests OSGeo.MapGuide.ObjectModels/MapDefinition OSGeo.MapGuide.ObjectModels/MapDefinition/v1_0_0 OSGeo.MapGuide.ObjectModels/MapDefinition/v2_3_0 OSGeo.MapGuide.ObjectModels/MapDefinition/v2_4_0 OSGeo.MapGuide.ObjectModels/MapDefinition/v3_0_0 OSGeo.MapGuide.ObjectModels/TileSetDefinition OSGeo.MapGuide.ObjectModels/TileSetDefinition/v3_0_0

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Feb 18 05:36:04 PST 2015


Author: jng
Date: 2015-02-18 05:36:04 -0800 (Wed, 18 Feb 2015)
New Revision: 8546

Added:
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/TileSetAbstractTests.cs
Modified:
   trunk/Tools/Maestro/Maestro.Base/Editor/MapDefinitionEditor.cs
   trunk/Tools/Maestro/Maestro.Editors/MapDefinition/ExtentCalculationDialog.cs
   trunk/Tools/Maestro/Maestro.Editors/MapDefinition/FiniteScaleListCtrl.cs
   trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs
   trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs
   trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapTreeModels.cs
   trunk/Tools/Maestro/Maestro.Editors/RepositoryIcons.cs
   trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs
   trunk/Tools/Maestro/Maestro.Editors/Strings.resx
   trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.Designer.cs
   trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.cs
   trunk/Tools/Maestro/Maestro.LiveMapEditor/MapSettingsDialog.cs
   trunk/Tools/Maestro/MgCooker/SetupRun.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/Mapping/RuntimeMapTests.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/BaseMapDefinitionValidator.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Tile/BatchSettings.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/OSGeo.MapGuide.ObjectModels.Tests.csproj
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/MapDefinitionInterfaces.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v1_0_0/MapDefinitionImpl.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_3_0/MapDefinitionImpl.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_4_0/MapDefinitionImpl.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v3_0_0/MapDefinitionImpl.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/TileSetInterfaces.cs
   trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/v3_0_0/TileSetImpl.cs
Log:
- #2515: Refactor the finite scale list editor to allow working against an ITileSetAbstract instance.
- #2515: Add extent editor (and auto-computation) to the Tile Set Definition editor.
- Refactor the Extent Computation dialog to allow working against both Map Definition and Tile Set Definition editors
- More ITileSetAbstract interface cleanup
- Move previous IBaseMapDefinition extension methods to work against ITileSetAbstract instead
- Add missing tile set icon in resource picker



Modified: trunk/Tools/Maestro/Maestro.Base/Editor/MapDefinitionEditor.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Base/Editor/MapDefinitionEditor.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Base/Editor/MapDefinitionEditor.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -26,6 +26,7 @@
 using OSGeo.MapGuide.MaestroAPI.Resource;
 using OSGeo.MapGuide.ObjectModels;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System.ComponentModel;
 using System.Drawing;
 using System.Windows.Forms;

Modified: trunk/Tools/Maestro/Maestro.Editors/MapDefinition/ExtentCalculationDialog.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/MapDefinition/ExtentCalculationDialog.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/MapDefinition/ExtentCalculationDialog.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -26,6 +26,7 @@
 using OSGeo.MapGuide.ObjectModels.LayerDefinition;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
 using System;
+using System.Linq;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Windows.Forms;
@@ -37,26 +38,26 @@
     /// </summary>
     public partial class ExtentCalculationDialog : Form
     {
-        private IMapDefinition _mdf;
+        private string _coordSys;
+        private Func<IEnumerable<string>> _layerIdCollector;
         private IServerConnection _conn;
 
+        private IList<string> _layerIdsToProcess;
+
         /// <summary>
         /// Initializes a new instance of the <see cref="ExtentCalculationDialog"/> class.
         /// </summary>
         /// <param name="mdf">The Map Definition</param>
         /// <param name="conn">The server connection</param>
-        public ExtentCalculationDialog(IMapDefinition mdf, IServerConnection conn)
+        /// <param name="layerIdCollector"></param>
+        public ExtentCalculationDialog(IServerConnection conn, string coordinateSystem, Func<IEnumerable<string>> layerIdCollector)
         {
             InitializeComponent();
-            _mdf = mdf;
+            _coordSys = coordinateSystem;
+            _layerIdCollector = layerIdCollector;
             _conn = conn;
             grdCalculations.DataSource = _results;
-
-            prgCalculations.Maximum = mdf.GetLayerCount();
-            if (mdf.BaseMap != null)
-                prgCalculations.Maximum += GetLayerCount(mdf.BaseMap);
-
-            txtCoordinateSystem.Text = mdf.CoordinateSystem;
+            txtCoordinateSystem.Text = _coordSys;
         }
 
         private int GetLayerCount(IBaseMapDefinition baseMap)
@@ -78,6 +79,8 @@
         /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
         protected override void OnLoad(EventArgs e)
         {
+            _layerIdsToProcess = _layerIdCollector().Distinct().ToList();
+            prgCalculations.Maximum = _layerIdsToProcess.Count;
             bgCalculation.RunWorkerAsync();
         }
 
@@ -141,27 +144,14 @@
 
         private void bgCalculation_DoWork(object sender, DoWorkEventArgs e)
         {
-            var mdf = _mdf;
             var resSvc = _conn.ResourceService;
 
             //Accumulate layers
             Dictionary<string, ILayerDefinition> layers = new Dictionary<string, ILayerDefinition>();
-            foreach (var lyr in mdf.MapLayer)
+            foreach (var ldfId in _layerIdsToProcess)
             {
-                if (!layers.ContainsKey(lyr.ResourceId))
-                    layers.Add(lyr.ResourceId, (ILayerDefinition)resSvc.GetResource(lyr.ResourceId));
+                layers.Add(ldfId, (ILayerDefinition)resSvc.GetResource(ldfId));
             }
-            if (mdf.BaseMap != null)
-            {
-                foreach (var group in mdf.BaseMap.BaseMapLayerGroups)
-                {
-                    foreach (var layer in group.BaseMapLayer)
-                    {
-                        if (!layers.ContainsKey(layer.ResourceId))
-                            layers.Add(layer.ResourceId, (ILayerDefinition)resSvc.GetResource(layer.ResourceId));
-                    }
-                }
-            }
 
             Check.ArgumentNotNull(layers, "layers");
             int processed = 0;
@@ -180,13 +170,13 @@
                 res.CoordinateSystem = wkt;
 
                 bool tx = false;
-                if (wkt != mdf.CoordinateSystem)
+                if (wkt != _coordSys)
                 {
                     tx = true;
                     //Transform if not the same, otherwise assume either arbitrary or same as the map
                     if (!string.IsNullOrEmpty(wkt))
                     {
-                        e1 = Utility.TransformEnvelope(e1, wkt, mdf.CoordinateSystem);
+                        e1 = Utility.TransformEnvelope(e1, wkt, _coordSys);
                         res.TransformedResult = e1;
                     }
                 }

Modified: trunk/Tools/Maestro/Maestro.Editors/MapDefinition/FiniteScaleListCtrl.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/MapDefinition/FiniteScaleListCtrl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/MapDefinition/FiniteScaleListCtrl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -22,7 +22,9 @@
 
 using Maestro.Shared.UI;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System;
+using System.Linq;
 using System.ComponentModel;
 using System.Windows.Forms;
 
@@ -46,18 +48,18 @@
 
         private BindingList<double> _scales;
 
-        private IMapDefinition _map;
+        private ITileSetAbstract _tileSet;
         private IEditorService _edSvc;
 
-        public FiniteScaleListCtrl(IMapDefinition map, IEditorService editorSvc)
+        public FiniteScaleListCtrl(ITileSetAbstract map, IEditorService editorSvc)
             : this()
         {
-            _map = map;
+            _tileSet = map;
             _edSvc = editorSvc;
             //Init scale list
-            if (_map.BaseMap != null)
+            if (_tileSet != null)
             {
-                foreach (var scale in _map.BaseMap.FiniteDisplayScale)
+                foreach (var scale in _tileSet.FiniteDisplayScale)
                 {
                     _scales.Add(scale);
                 }
@@ -66,6 +68,28 @@
             _scales.ListChanged += new ListChangedEventHandler(OnScaleListChanged);
         }
 
+        private IMapDefinition _parent;
+
+        public FiniteScaleListCtrl(IMapDefinition parent, IEditorService editorSvc)
+            : this()
+        {
+            _parent = parent;
+            _parent.InitBaseMap();
+
+            _tileSet = _parent.BaseMap;
+            _edSvc = editorSvc;
+            //Init scale list
+            if (_tileSet != null)
+            {
+                foreach (var scale in _tileSet.FiniteDisplayScale)
+                {
+                    _scales.Add(scale);
+                }
+            }
+            //Now wire change events
+            _scales.ListChanged += new ListChangedEventHandler(OnScaleListChanged);
+        }
+
         private void OnScaleListChanged(object sender, ListChangedEventArgs e)
         {
             switch (e.ListChangedType)
@@ -86,22 +110,26 @@
 
         private void ClearScales()
         {
-            _map.InitBaseMap();
-            _map.RemoveAllFiniteDisplayScales(true);
+            _tileSet.RemoveAllScales();
+            if (_parent != null)
+                _parent.RemoveBaseMap();
             _edSvc.MarkDirty();
         }
 
         private void RemoveScaleFromMap(double scale)
         {
             _scales.Remove(scale);
-            _map.RemoveFiniteDisplayScale(scale, true);
+            _tileSet.RemoveFiniteDisplayScale(scale);
+            if (_parent != null && _tileSet.ScaleCount == 0)
+                _parent.RemoveBaseMap();
             _edSvc.MarkDirty();
         }
 
         private void AddScaleToMap(double scale)
         {
-            _map.InitBaseMap();
-            _map.AddFiniteDisplayScale(scale);
+            if (_parent != null && _parent.BaseMap == null)
+                _parent.AttachBaseMap((IBaseMapDefinition)_tileSet);
+            _tileSet.AddFiniteDisplayScale(scale);
             _edSvc.MarkDirty();
         }
 
@@ -162,7 +190,7 @@
                     using (new WaitCursor(this))
                     {
                         _scales.Clear();
-                        foreach (double scale in dlg.Scales)
+                        foreach (double scale in dlg.Scales.OrderBy(s => s))
                         {
                             _scales.Add(scale);
                         }

Modified: trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -1163,7 +1163,7 @@
         {
             _map.InitBaseMap();
             var grp = _map.BaseMap.AddBaseLayerGroup(GenerateBaseGroupName(_map));
-            _tiledLayerModel.Invalidate();
+            _tiledLayerModel.Invalidate(_map.BaseMap);
         }
 
         private void btnRemoveBaseLayerGroup_Click(object sender, EventArgs e)
@@ -1454,6 +1454,7 @@
         private void OnFiniteScaleListSelected()
         {
             propertiesPanel.Controls.Clear();
+            _map.InitBaseMap();
             var item = new FiniteScaleListCtrl(_map, _edSvc);
 
             item.Dock = DockStyle.Fill;
@@ -1467,9 +1468,7 @@
             btnBaseLayerGroupToRegular.Enabled = true;
 
             propertiesPanel.Controls.Clear();
-            //var item = new GroupPropertiesCtrl(_map, group.Tag);
-            //item.GroupChanged += (s, evt) => { OnResourceChanged(); };
-            //item.Dock = DockStyle.Fill;
+
             _activeLayer = null;
             AddBaseGroupControl(group);
         }
@@ -1481,9 +1480,6 @@
             btnMoveBaseLayerUp.Enabled = true;
             btnBaseLayerGroupToRegular.Enabled = false;
 
-            //var item = new LayerPropertiesCtrl(layer.Tag, _edSvc.ResourceService, _edSvc);
-            //item.LayerChanged += (s, evt) => { OnResourceChanged(); };
-            //item.Dock = DockStyle.Fill;
             _activeLayer = null;
             AddBaseLayerControl(layer);
         }
@@ -2118,12 +2114,24 @@
             {
                 if (picker.ShowDialog() == DialogResult.OK )
                 {
+                    var tsd = (ITileSetDefinition)_edSvc.CurrentConnection.ResourceService.GetResource(picker.ResourceID);
+                    if (tsd.TileStoreParameters.TileProvider != "Default") //NOXLATE
+                    {
+                        MessageBox.Show(string.Format(Maestro.Editors.Strings.CannotLinkIncompatibleTileSet, tsd.TileStoreParameters.TileProvider));
+                        return;
+                    }
                     txtTileSet.Text = picker.ResourceID;
-
-                    var tsd = (ITileSetDefinition)_edSvc.CurrentConnection.ResourceService.GetResource(picker.ResourceID);
                     string coordSys = tsd.GetDefaultCoordinateSystem();
                     if (!string.IsNullOrEmpty(coordSys))
+                    {
+                        //Update Map Definition's CS and extents to match that from the tile set. Note that this has no real
+                        //ramifications. Internally the Tile Set's CS and extents will be used anyway, this is just a way to
+                        //communicate to the user that the Tile Set's CS and extents take precedence.
                         _map.CoordinateSystem = coordSys;
+                        var env = tsd.Extents;
+                        _map.SetExtents(env.MinX, env.MinY, env.MaxX, env.MaxY);
+                        MessageBox.Show(Maestro.Editors.Strings.LinkedTileSetNote);
+                    }
                 }
             }
         }

Modified: trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -25,6 +25,7 @@
 using OSGeo.MapGuide.MaestroAPI;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
 using System;
+using System.Collections.Generic;
 using System.ComponentModel;
 using System.Globalization;
 using System.Windows.Forms;
@@ -234,9 +235,29 @@
             }
         }
 
+        private IEnumerable<string> CollectLayerIds()
+        {
+            HashSet<string> ids = new HashSet<string>();
+            foreach (var layer in _map.MapLayer)
+            {
+                ids.Add(layer.ResourceId);
+            }
+            if (_map.BaseMap != null)
+            {
+                foreach (var grp in _map.BaseMap.BaseMapLayerGroups)
+                {
+                    foreach (var layer in grp.BaseMapLayer)
+                    {
+                        ids.Add(layer.ResourceId);
+                    }
+                }
+            }
+            return ids;
+        }
+
         private void btnSetZoom_Click(object sender, EventArgs e)
         {
-            var diag = new ExtentCalculationDialog(_map, _service.CurrentConnection);
+            var diag = new ExtentCalculationDialog(_service.CurrentConnection, _map.CoordinateSystem, CollectLayerIds);
             if (diag.ShowDialog() == DialogResult.OK)
             {
                 var env = diag.Extents;

Modified: trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapTreeModels.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapTreeModels.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/MapDefinition/MapTreeModels.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -281,18 +281,13 @@
             {
                 if (_tileSet != null)
                 {
-                    if (_tileSet.SupportsCustomFiniteDisplayScales)
+                    if (_tileSet.SupportsCustomFiniteDisplayScalesUnconditionally)
                         yield return new ScaleItem(Strings.FiniteDisplayScales, new List<double>(_tileSet.FiniteDisplayScale));
                     foreach (var grp in _tileSet.BaseMapLayerGroups)
                     {
                         yield return new BaseLayerGroupItem(grp);
                     }
                 }
-                else
-                {
-                    if (_tileSet.SupportsCustomFiniteDisplayScales)
-                        yield return new ScaleItem(Strings.FiniteDisplayScales, new List<double>());
-                }
             }
             else
             {
@@ -315,5 +310,11 @@
             var grp = treePath.LastNode as BaseLayerGroupItem;
             return grp == null;
         }
+
+        internal void Invalidate(ITileSetAbstract tileSet)
+        {
+            _tileSet = tileSet;
+            base.Invalidate();
+        }
     }
 }
\ No newline at end of file

Modified: trunk/Tools/Maestro/Maestro.Editors/RepositoryIcons.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/RepositoryIcons.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/RepositoryIcons.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -101,6 +101,11 @@
         public const int RES_FOLDER = 13;
 
         /// <summary>
+        /// Icon for tile sets
+        /// </summary>
+        public const int RES_TILESET = 14;
+
+        /// <summary>
         /// Gets the image icon index for the given resource type
         /// </summary>
         /// <param name="resType">Type of the resource.</param>
@@ -145,6 +150,9 @@
                 case "WebLayout":
                     return RES_WEBLAYOUT;
 
+                case "TileSetDefinition":
+                    return RES_TILESET;
+
                 default:
                     throw new ArgumentException();
             }
@@ -183,6 +191,7 @@
             imgList.Images.Add(Properties.Resources.script__arrow);
             imgList.Images.Add(Properties.Resources.server);
             imgList.Images.Add(Properties.Resources.folder_horizontal);
+            imgList.Images.Add(Properties.Resources.grid);
         }
     }
 }
\ No newline at end of file

Modified: trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/Strings.Designer.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -142,6 +142,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to You cannot link to a tile set that does not use the default provider. Your selected tile set uses the provider: {0}.
+        /// </summary>
+        internal static string CannotLinkIncompatibleTileSet {
+            get {
+                return ResourceManager.GetString("CannotLinkIncompatibleTileSet", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Ensure the Geometry box is checked.
         /// </summary>
         internal static string CheckGeometryFirst {
@@ -1841,6 +1850,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to The Map Definition's coordinate system and extents have been replaced with the ones from the linked tile set.
+        /// </summary>
+        internal static string LinkedTileSetNote {
+            get {
+                return ResourceManager.GetString("LinkedTileSetNote", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Loading Feature Classes.
         /// </summary>
         internal static string LoadingFeatureClasses {

Modified: trunk/Tools/Maestro/Maestro.Editors/Strings.resx
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/Strings.resx	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/Strings.resx	2015-02-18 13:36:04 UTC (rev 8546)
@@ -138,6 +138,15 @@
   <data name="BetweenLabel" xml:space="preserve">
     <value>Between {0} and {1}</value>
   </data>
+  <data name="CannotCreateThemeForCompositeStyleClassicEditor" xml:space="preserve">
+    <value>Theming composite styles with this editor is not supported</value>
+  </data>
+  <data name="CannotCreateThemeFromCompoundSymbolInstance" xml:space="preserve">
+    <value>Creating themes from a Composite Rule with a Compound Symbol is not supported</value>
+  </data>
+  <data name="CannotLinkIncompatibleTileSet" xml:space="preserve">
+    <value>You cannot link to a tile set that does not use the default provider. Your selected tile set uses the provider: {0}</value>
+  </data>
   <data name="CheckGeometryFirst" xml:space="preserve">
     <value>Ensure the Geometry box is checked</value>
   </data>
@@ -150,6 +159,9 @@
   <data name="CmsBingStreet" xml:space="preserve">
     <value>Bing Maps Street</value>
   </data>
+  <data name="CmsGeneric" xml:space="preserve">
+    <value>Generic Layer</value>
+  </data>
   <data name="CmsGoogleHybrid" xml:space="preserve">
     <value>Google Hybrid</value>
   </data>
@@ -171,6 +183,15 @@
   <data name="CmsOsmTransport" xml:space="preserve">
     <value>Open Street Map (TransportMap)</value>
   </data>
+  <data name="CmsStamenTerrain" xml:space="preserve">
+    <value>Stamen (Terrain)</value>
+  </data>
+  <data name="CmsStamenToner" xml:space="preserve">
+    <value>Stamen (Toner)</value>
+  </data>
+  <data name="CmsStamenWaterColor" xml:space="preserve">
+    <value>Stamen (WaterColor)</value>
+  </data>
   <data name="CmsYahooHybrid" xml:space="preserve">
     <value>Yahoo! Maps Hybrid</value>
   </data>
@@ -583,6 +604,12 @@
 </CommandTypesDataset>
 </value>
   </data>
+  <data name="CompositeThemeRequiresFirstRuleAsTemplate" xml:space="preserve">
+    <value>Generating a theme for a composite style, requires a composite rule</value>
+  </data>
+  <data name="ComputingThemeParameters" xml:space="preserve">
+    <value>Computing Theme Parameters ...</value>
+  </data>
   <data name="ConfigurationDocumentReset" xml:space="preserve">
     <value>Configuration Document has been reset</value>
   </data>
@@ -595,6 +622,12 @@
   <data name="ConfirmGoogleScaleList" xml:space="preserve">
     <value>Are you sure you want to use a Google-compatible Scale List? This will overwrite your existing scale ranges and will only line up with commercial layers in Fusion if your Map's Coordinate System is WGS84.PseudoMercator</value>
   </data>
+  <data name="ConfirmNonMapGuideSupportedCsWkt" xml:space="preserve">
+    <value>The WKT you entered is not recognised by MapGuide's Coordinate System Library. Use it anyway?</value>
+  </data>
+  <data name="ConfirmWmsLogicalClassSwap" xml:space="preserve">
+    <value>In some cases, the actual WMS layer name would be generated in the FDO class description. Swap FDO logical class names with their descriptions?</value>
+  </data>
   <data name="ContentFileMissing" xml:space="preserve">
     <value>The content file does not exist</value>
   </data>
@@ -610,6 +643,12 @@
   <data name="DataReadError" xml:space="preserve">
     <value>Unable to read data from the selected column: {0}</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="DeleteCommand" xml:space="preserve">
     <value>Delete Command</value>
   </data>
@@ -619,6 +658,9 @@
   <data name="DivergingName" xml:space="preserve">
     <value>Diverging</value>
   </data>
+  <data name="EditSymbolDefinition" xml:space="preserve">
+    <value>Edit Symbol Definition</value>
+  </data>
   <data name="EditWatermarkInstance" xml:space="preserve">
     <value>Edit Watermark Instance</value>
   </data>
@@ -628,6 +670,9 @@
   <data name="ErrNotAFolder" xml:space="preserve">
     <value>Not a folder</value>
   </data>
+  <data name="ErrorExplodingCompositeStyleNotSupported" xml:space="preserve">
+    <value>Exploding Composite Styles is not currently supported</value>
+  </data>
   <data name="ErrorInvalidSymbolLibraryResourceId" xml:space="preserve">
     <value>Not a valid symbol library resource identifier: {0}</value>
   </data>
@@ -646,18 +691,60 @@
   <data name="ExportNoCustomCommandsSelected" xml:space="preserve">
     <value>No custom commands selected. Nothing to export</value>
   </data>
+  <data name="ExprDispBoolean" xml:space="preserve">
+    <value>Boolean: {0}</value>
+  </data>
+  <data name="ExprDispDateTime" xml:space="preserve">
+    <value>DateTime: {0}</value>
+  </data>
+  <data name="ExprDispDouble" xml:space="preserve">
+    <value>Double: {0}</value>
+  </data>
+  <data name="ExprDispFunction" xml:space="preserve">
+    <value>Function: {0}</value>
+  </data>
+  <data name="ExprDispGeometry" xml:space="preserve">
+    <value>Geometry: {0}</value>
+  </data>
+  <data name="ExprDispIdentifier" xml:space="preserve">
+    <value>Identifier: {0}</value>
+  </data>
+  <data name="ExprDispInt32" xml:space="preserve">
+    <value>Int32: {0}</value>
+  </data>
+  <data name="ExprDispParameter" xml:space="preserve">
+    <value>Parameter: {0}</value>
+  </data>
+  <data name="ExprDispString" xml:space="preserve">
+    <value>String: '{0}'</value>
+  </data>
+  <data name="ExprDispUnaryExpr" xml:space="preserve">
+    <value>Unary Expression (Negated)</value>
+  </data>
+  <data name="ExprEditorFunctionDesc" xml:space="preserve">
+    <value>{0}{4}Description:{1}{4}Arguments:{2}{4}Returns: {3}</value>
+  </data>
   <data name="ExpressionItem" xml:space="preserve">
     <value>Expression...</value>
   </data>
+  <data name="ExprIsValid" xml:space="preserve">
+    <value>Expression is valid</value>
+  </data>
   <data name="ExtendedClassTooltip" xml:space="preserve">
     <value>Extended class based on: {0}</value>
   </data>
+  <data name="ExtendedFeatureClassAlreadyExists" xml:space="preserve">
+    <value>An extended feature class named ({0}) already exist. Please choose a different name</value>
+  </data>
   <data name="ExtentsCalculationCompleted" xml:space="preserve">
     <value>Map extents calculation completed. Click Accept to use the calculated extents.</value>
   </data>
   <data name="ExtentsTransformationFailed" xml:space="preserve">
     <value>Could not transform extent of layer {0} to the map definition's coordinate system. Extents ignored</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="FailEnumDataStores" xml:space="preserve">
     <value>Failed to enumerate data stores. Reason: {0}</value>
   </data>
@@ -667,6 +754,45 @@
   <data name="FdoConnectionStringComponentNotFound" xml:space="preserve">
     <value>The component "{0}" could not be found in the specified FDO connection string</value>
   </data>
+  <data name="FdoDispDistanceCondition" xml:space="preserve">
+    <value>Distance ({0})</value>
+  </data>
+  <data name="FdoDispDistanceTitle" xml:space="preserve">
+    <value>Distance</value>
+  </data>
+  <data name="FdoDispExprTitle" xml:space="preserve">
+    <value>Expression</value>
+  </data>
+  <data name="FdoDispIdentifierTitle" xml:space="preserve">
+    <value>Identifier</value>
+  </data>
+  <data name="FdoDispInCondition" xml:space="preserve">
+    <value>In Condition ({0})</value>
+  </data>
+  <data name="FdoDispNullCondition" xml:space="preserve">
+    <value>Null Condition ({0})</value>
+  </data>
+  <data name="FdoDispSpatialCondition" xml:space="preserve">
+    <value>Spatial Condition ({0})</value>
+  </data>
+  <data name="FdoDispUnaryOperator" xml:space="preserve">
+    <value>Unary Operator (NOT)</value>
+  </data>
+  <data name="FeatureClassNotFound" xml:space="preserve">
+    <value>Feature Class not found: {0}</value>
+  </data>
+  <data name="FeatureNotImplemented" xml:space="preserve">
+    <value>This feature is not implemented yet</value>
+  </data>
+  <data name="FetchingClassDefinition" xml:space="preserve">
+    <value>Fetching Class Definition</value>
+  </data>
+  <data name="FetchingClassNames" xml:space="preserve">
+    <value>Fetching Class Names</value>
+  </data>
+  <data name="FetchingSchemaNames" xml:space="preserve">
+    <value>Fetching Schema Names</value>
+  </data>
   <data name="FieldRequired" xml:space="preserve">
     <value>This field is required: {0}</value>
   </data>
@@ -688,6 +814,9 @@
   <data name="FiletypeZip" xml:space="preserve">
     <value>Zip files ({0})</value>
   </data>
+  <data name="FilterIsValid" xml:space="preserve">
+    <value>Filter is valid</value>
+  </data>
   <data name="FindEmptyString" xml:space="preserve">
     <value>Cannot Find an Empty String</value>
   </data>
@@ -700,6 +829,18 @@
   <data name="FiniteDisplayScales" xml:space="preserve">
     <value>Finite Display Scales</value>
   </data>
+  <data name="FltrDispBinaryLogicalOperator" xml:space="preserve">
+    <value>Binary Logical Operator ({0})</value>
+  </data>
+  <data name="FltrDispComparisonCondition" xml:space="preserve">
+    <value>Comparison ({0})</value>
+  </data>
+  <data name="FltrDispLeftNode" xml:space="preserve">
+    <value>Left</value>
+  </data>
+  <data name="FltrDispRightNode" xml:space="preserve">
+    <value>Right</value>
+  </data>
   <data name="FolderMissingPrefix" xml:space="preserve">
     <value>The folder must start with \"Library://\", do you want the starting folder to become:\n {0} ?</value>
   </data>
@@ -718,6 +859,9 @@
   <data name="FsPreview_DataPropertyNodeTooltip" xml:space="preserve">
     <value>Name: {0}{8}Description: {1}{8}Data Type: {2}{8}Nullable: {3}{8}Read Only: {4}{8}Length: {5}{8}Precision: {6}{8}Scale: {7}</value>
   </data>
+  <data name="FsPreview_GenericPropertyTooltip" xml:space="preserve">
+    <value>Property: {0}{2}Type: {1}</value>
+  </data>
   <data name="FsPreview_GeometryPropertyNodeTooltip" xml:space="preserve">
     <value>Name: {0}{7}Description: {1}{7}Geometry Types: {2}{7}Read Only: {3}{7}Has Elevation: {4}{7}Has Measure: {5}{7}Spatial Context: {6}</value>
   </data>
@@ -727,6 +871,93 @@
   <data name="FsSqlServerSpatial" xml:space="preserve">
     <value>SQL Server Spatial Feature Source</value>
   </data>
+  <data name="Func_ARGB_AValueDescription" xml:space="preserve">
+    <value>Alpha value</value>
+  </data>
+  <data name="Func_ARGB_BValueDescription" xml:space="preserve">
+    <value>Blue value</value>
+  </data>
+  <data name="Func_ARGB_Description" xml:space="preserve">
+    <value>Color generation function</value>
+  </data>
+  <data name="Func_ARGB_GValueDescription" xml:space="preserve">
+    <value>Green value</value>
+  </data>
+  <data name="Func_ARGB_RValueDescription" xml:space="preserve">
+    <value>Red value</value>
+  </data>
+  <data name="Func_DECAP_Description" xml:space="preserve">
+    <value>String formatting function</value>
+  </data>
+  <data name="Func_DECAP_StringValueDescription" xml:space="preserve">
+    <value>String to format</value>
+  </data>
+  <data name="Func_FEATURECLASS_Description" xml:space="preserve">
+    <value>Returns the active feature class name</value>
+  </data>
+  <data name="Func_FEATUREID_Description" xml:space="preserve">
+    <value>Returns the active feature Id</value>
+  </data>
+  <data name="Func_IF_ConditionDescription" xml:space="preserve">
+    <value>Boolean expression (filter) encapsulated in a string</value>
+  </data>
+  <data name="Func_IF_Description" xml:space="preserve">
+    <value>If evaluator for style theming</value>
+  </data>
+  <data name="Func_IF_FalseValueDescription" xml:space="preserve">
+    <value>Returned if condition is false</value>
+  </data>
+  <data name="Func_IF_TrueValueDescription" xml:space="preserve">
+    <value>Returned if condition is true</value>
+  </data>
+  <data name="Func_LAYERID_Description" xml:space="preserve">
+    <value>Returns the active layer Id</value>
+  </data>
+  <data name="Func_LOOKUP_DefaultValueDescription" xml:space="preserve">
+    <value>Default value returned if expression does not evaluate to any of the keys</value>
+  </data>
+  <data name="Func_LOOKUP_Description" xml:space="preserve">
+    <value>Lookup table for style theming</value>
+  </data>
+  <data name="Func_LOOKUP_ExpressionDescription" xml:space="preserve">
+    <value>Key expression</value>
+  </data>
+  <data name="Func_LOOKUP_IndexDescription" xml:space="preserve">
+    <value>Lookup index that can be matched by the key expression</value>
+  </data>
+  <data name="Func_LOOKUP_ValueDescription" xml:space="preserve">
+    <value>Value that is returned when the key expression matches the associated index</value>
+  </data>
+  <data name="Func_MAPNAME_Description" xml:space="preserve">
+    <value>Returns the active map name</value>
+  </data>
+  <data name="Func_RANGE_DefaultValueDescription" xml:space="preserve">
+    <value>Default value returned if expression does not fall into any of the ranges</value>
+  </data>
+  <data name="Func_RANGE_Description" xml:space="preserve">
+    <value>Range table for style theming</value>
+  </data>
+  <data name="Func_RANGE_ExpressionDescription" xml:space="preserve">
+    <value>Key expression</value>
+  </data>
+  <data name="Func_RANGE_MaxDescription" xml:space="preserve">
+    <value>Exclusive maximum of range that can be matched by the key expression</value>
+  </data>
+  <data name="Func_RANGE_MinDescription" xml:space="preserve">
+    <value>Inclusive minimum of range that can be matched by the key expression</value>
+  </data>
+  <data name="Func_RANGE_ValueDescription" xml:space="preserve">
+    <value>Value that is returned when the key expression matches the associated range</value>
+  </data>
+  <data name="Func_SESSION_Description" xml:space="preserve">
+    <value>Returns the active session</value>
+  </data>
+  <data name="Func_URLENCODE_Description" xml:space="preserve">
+    <value>String encoding function</value>
+  </data>
+  <data name="Func_URLENCODE_StringValueDescription" xml:space="preserve">
+    <value>String to URL encode</value>
+  </data>
   <data name="FunctionTooltip" xml:space="preserve">
     <value>Function: {1}({2})
 Description: {3}
@@ -894,6 +1125,9 @@
   <data name="GeomFilterTemplate" xml:space="preserve">
     <value><geometry property> {0} GeomFromText('<FGF geometry text>')</value>
   </data>
+  <data name="GroupAlreadyExists" xml:space="preserve">
+    <value>A group named "{0}" already exists. Choose a different name</value>
+  </data>
   <data name="HeaderFileMissing" xml:space="preserve">
     <value>The header file does not exist</value>
   </data>
@@ -921,12 +1155,30 @@
   <data name="InvalidConnection" xml:space="preserve">
     <value>This is not a valid connection: {0}</value>
   </data>
+  <data name="InvalidExpressionPropertyNotFound" xml:space="preserve">
+    <value>Invalid Expression. Property not found: {0}</value>
+  </data>
+  <data name="InvalidExpressionUnsupportedFunction" xml:space="preserve">
+    <value>Invalid Expression. Function not supported: {0}</value>
+  </data>
   <data name="InvalidFeatureSourceNoClasses" xml:space="preserve">
     <value>Feature Source ({0}) has no usable feature classes. Choose a different feature source</value>
   </data>
   <data name="InvalidFieldCountError" xml:space="preserve">
     <value>Invalid field count in line {0}</value>
   </data>
+  <data name="InvalidFilterUnsupportedConditionType" xml:space="preserve">
+    <value>Invalid Filter. Unsupported condition type: {0}</value>
+  </data>
+  <data name="InvalidFilterUnsupportedDistanceOperator" xml:space="preserve">
+    <value>Invalid Filter. Unsupported distance operator: {0}</value>
+  </data>
+  <data name="InvalidFilterUnsupportedSpatialOperator" xml:space="preserve">
+    <value>Invalid Filter. Unsupported spatial operator: {0}</value>
+  </data>
+  <data name="InvalidLayerNameFormat" xml:space="preserve">
+    <value>Invalid Layer Name Format. Name must have both {0} and {1} format markers</value>
+  </data>
   <data name="InvalidRecordCountError" xml:space="preserve">
     <value>Invalid record count in line {0}</value>
   </data>
@@ -957,18 +1209,54 @@
   <data name="LastUpdated" xml:space="preserve">
     <value>Last Updated: </value>
   </data>
+  <data name="LayerAlreadyAtBottomOfGroup" xml:space="preserve">
+    <value>The selected layer is already at the bottom of its group</value>
+  </data>
+  <data name="LayerAlreadyAtTopOfGroup" xml:space="preserve">
+    <value>The selected layer is already at the top of its group</value>
+  </data>
+  <data name="LayerChangedFeatureClass" xml:space="preserve">
+    <value>You have changed the Feature Class for this layer. Styles made for the previous Feature Class may no longer be applicable to this Feature Class. You should review such style settings (eg. Settings involving FDO expressions) to see if anything needs to be changed.</value>
+  </data>
+  <data name="LayerEditorFeatureClassNotFound" xml:space="preserve">
+    <value>Feature Class Not Found</value>
+  </data>
+  <data name="LayerEditorFeatureSourceNotFound" xml:space="preserve">
+    <value>Feature Source Not Found</value>
+  </data>
+  <data name="LayerEditorGeometryNotFound" xml:space="preserve">
+    <value>Geometry Property Not Found</value>
+  </data>
+  <data name="LayerEditorHasErrors" xml:space="preserve">
+    <value>Found errors in the Layer Definition. Please check any errors flagged in the editor.</value>
+  </data>
   <data name="LayerGroupConvertedToBaseLayerGroup" xml:space="preserve">
     <value>Layer Group ({0}) successfully converted to Base Layer Group ({1})</value>
   </data>
   <data name="LessThanLabel" xml:space="preserve">
     <value>Less than {0}</value>
   </data>
+  <data name="LoadingFeatureClasses" xml:space="preserve">
+    <value>Loading Feature Classes</value>
+  </data>
   <data name="LoadProcedureVersionExecutionNotSupported" xml:space="preserve">
     <value>This connection does not support executing this type of Load Procedure</value>
   </data>
   <data name="MapUpdatedToUseGroup" xml:space="preserve">
     <value>Map widget has been updated to use the map group: {0}</value>
   </data>
+  <data name="MdfEditorExpandInLegend" xml:space="preserve">
+    <value>Expand In Legend</value>
+  </data>
+  <data name="MdfEditorSelectable" xml:space="preserve">
+    <value>Selectable</value>
+  </data>
+  <data name="MdfEditorShowInLegend" xml:space="preserve">
+    <value>Show In Legend</value>
+  </data>
+  <data name="MdfEditorVisible" xml:space="preserve">
+    <value>Visible</value>
+  </data>
   <data name="MissingColumnError" xml:space="preserve">
     <value>Missing column "{0}"</value>
   </data>
@@ -981,6 +1269,9 @@
   <data name="MoreThanLabel" xml:space="preserve">
     <value>More than {0}</value>
   </data>
+  <data name="MultiSigFunction" xml:space="preserve">
+    <value>{0} ({1} signatures)</value>
+  </data>
   <data name="NewFlyout" xml:space="preserve">
     <value>New Flyout</value>
   </data>
@@ -999,12 +1290,24 @@
   <data name="NoColumnValuesError" xml:space="preserve">
     <value>No values found in selected column</value>
   </data>
+  <data name="NoFeatureClassAssigned" xml:space="preserve">
+    <value>No Feature Class assigned</value>
+  </data>
   <data name="NoFolderSelected" xml:space="preserve">
     <value>You have not selected a starting folder, do you want to back up the entire site?</value>
   </data>
+  <data name="None" xml:space="preserve">
+    <value>None</value>
+  </data>
+  <data name="NonMapGuideSupportedCsWkt" xml:space="preserve">
+    <value>Non-supported WKT</value>
+  </data>
   <data name="NoRasterClasses" xml:space="preserve">
     <value>This feature source has no class definitions with raster properties</value>
   </data>
+  <data name="NoRegisteredPreviewerForProvider" xml:space="preserve">
+    <value>No registered previewer for connection: {0}</value>
+  </data>
   <data name="NoRestorePathWarning" xml:space="preserve">
     <value>You have selected to restore the package at another location, but not entered one.
 This will cause the package to be restored a the root of the resource tree.
@@ -1043,6 +1346,9 @@
   <data name="OdbcConnectionStringComponentNotFound" xml:space="preserve">
     <value>The component "{0}" could not be found in the specified ODBC connection string</value>
   </data>
+  <data name="OdbcConnStrMissingMgPlaceholders" xml:space="preserve">
+    <value>The ODBC connection string requires a %MG_USERNAME% and %MG_PASSWORD% placeholder tokens present</value>
+  </data>
   <data name="OdbcNoMarkedFile" xml:space="preserve">
     <value>Could not infer ODBC driver. No file specified</value>
   </data>
@@ -1052,6 +1358,9 @@
   <data name="OperationCompleted" xml:space="preserve">
     <value>Operation Completed</value>
   </data>
+  <data name="OptionsSyncedToDocument" xml:space="preserve">
+    <value>Options synced back to document</value>
+  </data>
   <data name="OutputFileMissing" xml:space="preserve">
     <value>You must enter a full path to the output file</value>
   </data>
@@ -1073,6 +1382,9 @@
   <data name="ParameterOverrideExists" xml:space="preserve">
     <value>Parameter Override already specified</value>
   </data>
+  <data name="PreviewMap" xml:space="preserve">
+    <value>Preview Map</value>
+  </data>
   <data name="PreviewQueryElapsed" xml:space="preserve">
     <value>Preview Completed in {0}ms</value>
   </data>
@@ -1082,6 +1394,9 @@
   <data name="PreviewUrlNotAvailable" xml:space="preserve">
     <value>The Preview URL is not currently available</value>
   </data>
+  <data name="PrgPreparingResourcePreview" xml:space="preserve">
+    <value>Preparing resource preview</value>
+  </data>
   <data name="ProcessedItem" xml:space="preserve">
     <value>Processed: {0}</value>
   </data>
@@ -1121,6 +1436,9 @@
   <data name="PropEnumNoValues" xml:space="preserve">
     <value>Could not find possible values for enumerable property</value>
   </data>
+  <data name="PropertyInfo" xml:space="preserve">
+    <value>Name: {1}{0}Identifier: {2}{0}Description: {3}{0}Type: {4}{0}Default Value: {5}</value>
+  </data>
   <data name="PropertyTooltip" xml:space="preserve">
     <value>Property: {0}
 Type: {1}</value>
@@ -1143,6 +1461,9 @@
 This will result in the entire repository being deleted and replaced with this package.
 Are you absolutely sure that is what you want?</value>
   </data>
+  <data name="Required" xml:space="preserve">
+    <value>Required</value>
+  </data>
   <data name="RequiredServiceNotSupported" xml:space="preserve">
     <value>This connection does not support required service: </value>
   </data>
@@ -1167,6 +1488,9 @@
   <data name="SelectColumnPlaceholder" xml:space="preserve">
     <value><Select column></value>
   </data>
+  <data name="SelectedItemCount" xml:space="preserve">
+    <value>{0} selected items</value>
+  </data>
   <data name="SelectFeatureClass" xml:space="preserve">
     <value>Select Feature Class</value>
   </data>
@@ -1185,6 +1509,9 @@
   <data name="SelectProperty" xml:space="preserve">
     <value>Select Property</value>
   </data>
+  <data name="SelectSourceResource" xml:space="preserve">
+    <value>Choose a resource for "Selected Resource" first</value>
+  </data>
   <data name="SelectSpatialContext" xml:space="preserve">
     <value>Select Spatial Context</value>
   </data>
@@ -1200,6 +1527,9 @@
   <data name="SequentialName" xml:space="preserve">
     <value>Sequential</value>
   </data>
+  <data name="SiteVersionDoesntSupportWatermarks" xml:space="preserve">
+    <value>The site version of this current connection is not known to support watermarks</value>
+  </data>
   <data name="SpatialContextsFound" xml:space="preserve">
     <value>{0} spatial contexts found</value>
   </data>
@@ -1281,6 +1611,15 @@
   <data name="TextUploading" xml:space="preserve">
     <value>Uploading</value>
   </data>
+  <data name="ThemeExpressionOnlySupportsIndividualValues" xml:space="preserve">
+    <value>Only individual values is supported when generating a theme expression</value>
+  </data>
+  <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="ThemingNotAVectorLayer" xml:space="preserve">
+    <value>The layer being themed is not a vector layer</value>
+  </data>
   <data name="TitleBufferUnits" xml:space="preserve">
     <value>Buffer Units</value>
   </data>
@@ -1343,12 +1682,18 @@
   <data name="UpdatingConfiguration" xml:space="preserve">
     <value>Updating Configuration Document</value>
   </data>
+  <data name="UpdatingStylePreviews" xml:space="preserve">
+    <value>Updating Style Previews</value>
+  </data>
   <data name="ValidateOutputfileError" xml:space="preserve">
     <value>An error occured while validating the output file path: {0}</value>
   </data>
   <data name="WarningMapExtentCalculation" xml:space="preserve">
     <value>Could not transform extents of one or more layers in this Map Definition. These extents have not been factored into the computed result.</value>
   </data>
+  <data name="WarningUnconfiguredWmsFeatureSource" xml:space="preserve">
+    <value>Your WMS Feature Source is not configured. An un-configured WMS Feature Source may not properly read layer information from your WMS Server. Click "Advanced" after testing your connection to build a default document.</value>
+  </data>
   <data name="WidgetNameExists" xml:space="preserve">
     <value>A widget named {0} already exists</value>
   </data>
@@ -1364,346 +1709,7 @@
   <data name="XmlEditorCursorTemplate" xml:space="preserve">
     <value>Line {0}, Column {1}</value>
   </data>
-  <data name="FeatureNotImplemented" xml:space="preserve">
-    <value>This feature is not implemented yet</value>
+  <data name="LinkedTileSetNote" xml:space="preserve">
+    <value>The Map Definition's coordinate system and extents have been replaced with the ones from the linked tile set</value>
   </data>
-  <data name="ErrorExplodingCompositeStyleNotSupported" xml:space="preserve">
-    <value>Exploding Composite Styles is not currently supported</value>
-  </data>
-  <data name="InvalidLayerNameFormat" xml:space="preserve">
-    <value>Invalid Layer Name Format. Name must have both {0} and {1} format markers</value>
-  </data>
-  <data name="ConfirmWmsLogicalClassSwap" xml:space="preserve">
-    <value>In some cases, the actual WMS layer name would be generated in the FDO class description. Swap FDO logical class names with their descriptions?</value>
-  </data>
-  <data name="FsPreview_GenericPropertyTooltip" xml:space="preserve">
-    <value>Property: {0}{2}Type: {1}</value>
-  </data>
-  <data name="ExprEditorFunctionDesc" xml:space="preserve">
-    <value>{0}{4}Description:{1}{4}Arguments:{2}{4}Returns: {3}</value>
-  </data>
-  <data name="Func_ARGB_AValueDescription" xml:space="preserve">
-    <value>Alpha value</value>
-  </data>
-  <data name="Func_ARGB_BValueDescription" xml:space="preserve">
-    <value>Blue value</value>
-  </data>
-  <data name="Func_ARGB_Description" xml:space="preserve">
-    <value>Color generation function</value>
-  </data>
-  <data name="Func_ARGB_GValueDescription" xml:space="preserve">
-    <value>Green value</value>
-  </data>
-  <data name="Func_ARGB_RValueDescription" xml:space="preserve">
-    <value>Red value</value>
-  </data>
-  <data name="Func_DECAP_Description" xml:space="preserve">
-    <value>String formatting function</value>
-  </data>
-  <data name="Func_DECAP_StringValueDescription" xml:space="preserve">
-    <value>String to format</value>
-  </data>
-  <data name="Func_FEATURECLASS_Description" xml:space="preserve">
-    <value>Returns the active feature class name</value>
-  </data>
-  <data name="Func_FEATUREID_Description" xml:space="preserve">
-    <value>Returns the active feature Id</value>
-  </data>
-  <data name="Func_IF_ConditionDescription" xml:space="preserve">
-    <value>Boolean expression (filter) encapsulated in a string</value>
-  </data>
-  <data name="Func_IF_Description" xml:space="preserve">
-    <value>If evaluator for style theming</value>
-  </data>
-  <data name="Func_IF_FalseValueDescription" xml:space="preserve">
-    <value>Returned if condition is false</value>
-  </data>
-  <data name="Func_IF_TrueValueDescription" xml:space="preserve">
-    <value>Returned if condition is true</value>
-  </data>
-  <data name="Func_LAYERID_Description" xml:space="preserve">
-    <value>Returns the active layer Id</value>
-  </data>
-  <data name="Func_LOOKUP_DefaultValueDescription" xml:space="preserve">
-    <value>Default value returned if expression does not evaluate to any of the keys</value>
-  </data>
-  <data name="Func_LOOKUP_Description" xml:space="preserve">
-    <value>Lookup table for style theming</value>
-  </data>
-  <data name="Func_LOOKUP_ExpressionDescription" xml:space="preserve">
-    <value>Key expression</value>
-  </data>
-  <data name="Func_LOOKUP_IndexDescription" xml:space="preserve">
-    <value>Lookup index that can be matched by the key expression</value>
-  </data>
-  <data name="Func_LOOKUP_ValueDescription" xml:space="preserve">
-    <value>Value that is returned when the key expression matches the associated index</value>
-  </data>
-  <data name="Func_MAPNAME_Description" xml:space="preserve">
-    <value>Returns the active map name</value>
-  </data>
-  <data name="Func_RANGE_DefaultValueDescription" xml:space="preserve">
-    <value>Default value returned if expression does not fall into any of the ranges</value>
-  </data>
-  <data name="Func_RANGE_Description" xml:space="preserve">
-    <value>Range table for style theming</value>
-  </data>
-  <data name="Func_RANGE_ExpressionDescription" xml:space="preserve">
-    <value>Key expression</value>
-  </data>
-  <data name="Func_RANGE_MaxDescription" xml:space="preserve">
-    <value>Exclusive maximum of range that can be matched by the key expression</value>
-  </data>
-  <data name="Func_RANGE_MinDescription" xml:space="preserve">
-    <value>Inclusive minimum of range that can be matched by the key expression</value>
-  </data>
-  <data name="Func_RANGE_ValueDescription" xml:space="preserve">
-    <value>Value that is returned when the key expression matches the associated range</value>
-  </data>
-  <data name="Func_SESSION_Description" xml:space="preserve">
-    <value>Returns the active session</value>
-  </data>
-  <data name="Func_URLENCODE_Description" xml:space="preserve">
-    <value>String encoding function</value>
-  </data>
-  <data name="Func_URLENCODE_StringValueDescription" xml:space="preserve">
-    <value>String to URL encode</value>
-  </data>
-  <data name="LoadingFeatureClasses" xml:space="preserve">
-    <value>Loading Feature Classes</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="PreviewMap" xml:space="preserve">
-    <value>Preview Map</value>
-  </data>
-  <data name="PrgPreparingResourcePreview" xml:space="preserve">
-    <value>Preparing resource preview</value>
-  </data>
-  <data name="SiteVersionDoesntSupportWatermarks" xml:space="preserve">
-    <value>The site version of this current connection is not known to support watermarks</value>
-  </data>
-  <data name="NoRegisteredPreviewerForProvider" xml:space="preserve">
-    <value>No registered previewer for connection: {0}</value>
-  </data>
-  <data name="FeatureClassNotFound" xml:space="preserve">
-    <value>Feature Class not found: {0}</value>
-  </data>
-  <data name="NoFeatureClassAssigned" xml:space="preserve">
-    <value>No Feature Class assigned</value>
-  </data>
-  <data name="LayerAlreadyAtBottomOfGroup" xml:space="preserve">
-    <value>The selected layer is already at the bottom of its group</value>
-  </data>
-  <data name="LayerAlreadyAtTopOfGroup" xml:space="preserve">
-    <value>The selected layer is already at the top of its group</value>
-  </data>
-  <data name="OdbcConnStrMissingMgPlaceholders" xml:space="preserve">
-    <value>The ODBC connection string requires a %MG_USERNAME% and %MG_PASSWORD% placeholder tokens present</value>
-  </data>
-  <data name="GroupAlreadyExists" xml:space="preserve">
-    <value>A group named "{0}" already exists. Choose a different name</value>
-  </data>
-  <data name="ExtendedFeatureClassAlreadyExists" xml:space="preserve">
-    <value>An extended feature class named ({0}) already exist. Please choose a different name</value>
-  </data>
-  <data name="ConfirmNonMapGuideSupportedCsWkt" xml:space="preserve">
-    <value>The WKT you entered is not recognised by MapGuide's Coordinate System Library. Use it anyway?</value>
-  </data>
-  <data name="NonMapGuideSupportedCsWkt" xml:space="preserve">
-    <value>Non-supported WKT</value>
-  </data>
-  <data name="MdfEditorExpandInLegend" xml:space="preserve">
-    <value>Expand In Legend</value>
-  </data>
-  <data name="MdfEditorSelectable" xml:space="preserve">
-    <value>Selectable</value>
-  </data>
-  <data name="MdfEditorShowInLegend" xml:space="preserve">
-    <value>Show In Legend</value>
-  </data>
-  <data name="MdfEditorVisible" xml:space="preserve">
-    <value>Visible</value>
-  </data>
-  <data name="SelectedItemCount" xml:space="preserve">
-    <value>{0} selected items</value>
-  </data>
-  <data name="ComputingThemeParameters" xml:space="preserve">
-    <value>Computing Theme Parameters ...</value>
-  </data>
-  <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="UpdatingStylePreviews" xml:space="preserve">
-    <value>Updating Style Previews</value>
-  </data>
-  <data name="CannotCreateThemeFromCompoundSymbolInstance" xml:space="preserve">
-    <value>Creating themes from a Composite Rule with a Compound Symbol is not supported</value>
-  </data>
-  <data name="CompositeThemeRequiresFirstRuleAsTemplate" xml:space="preserve">
-    <value>Generating a theme for a composite style, requires a composite rule</value>
-  </data>
-  <data name="LayerChangedFeatureClass" xml:space="preserve">
-    <value>You have changed the Feature Class for this layer. Styles made for the previous Feature Class may no longer be applicable to this Feature Class. You should review such style settings (eg. Settings involving FDO expressions) to see if anything needs to be changed.</value>
-  </data>
-  <data name="ThemeExpressionOnlySupportsIndividualValues" xml:space="preserve">
-    <value>Only individual values is supported when generating a theme expression</value>
-  </data>
-  <data name="ThemingNotAVectorLayer" xml:space="preserve">
-    <value>The layer being themed is not a vector layer</value>
-  </data>
-  <data name="WarningUnconfiguredWmsFeatureSource" xml:space="preserve">
-    <value>Your WMS Feature Source is not configured. An un-configured WMS Feature Source may not properly read layer information from your WMS Server. Click "Advanced" after testing your connection to build a default document.</value>
-  </data>
-  <data name="FetchingClassDefinition" xml:space="preserve">
-    <value>Fetching Class Definition</value>
-  </data>
-  <data name="FetchingClassNames" xml:space="preserve">
-    <value>Fetching Class Names</value>
-  </data>
-  <data name="FetchingSchemaNames" xml:space="preserve">
-    <value>Fetching Schema Names</value>
-  </data>
-  <data name="Required" xml:space="preserve">
-    <value>Required</value>
-  </data>
-  <data name="SelectSourceResource" xml:space="preserve">
-    <value>Choose a resource for "Selected Resource" first</value>
-  </data>
-  <data name="LayerEditorFeatureClassNotFound" xml:space="preserve">
-    <value>Feature Class Not Found</value>
-  </data>
-  <data name="LayerEditorFeatureSourceNotFound" xml:space="preserve">
-    <value>Feature Source Not Found</value>
-  </data>
-  <data name="LayerEditorGeometryNotFound" xml:space="preserve">
-    <value>Geometry Property Not Found</value>
-  </data>
-  <data name="LayerEditorHasErrors" xml:space="preserve">
-    <value>Found errors in the Layer Definition. Please check any errors flagged in the editor.</value>
-  </data>
-  <data name="CannotCreateThemeForCompositeStyleClassicEditor" xml:space="preserve">
-    <value>Theming composite styles with this editor is not supported</value>
-  </data>
-  <data name="EditSymbolDefinition" xml:space="preserve">
-    <value>Edit Symbol Definition</value>
-  </data>
-  <data name="PropertyInfo" xml:space="preserve">
-    <value>Name: {1}{0}Identifier: {2}{0}Description: {3}{0}Type: {4}{0}Default Value: {5}</value>
-  </data>
-  <data name="CmsGeneric" xml:space="preserve">
-    <value>Generic Layer</value>
-  </data>
-  <data name="OptionsSyncedToDocument" xml:space="preserve">
-    <value>Options synced back to document</value>
-  </data>
-  <data name="MultiSigFunction" xml:space="preserve">
-    <value>{0} ({1} signatures)</value>
-  </data>
-  <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>
-  <data name="CmsStamenTerrain" xml:space="preserve">
-    <value>Stamen (Terrain)</value>
-  </data>
-  <data name="CmsStamenToner" xml:space="preserve">
-    <value>Stamen (Toner)</value>
-  </data>
-  <data name="CmsStamenWaterColor" xml:space="preserve">
-    <value>Stamen (WaterColor)</value>
-  </data>
-  <data name="ExprIsValid" xml:space="preserve">
-    <value>Expression is valid</value>
-  </data>
-  <data name="FilterIsValid" xml:space="preserve">
-    <value>Filter is valid</value>
-  </data>
-  <data name="InvalidExpressionPropertyNotFound" xml:space="preserve">
-    <value>Invalid Expression. Property not found: {0}</value>
-  </data>
-  <data name="InvalidExpressionUnsupportedFunction" xml:space="preserve">
-    <value>Invalid Expression. Function not supported: {0}</value>
-  </data>
-  <data name="InvalidFilterUnsupportedConditionType" xml:space="preserve">
-    <value>Invalid Filter. Unsupported condition type: {0}</value>
-  </data>
-  <data name="InvalidFilterUnsupportedDistanceOperator" xml:space="preserve">
-    <value>Invalid Filter. Unsupported distance operator: {0}</value>
-  </data>
-  <data name="InvalidFilterUnsupportedSpatialOperator" xml:space="preserve">
-    <value>Invalid Filter. Unsupported spatial operator: {0}</value>
-  </data>
-  <data name="ExprDispBoolean" xml:space="preserve">
-    <value>Boolean: {0}</value>
-  </data>
-  <data name="ExprDispDateTime" xml:space="preserve">
-    <value>DateTime: {0}</value>
-  </data>
-  <data name="ExprDispDouble" xml:space="preserve">
-    <value>Double: {0}</value>
-  </data>
-  <data name="ExprDispFunction" xml:space="preserve">
-    <value>Function: {0}</value>
-  </data>
-  <data name="ExprDispGeometry" xml:space="preserve">
-    <value>Geometry: {0}</value>
-  </data>
-  <data name="ExprDispIdentifier" xml:space="preserve">
-    <value>Identifier: {0}</value>
-  </data>
-  <data name="ExprDispInt32" xml:space="preserve">
-    <value>Int32: {0}</value>
-  </data>
-  <data name="ExprDispParameter" xml:space="preserve">
-    <value>Parameter: {0}</value>
-  </data>
-  <data name="ExprDispString" xml:space="preserve">
-    <value>String: '{0}'</value>
-  </data>
-  <data name="ExprDispUnaryExpr" xml:space="preserve">
-    <value>Unary Expression (Negated)</value>
-  </data>
-  <data name="FdoDispDistanceCondition" xml:space="preserve">
-    <value>Distance ({0})</value>
-  </data>
-  <data name="FdoDispDistanceTitle" xml:space="preserve">
-    <value>Distance</value>
-  </data>
-  <data name="FdoDispExprTitle" xml:space="preserve">
-    <value>Expression</value>
-  </data>
-  <data name="FdoDispIdentifierTitle" xml:space="preserve">
-    <value>Identifier</value>
-  </data>
-  <data name="FdoDispInCondition" xml:space="preserve">
-    <value>In Condition ({0})</value>
-  </data>
-  <data name="FdoDispNullCondition" xml:space="preserve">
-    <value>Null Condition ({0})</value>
-  </data>
-  <data name="FdoDispSpatialCondition" xml:space="preserve">
-    <value>Spatial Condition ({0})</value>
-  </data>
-  <data name="FdoDispUnaryOperator" xml:space="preserve">
-    <value>Unary Operator (NOT)</value>
-  </data>
-  <data name="FltrDispBinaryLogicalOperator" xml:space="preserve">
-    <value>Binary Logical Operator ({0})</value>
-  </data>
-  <data name="FltrDispComparisonCondition" xml:space="preserve">
-    <value>Comparison ({0})</value>
-  </data>
-  <data name="FltrDispLeftNode" xml:space="preserve">
-    <value>Left</value>
-  </data>
-  <data name="FltrDispRightNode" xml:space="preserve">
-    <value>Right</value>
-  </data>
 </root>
\ No newline at end of file

Modified: trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.Designer.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.Designer.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.Designer.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -31,11 +31,23 @@
             this.label1 = new System.Windows.Forms.Label();
             this.grpSettings = new System.Windows.Forms.GroupBox();
             this.txtProvider = new System.Windows.Forms.TextBox();
+            this.grpExtents = new System.Windows.Forms.GroupBox();
+            this.btnSetZoom = new System.Windows.Forms.Button();
+            this.txtMaxY = new System.Windows.Forms.TextBox();
+            this.label4 = new System.Windows.Forms.Label();
+            this.txtMaxX = new System.Windows.Forms.TextBox();
+            this.label5 = new System.Windows.Forms.Label();
+            this.txtMinY = new System.Windows.Forms.TextBox();
+            this.label3 = new System.Windows.Forms.Label();
+            this.txtMinX = new System.Windows.Forms.TextBox();
+            this.label2 = new System.Windows.Forms.Label();
             this.contentPanel.SuspendLayout();
+            this.grpExtents.SuspendLayout();
             this.SuspendLayout();
             // 
             // contentPanel
             // 
+            this.contentPanel.Controls.Add(this.grpExtents);
             this.contentPanel.Controls.Add(this.txtProvider);
             this.contentPanel.Controls.Add(this.grpSettings);
             this.contentPanel.Controls.Add(this.label1);
@@ -55,9 +67,9 @@
             this.grpSettings.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
             | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-            this.grpSettings.Location = new System.Drawing.Point(13, 47);
+            this.grpSettings.Location = new System.Drawing.Point(251, 47);
             this.grpSettings.Name = "grpSettings";
-            this.grpSettings.Size = new System.Drawing.Size(554, 227);
+            this.grpSettings.Size = new System.Drawing.Size(316, 227);
             this.grpSettings.TabIndex = 2;
             this.grpSettings.TabStop = false;
             this.grpSettings.Text = "Settings";
@@ -72,6 +84,104 @@
             this.txtProvider.Size = new System.Drawing.Size(474, 20);
             this.txtProvider.TabIndex = 3;
             // 
+            // grpExtents
+            // 
+            this.grpExtents.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left)));
+            this.grpExtents.Controls.Add(this.btnSetZoom);
+            this.grpExtents.Controls.Add(this.txtMaxY);
+            this.grpExtents.Controls.Add(this.label4);
+            this.grpExtents.Controls.Add(this.txtMaxX);
+            this.grpExtents.Controls.Add(this.label5);
+            this.grpExtents.Controls.Add(this.txtMinY);
+            this.grpExtents.Controls.Add(this.label3);
+            this.grpExtents.Controls.Add(this.txtMinX);
+            this.grpExtents.Controls.Add(this.label2);
+            this.grpExtents.Location = new System.Drawing.Point(13, 47);
+            this.grpExtents.Name = "grpExtents";
+            this.grpExtents.Size = new System.Drawing.Size(232, 227);
+            this.grpExtents.TabIndex = 4;
+            this.grpExtents.TabStop = false;
+            this.grpExtents.Text = "Extents";
+            // 
+            // btnSetZoom
+            // 
+            this.btnSetZoom.ImeMode = System.Windows.Forms.ImeMode.NoControl;
+            this.btnSetZoom.Location = new System.Drawing.Point(13, 125);
+            this.btnSetZoom.Name = "btnSetZoom";
+            this.btnSetZoom.Size = new System.Drawing.Size(206, 48);
+            this.btnSetZoom.TabIndex = 11;
+            this.btnSetZoom.Text = "Set view to combined extent of current layers";
+            this.btnSetZoom.Click += new System.EventHandler(this.btnSetZoom_Click);
+            // 
+            // txtMaxY
+            // 
+            this.txtMaxY.Location = new System.Drawing.Point(119, 87);
+            this.txtMaxY.Name = "txtMaxY";
+            this.txtMaxY.Size = new System.Drawing.Size(100, 20);
+            this.txtMaxY.TabIndex = 7;
+            this.txtMaxY.TextChanged += new System.EventHandler(this.txtMaxY_TextChanged);
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(116, 71);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(46, 13);
+            this.label4.TabIndex = 6;
+            this.label4.Text = "Upper Y";
+            // 
+            // txtMaxX
+            // 
+            this.txtMaxX.Location = new System.Drawing.Point(13, 87);
+            this.txtMaxX.Name = "txtMaxX";
+            this.txtMaxX.Size = new System.Drawing.Size(100, 20);
+            this.txtMaxX.TabIndex = 5;
+            this.txtMaxX.TextChanged += new System.EventHandler(this.txtMaxX_TextChanged);
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(10, 71);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(46, 13);
+            this.label5.TabIndex = 4;
+            this.label5.Text = "Upper X";
+            // 
+            // txtMinY
+            // 
+            this.txtMinY.Location = new System.Drawing.Point(119, 43);
+            this.txtMinY.Name = "txtMinY";
+            this.txtMinY.Size = new System.Drawing.Size(100, 20);
+            this.txtMinY.TabIndex = 3;
+            this.txtMinY.TextChanged += new System.EventHandler(this.txtMinY_TextChanged);
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(116, 27);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(46, 13);
+            this.label3.TabIndex = 2;
+            this.label3.Text = "Lower Y";
+            // 
+            // txtMinX
+            // 
+            this.txtMinX.Location = new System.Drawing.Point(13, 43);
+            this.txtMinX.Name = "txtMinX";
+            this.txtMinX.Size = new System.Drawing.Size(100, 20);
+            this.txtMinX.TabIndex = 1;
+            this.txtMinX.TextChanged += new System.EventHandler(this.txtMinX_TextChanged);
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(10, 27);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(46, 13);
+            this.label2.TabIndex = 0;
+            this.label2.Text = "Lower X";
+            // 
             // TileSetSettingsCtrl
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -81,6 +191,8 @@
             this.Size = new System.Drawing.Size(582, 319);
             this.contentPanel.ResumeLayout(false);
             this.contentPanel.PerformLayout();
+            this.grpExtents.ResumeLayout(false);
+            this.grpExtents.PerformLayout();
             this.ResumeLayout(false);
 
         }
@@ -90,5 +202,15 @@
         private System.Windows.Forms.Label label1;
         private System.Windows.Forms.GroupBox grpSettings;
         private System.Windows.Forms.TextBox txtProvider;
+        private System.Windows.Forms.GroupBox grpExtents;
+        private System.Windows.Forms.TextBox txtMaxY;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.TextBox txtMaxX;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.TextBox txtMinY;
+        private System.Windows.Forms.Label label3;
+        private System.Windows.Forms.TextBox txtMinX;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.Button btnSetZoom;
     }
 }

Modified: trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.Editors/TileSetDefinition/TileSetSettingsCtrl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -32,6 +32,8 @@
 using OSGeo.MapGuide.ObjectModels.Common;
 using Maestro.Editors.TileSetDefinition.Providers;
 using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
+using Maestro.Editors.MapDefinition;
+using System.Globalization;
 
 namespace Maestro.Editors.TileSetDefinition
 {
@@ -45,15 +47,23 @@
 
         private bool _init = false;
         private ITileSetDefinition _tsd;
+        private IEditorService _service;
 
         public override void Bind(IEditorService service)
         {
-            service.RegisterCustomNotifier(this);
+            _service = service;
+            _service.RegisterCustomNotifier(this);
             try
             {
                 _init = true;
-                _tsd = (ITileSetDefinition)service.GetEditedResource();
-                var cmd = (IGetTileProviders)service.CurrentConnection.CreateCommand((int)CommandType.GetTileProviders);
+                _tsd = (ITileSetDefinition)_service.GetEditedResource();
+
+                txtMinX.Text = _tsd.Extents.MinX.ToString(CultureInfo.InvariantCulture);
+                txtMinY.Text = _tsd.Extents.MinY.ToString(CultureInfo.InvariantCulture);
+                txtMaxX.Text = _tsd.Extents.MaxX.ToString(CultureInfo.InvariantCulture);
+                txtMaxY.Text = _tsd.Extents.MaxY.ToString(CultureInfo.InvariantCulture);
+
+                var cmd = (IGetTileProviders)_service.CurrentConnection.CreateCommand((int)CommandType.GetTileProviders);
                 var providers = cmd.Execute();
 
                 var provider = providers.TileProvider.FirstOrDefault(p => p.Name == _tsd.TileStoreParameters.TileProvider);
@@ -81,5 +91,87 @@
         {
             return new GenericProviderCtrl(provider, _tsd, OnResourceChanged);
         }
+
+        private IEnumerable<string> CollectLayerIds()
+        {
+            HashSet<string> ids = new HashSet<string>();
+
+            foreach (var grp in _tsd.BaseMapLayerGroups)
+            {
+                foreach (var lyr in grp.BaseMapLayer)
+                {
+                    ids.Add(lyr.ResourceId);
+                }
+            }
+
+            return ids;
+        }
+
+        private void btnSetZoom_Click(object sender, EventArgs e)
+        {
+            string coordinateSystem = null;
+            if (_tsd.TileStoreParameters.TileProvider == "Default") //NOXLATE
+                coordinateSystem = _tsd.GetDefaultCoordinateSystem();
+            else
+                coordinateSystem = _service.CurrentConnection.CoordinateSystemCatalog.FindCoordSys("LL84").WKT;
+
+            var diag = new ExtentCalculationDialog(_service.CurrentConnection, coordinateSystem, CollectLayerIds);
+            if (diag.ShowDialog() == DialogResult.OK)
+            {
+                var env = diag.Extents;
+                if (env != null)
+                {
+                    txtMinX.Text = env.MinX.ToString(CultureInfo.InvariantCulture);
+                    txtMinY.Text = env.MinY.ToString(CultureInfo.InvariantCulture);
+                    txtMaxX.Text = env.MaxX.ToString(CultureInfo.InvariantCulture);
+                    txtMaxY.Text = env.MaxY.ToString(CultureInfo.InvariantCulture);
+                    OnResourceChanged();
+                }
+                else
+                {
+                    MessageBox.Show(Strings.ErrorMapExtentCalculationFailed, Strings.TitleError, MessageBoxButtons.OK, MessageBoxIcon.Error);
+                }
+            }
+        }
+
+        private void txtMinX_TextChanged(object sender, EventArgs e)
+        {
+            if (_init)
+                return;
+
+            double d;
+            if (double.TryParse(txtMinX.Text, out d))
+                _tsd.Extents.MinX = d;
+        }
+
+        private void txtMinY_TextChanged(object sender, EventArgs e)
+        {
+            if (_init)
+                return;
+
+            double d;
+            if (double.TryParse(txtMinY.Text, out d))
+                _tsd.Extents.MinY = d;
+        }
+
+        private void txtMaxX_TextChanged(object sender, EventArgs e)
+        {
+            if (_init)
+                return;
+
+            double d;
+            if (double.TryParse(txtMaxX.Text, out d))
+                _tsd.Extents.MaxX = d;
+        }
+
+        private void txtMaxY_TextChanged(object sender, EventArgs e)
+        {
+            if (_init)
+                return;
+
+            double d;
+            if (double.TryParse(txtMaxY.Text, out d))
+                _tsd.Extents.MaxY = d;
+        }
     }
 }

Modified: trunk/Tools/Maestro/Maestro.LiveMapEditor/MapSettingsDialog.cs
===================================================================
--- trunk/Tools/Maestro/Maestro.LiveMapEditor/MapSettingsDialog.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/Maestro.LiveMapEditor/MapSettingsDialog.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -27,6 +27,7 @@
 using OSGeo.MapGuide.ObjectModels;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
 using System;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Windows.Forms;
 
@@ -116,9 +117,29 @@
             }
         }
 
+        private IEnumerable<string> CollectLayerIds()
+        {
+            HashSet<string> ids = new HashSet<string>();
+            foreach (var layer in _mdf.MapLayer)
+            {
+                ids.Add(layer.ResourceId);
+            }
+            if (_mdf.BaseMap != null)
+            {
+                foreach (var grp in _mdf.BaseMap.BaseMapLayerGroups)
+                {
+                    foreach (var layer in grp.BaseMapLayer)
+                    {
+                        ids.Add(layer.ResourceId);
+                    }
+                }
+            }
+            return ids;
+        }
+
         private void btnSetZoom_Click(object sender, EventArgs e)
         {
-            var diag = new ExtentCalculationDialog(_mdf, _conn);
+            var diag = new ExtentCalculationDialog(_conn, _mdf.CoordinateSystem, CollectLayerIds);
             if (diag.ShowDialog() == DialogResult.OK)
             {
                 var env = diag.Extents;

Modified: trunk/Tools/Maestro/MgCooker/SetupRun.cs
===================================================================
--- trunk/Tools/Maestro/MgCooker/SetupRun.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/MgCooker/SetupRun.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -28,6 +28,7 @@
 using OSGeo.MapGuide.ObjectModels;
 using OSGeo.MapGuide.ObjectModels.Common;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Mapping/RuntimeMap.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -28,6 +28,7 @@
 using OSGeo.MapGuide.ObjectModels.Common;
 using OSGeo.MapGuide.ObjectModels.LayerDefinition;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/BaseMapDefinitionValidator.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/BaseMapDefinitionValidator.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/BaseMapDefinitionValidator.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -26,6 +26,7 @@
 using OSGeo.MapGuide.ObjectModels.FeatureSource;
 using OSGeo.MapGuide.ObjectModels.LayerDefinition;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System;
 using System.Collections.Generic;
 

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Tile/BatchSettings.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Tile/BatchSettings.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Tile/BatchSettings.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -23,6 +23,7 @@
 using OSGeo.MapGuide.ObjectModels;
 using OSGeo.MapGuide.ObjectModels.Common;
 using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System;
 using System.Collections.Generic;
 

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/Mapping/RuntimeMapTests.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/Mapping/RuntimeMapTests.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/Mapping/RuntimeMapTests.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -20,18 +20,19 @@
 
 #endregion Disclaimer / License
 
+using Moq;
+using NUnit.Framework;
+using OSGeo.MapGuide.MaestroAPI.Mapping;
+using OSGeo.MapGuide.MaestroAPI.Services;
+using OSGeo.MapGuide.ObjectModels;
+using OSGeo.MapGuide.ObjectModels.LayerDefinition;
+using OSGeo.MapGuide.ObjectModels.MapDefinition;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using System.Text;
-using OSGeo.MapGuide.MaestroAPI.Mapping;
-using NUnit.Framework;
-using OSGeo.MapGuide.ObjectModels;
-using OSGeo.MapGuide.ObjectModels.MapDefinition;
-using System.IO;
-using Moq;
-using OSGeo.MapGuide.MaestroAPI.Services;
-using OSGeo.MapGuide.ObjectModels.LayerDefinition;
 
 namespace OSGeo.MapGuide.MaestroAPI.Mapping.Tests
 {

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/OSGeo.MapGuide.ObjectModels.Tests.csproj
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/OSGeo.MapGuide.ObjectModels.Tests.csproj	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/OSGeo.MapGuide.ObjectModels.Tests.csproj	2015-02-18 13:36:04 UTC (rev 8546)
@@ -78,6 +78,7 @@
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
     <Compile Include="ResourceTests.cs" />
+    <Compile Include="TileSetAbstractTests.cs" />
     <Compile Include="TileSetDefinitionTests.cs" />
   </ItemGroup>
   <ItemGroup>

Added: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/TileSetAbstractTests.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/TileSetAbstractTests.cs	                        (rev 0)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModel.Tests/TileSetAbstractTests.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -0,0 +1,244 @@
+#region Disclaimer / License
+
+// Copyright (C) 2015, 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 Disclaimer / License
+using NUnit.Framework;
+using OSGeo.MapGuide.ObjectModels.TileSetDefinition;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OSGeo.MapGuide.ObjectModels.Tests
+{
+    // This test suite exercises known implementations of ITileSetAbstract to ensure consistent behaviour
+
+    [TestFixture]
+    public class TileSetAbstractTests
+    {
+        [Test]
+        public void FiniteScalesTest()
+        {
+            var mdf = ObjectFactory.CreateMapDefinition(new Version(3, 0, 0), "Test");
+            var tsd = ObjectFactory.CreateTileSetDefinition(new Version(3, 0, 0));
+
+            mdf.InitBaseMap();
+            tsd.SetDefaultProviderParameters(300, 300, "", new double[] { });
+
+            ITileSetAbstract tsMapDef = mdf.BaseMap;
+            ITileSetAbstract tsTileSet = tsd;
+
+            Assert.False(tsTileSet.SupportsCustomFiniteDisplayScalesUnconditionally);
+            Assert.True(tsTileSet.SupportsCustomFiniteDisplayScales);
+
+            tsMapDef.SetFiniteDisplayScales(new double[] { 1.0, 2.0, 4.0 });
+            tsTileSet.SetFiniteDisplayScales(new double[] { 1.0, 2.0, 4.0 });
+
+            Assert.AreEqual(3, tsMapDef.ScaleCount);
+            Assert.AreEqual(3, tsTileSet.ScaleCount);
+
+            tsMapDef.SetFiniteDisplayScales(new double[] { 1.0, 2.0, 4.0, 8.0, 16.0 });
+            tsTileSet.SetFiniteDisplayScales(new double[] { 1.0, 2.0, 4.0, 8.0, 16.0 });
+
+            Assert.AreEqual(5, tsMapDef.ScaleCount);
+            Assert.AreEqual(5, tsTileSet.ScaleCount);
+
+            Assert.AreEqual(1.0, tsMapDef.GetScaleAt(0));
+            Assert.AreEqual(1.0, tsTileSet.GetScaleAt(0));
+
+            Assert.AreEqual(2.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(2.0, tsTileSet.GetScaleAt(1));
+
+            Assert.AreEqual(4.0, tsMapDef.GetScaleAt(2));
+            Assert.AreEqual(4.0, tsTileSet.GetScaleAt(2));
+
+            Assert.AreEqual(8.0, tsMapDef.GetScaleAt(3));
+            Assert.AreEqual(8.0, tsTileSet.GetScaleAt(3));
+
+            Assert.AreEqual(16.0, tsMapDef.GetScaleAt(4));
+            Assert.AreEqual(16.0, tsTileSet.GetScaleAt(4));
+
+            tsMapDef.RemoveScaleAt(3);
+            tsTileSet.RemoveScaleAt(3);
+
+            Assert.AreEqual(1.0, tsMapDef.GetScaleAt(0));
+            Assert.AreEqual(1.0, tsTileSet.GetScaleAt(0));
+
+            Assert.AreEqual(2.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(2.0, tsTileSet.GetScaleAt(1));
+
+            Assert.AreEqual(4.0, tsMapDef.GetScaleAt(2));
+            Assert.AreEqual(4.0, tsTileSet.GetScaleAt(2));
+
+            Assert.AreEqual(16.0, tsMapDef.GetScaleAt(3));
+            Assert.AreEqual(16.0, tsTileSet.GetScaleAt(3));
+
+            tsMapDef.RemoveScaleAt(0);
+            tsTileSet.RemoveScaleAt(0);
+
+            Assert.AreEqual(2.0, tsMapDef.GetScaleAt(0));
+            Assert.AreEqual(2.0, tsTileSet.GetScaleAt(0));
+
+            Assert.AreEqual(4.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(4.0, tsTileSet.GetScaleAt(1));
+
+            Assert.AreEqual(16.0, tsMapDef.GetScaleAt(2));
+            Assert.AreEqual(16.0, tsTileSet.GetScaleAt(2));
+
+            tsMapDef.RemoveScaleAt(2);
+            tsTileSet.RemoveScaleAt(2);
+
+            Assert.AreEqual(2.0, tsMapDef.GetScaleAt(0));
+            Assert.AreEqual(2.0, tsTileSet.GetScaleAt(0));
+
+            Assert.AreEqual(4.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(4.0, tsTileSet.GetScaleAt(1));
+
+            Assert.AreEqual(2.0, tsMapDef.GetMinScale());
+            Assert.AreEqual(2.0, tsTileSet.GetMinScale());
+
+            tsMapDef.RemoveFiniteDisplayScale(1.2);
+            tsTileSet.RemoveFiniteDisplayScale(1.2);
+
+            Assert.AreEqual(2.0, tsMapDef.GetScaleAt(0));
+            Assert.AreEqual(2.0, tsTileSet.GetScaleAt(0));
+
+            Assert.AreEqual(4.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(4.0, tsTileSet.GetScaleAt(1));
+
+            Assert.Throws<ArgumentOutOfRangeException>(() => tsMapDef.RemoveScaleAt(6));
+            Assert.Throws<ArgumentOutOfRangeException>(() => tsTileSet.RemoveScaleAt(6));
+
+            Assert.AreEqual(2.0, tsMapDef.GetScaleAt(0));
+            Assert.AreEqual(2.0, tsTileSet.GetScaleAt(0));
+
+            Assert.AreEqual(4.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(4.0, tsTileSet.GetScaleAt(1));
+
+            tsMapDef.AddFiniteDisplayScale(3.0);
+            tsTileSet.AddFiniteDisplayScale(3.0);
+
+            Assert.AreEqual(3, tsMapDef.ScaleCount);
+            Assert.AreEqual(3, tsTileSet.ScaleCount);
+
+            Assert.AreEqual(3.0, tsMapDef.GetScaleAt(1));
+            Assert.AreEqual(3.0, tsTileSet.GetScaleAt(1));
+
+            tsMapDef.RemoveAllScales();
+            tsTileSet.RemoveAllScales();
+
+            Assert.AreEqual(0, tsMapDef.ScaleCount);
+            Assert.AreEqual(0, tsTileSet.ScaleCount);
+        }
+
+        [Test]
+        public void TestUnsupportedScaleOperations()
+        {
+            var tsd = ObjectFactory.CreateTileSetDefinition(new Version(3, 0, 0));
+
+            tsd.SetXYZProviderParameters();
+
+            ITileSetAbstract tsTileSet = tsd;
+
+            Assert.False(tsTileSet.SupportsCustomFiniteDisplayScalesUnconditionally);
+            Assert.False(tsTileSet.SupportsCustomFiniteDisplayScales);
+
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.SetFiniteDisplayScales(new double[] { 1.0, 2.0, 4.0 }));
+            Assert.Throws<InvalidOperationException>(() => { var x = tsTileSet.ScaleCount; });
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.SetFiniteDisplayScales(new double[] { 1.0, 2.0, 4.0, 8.0, 16.0 }));
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.GetScaleAt(0));
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.RemoveScaleAt(3));
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.RemoveFiniteDisplayScale(1.2));
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.RemoveAllScales());
+            Assert.Throws<InvalidOperationException>(() => tsTileSet.AddFiniteDisplayScale(1234.0));
+        }
+
+        [Test]
+        public void GroupManagementTest()
+        {
+            var mdf = ObjectFactory.CreateMapDefinition(new Version(3, 0, 0), "Test");
+            var tsd = ObjectFactory.CreateTileSetDefinition(new Version(3, 0, 0));
+
+            mdf.InitBaseMap();
+            tsd.SetDefaultProviderParameters(300, 300, "", new double[] { });
+
+            ITileSetAbstract tsMapDef = mdf.BaseMap;
+            ITileSetAbstract tsTileSet = tsd;
+
+            //Default tile set has a base group (to satisfy minimum content model), so clear that first
+            tsTileSet.RemoveBaseLayerGroup(tsTileSet.BaseMapLayerGroups.First());
+
+            Assert.AreEqual(0, tsMapDef.GroupCount);
+            Assert.AreEqual(0, tsTileSet.GroupCount);
+
+            var grpMapDef = tsMapDef.AddBaseLayerGroup("Test");
+            var grpTileSet = tsTileSet.AddBaseLayerGroup("Test");
+            Assert.NotNull(grpMapDef);
+            Assert.NotNull(grpTileSet);
+            Assert.AreEqual("Test", grpMapDef.Name);
+            Assert.AreEqual("Test", grpTileSet.Name);
+            Assert.AreEqual(1, tsMapDef.GroupCount);
+            Assert.AreEqual(1, tsTileSet.GroupCount);
+
+            Assert.NotNull(grpMapDef.AddLayer("layer1", "Library://test/layer1.LayerDefinition"));
+            Assert.NotNull(grpMapDef.AddLayer("layer2", "Library://test/layer2.LayerDefinition"));
+            Assert.NotNull(grpTileSet.AddLayer("layer1", "Library://test/layer1.LayerDefinition"));
+            Assert.NotNull(grpTileSet.AddLayer("layer2", "Library://test/layer2.LayerDefinition"));
+
+            grpMapDef = tsMapDef.AddBaseLayerGroup("Test2");
+            grpTileSet = tsTileSet.AddBaseLayerGroup("Test2");
+            Assert.NotNull(grpMapDef);
+            Assert.NotNull(grpTileSet);
+            Assert.AreEqual("Test2", grpMapDef.Name);
+            Assert.AreEqual("Test2", grpTileSet.Name);
+            Assert.AreEqual(2, tsMapDef.GroupCount);
+            Assert.AreEqual(2, tsTileSet.GroupCount);
+
+            Assert.NotNull(grpMapDef.AddLayer("layer3", "Library://test/layer3.LayerDefinition"));
+            Assert.NotNull(grpTileSet.AddLayer("layer3", "Library://test/layer3.LayerDefinition"));
+
+            Assert.AreEqual(3, tsMapDef.GetBaseLayerCount());
+            Assert.AreEqual(3, tsTileSet.GetBaseLayerCount());
+
+            Assert.NotNull(tsMapDef.GetBaseLayerByName("layer1"));
+            Assert.NotNull(tsMapDef.GetBaseLayerByName("layer2"));
+            Assert.NotNull(tsMapDef.GetBaseLayerByName("layer3"));
+
+            Assert.NotNull(tsTileSet.GetBaseLayerByName("layer1"));
+            Assert.NotNull(tsTileSet.GetBaseLayerByName("layer2"));
+            Assert.NotNull(tsTileSet.GetBaseLayerByName("layer3"));
+
+            tsMapDef.RemoveBaseLayerGroup(tsMapDef.GetGroup("Test"));
+            tsTileSet.RemoveBaseLayerGroup(tsTileSet.GetGroup("Test"));
+
+            Assert.Null(tsMapDef.GetBaseLayerByName("layer1"));
+            Assert.Null(tsMapDef.GetBaseLayerByName("layer2"));
+            Assert.NotNull(tsMapDef.GetBaseLayerByName("layer3"));
+
+            Assert.Null(tsTileSet.GetBaseLayerByName("layer1"));
+            Assert.Null(tsTileSet.GetBaseLayerByName("layer2"));
+            Assert.NotNull(tsTileSet.GetBaseLayerByName("layer3"));
+
+            Assert.AreEqual(1, tsMapDef.GetBaseLayerCount());
+            Assert.AreEqual(1, tsTileSet.GetBaseLayerCount());
+        }
+    }
+}

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/MapDefinitionInterfaces.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/MapDefinitionInterfaces.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/MapDefinitionInterfaces.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -121,6 +121,13 @@
         IBaseMapDefinition BaseMap { get; }
 
         /// <summary>
+        /// Attaches the given base map section to this map definition. If an existing base map section
+        /// exists, it is replaced
+        /// </summary>
+        /// <param name="baseMap"></param>
+        void AttachBaseMap(IBaseMapDefinition baseMap);
+
+        /// <summary>
         /// Initializes the base map section of this map definition. Subsequent calls
         /// do nothing, unless you have cleared the section via <see cref="RemoveBaseMap"/>
         /// </summary>
@@ -317,199 +324,6 @@
     }
 
     /// <summary>
-    /// Extension methdo class
-    /// </summary>
-    public static class BaseMapDefinitionExtensions
-    {
-        /// <summary>
-        /// Gets the minimum finite display scale
-        /// </summary>
-        /// <param name="map"></param>
-        /// <returns></returns>
-        public static double GetMinScale(this IBaseMapDefinition map)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            if (map.ScaleCount == 0)
-                return 0.0;
-
-            var scales = new List<double>(map.FiniteDisplayScale);
-            scales.Sort();
-            return scales[0];
-        }
-
-        /// <summary>
-        /// Gets the maximum finite display scale
-        /// </summary>
-        /// <param name="map"></param>
-        /// <returns></returns>
-        public static double GetMaxScale(this IBaseMapDefinition map)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            if (map.ScaleCount == 0)
-                return 0.0;
-
-            var scales = new List<double>(map.FiniteDisplayScale);
-            scales.Sort();
-            return scales[scales.Count - 1];
-        }
-
-        /// <summary>
-        /// Gets the parent group for the specified layer
-        /// </summary>
-        /// <param name="map"></param>
-        /// <param name="layer"></param>
-        /// <returns></returns>
-        public static IBaseMapGroup GetGroupForLayer(this ITileSetAbstract map, IBaseMapLayer layer)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            foreach (var group in map.BaseMapLayerGroups)
-            {
-                foreach (var tl in group.BaseMapLayer)
-                {
-                    if (tl == layer)
-                        return group;
-                }
-            }
-            return null;
-        }
-
-        /// <summary>
-        /// Gets whether this base map group has tiled layers
-        /// </summary>
-        /// <param name="grp"></param>
-        /// <returns></returns>
-        public static bool HasLayers(this IBaseMapGroup grp)
-        {
-            Check.ArgumentNotNull(grp, "grp"); //NOXLATE
-            return new List<IBaseMapLayer>(grp.BaseMapLayer).Count > 0;
-        }
-
-        /// <summary>
-        /// Gets whether this base map has tiled layers
-        /// </summary>
-        /// <param name="map"></param>
-        /// <returns></returns>
-        public static bool HasLayers(this IBaseMapDefinition map)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            if (!map.HasGroups())
-                return false;
-
-            foreach (var group in map.BaseMapLayerGroups)
-            {
-                if (group.HasLayers())
-                    return true;
-            }
-            return false;
-        }
-
-        /// <summary>
-        /// Gets whether this base map has groups
-        /// </summary>
-        /// <param name="map"></param>
-        /// <returns></returns>
-        public static bool HasGroups(this IBaseMapDefinition map)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            return new List<IBaseMapGroup>(map.BaseMapLayerGroups).Count > 0;
-        }
-
-        /// <summary>
-        /// Gets the first base map group
-        /// </summary>
-        /// <param name="map"></param>
-        /// <returns></returns>
-        public static IBaseMapGroup GetFirstGroup(this ITileSetAbstract map)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            var list = new List<IBaseMapGroup>(map.BaseMapLayerGroups);
-            if (list.Count > 0)
-                return list[0];
-            return null;
-        }
-
-        /// <summary>
-        /// Gets whether a tiled layer of the specified name exists.
-        /// </summary>
-        /// <param name="map"></param>
-        /// <param name="layerName"></param>
-        /// <returns></returns>
-        public static bool LayerExists(this ITileSetAbstract map, string layerName)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            Check.ArgumentNotEmpty(layerName, "layerName"); //NOXLATE
-
-            foreach (var group in map.BaseMapLayerGroups)
-            {
-                foreach (var layer in group.BaseMapLayer)
-                {
-                    if (layerName.Equals(layer.Name))
-                        return true;
-                }
-            }
-            return false;
-        }
-
-        /// <summary>
-        /// Gets the base map group of the specified name
-        /// </summary>
-        /// <param name="map"></param>
-        /// <param name="groupName"></param>
-        /// <returns></returns>
-        public static IBaseMapGroup GetGroup(this IBaseMapDefinition map, string groupName)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            Check.ArgumentNotEmpty(groupName, "groupName"); //NOXLATE
-            foreach (var group in map.BaseMapLayerGroups)
-            {
-                if (groupName.Equals(group.Name))
-                    return group;
-            }
-            return null;
-        }
-
-        /// <summary>
-        /// Gets whether the specified base map group exists
-        /// </summary>
-        /// <param name="map"></param>
-        /// <param name="groupName"></param>
-        /// <returns></returns>
-        public static bool GroupExists(this IBaseMapDefinition map, string groupName)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            Check.ArgumentNotEmpty(groupName, "groupName"); //NOXLATE
-            foreach (var group in map.BaseMapLayerGroups)
-            {
-                if (groupName.Equals(group.Name))
-                    return true;
-            }
-            return false;
-        }
-
-        /// <summary>
-        /// Gets the tiled layers for the specified base map group
-        /// </summary>
-        /// <param name="map"></param>
-        /// <param name="groupName"></param>
-        /// <returns></returns>
-        public static IEnumerable<IBaseMapLayer> GetLayersForGroup(this IBaseMapDefinition map, string groupName)
-        {
-            Check.ArgumentNotNull(map, "map"); //NOXLATE
-            Check.ArgumentNotEmpty(groupName, "groupName"); //NOXLATE
-
-            foreach (var group in map.BaseMapLayerGroups)
-            {
-                if (groupName.Equals(group.Name))
-                {
-                    return group.BaseMapLayer;
-                }
-            }
-
-            return new IBaseMapLayer[0];
-        }
-    }
-
-    /// <summary>
     /// Extension method class
     /// </summary>
     public static class MapDefinitionExtensions
@@ -790,41 +604,7 @@
     /// </summary>
     public interface IBaseMapDefinition : ITileSetAbstract
     {
-        /// <summary>
-        /// Adds the finite display scale.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        void AddFiniteDisplayScale(double value);
-
-        /// <summary>
-        /// Removes the finite display scale.
-        /// </summary>
-        /// <param name="value">The value.</param>
-        void RemoveFiniteDisplayScale(double value);
-
-        /// <summary>
-        /// Gets the scale count.
-        /// </summary>
-        /// <value>The scale count.</value>
-        int ScaleCount { get; }
-
-        /// <summary>
-        /// Removes the scale at the specified index
-        /// </summary>
-        /// <param name="index">The index.</param>
-        void RemoveScaleAt(int index);
-
-        /// <summary>
-        /// Gets the scale at the specified index
-        /// </summary>
-        /// <param name="index">The index.</param>
-        /// <returns></returns>
-        double GetScaleAt(int index);
-
-        /// <summary>
-        /// Removes all scales.
-        /// </summary>
-        void RemoveAllScales();
+        
     }
 
     /// <summary>

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v1_0_0/MapDefinitionImpl.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v1_0_0/MapDefinitionImpl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v1_0_0/MapDefinitionImpl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -466,6 +466,15 @@
             }
         }
 
+        void IMapDefinition.AttachBaseMap(IBaseMapDefinition baseMap)
+        {
+            var bmd = baseMap as MapDefinitionTypeBaseMapDefinition;
+            if (bmd != null)
+            {
+                this.BaseMapDefinition = bmd;
+            }
+        }
+
         void IMapDefinition.InitBaseMap()
         {
             if (this.BaseMapDefinition == null)
@@ -750,12 +759,20 @@
             set;
         }
 
-        void IBaseMapDefinition.RemoveScaleAt(int index)
+        bool ITileSetAbstract.SupportsCustomFiniteDisplayScalesUnconditionally
         {
+            get
+            {
+                return true;
+            }
+        }
+
+        void ITileSetAbstract.RemoveScaleAt(int index)
+        {
             this.FiniteDisplayScale.RemoveAt(index);
         }
 
-        double IBaseMapDefinition.GetScaleAt(int index)
+        double ITileSetAbstract.GetScaleAt(int index)
         {
             return this.FiniteDisplayScale[index];
         }
@@ -772,7 +789,7 @@
         }
 
         [XmlIgnore]
-        int IBaseMapDefinition.ScaleCount
+        int ITileSetAbstract.ScaleCount
         {
             get { return this.FiniteDisplayScale.Count; }
         }
@@ -787,12 +804,22 @@
             this.FiniteDisplayScale.Remove(value);
         }
 
-        void IBaseMapDefinition.RemoveAllScales()
+        void ITileSetAbstract.SetFiniteDisplayScales(IEnumerable<double> scales)
         {
             this.FiniteDisplayScale.Clear();
+            foreach (double scale in scales.OrderBy(s => s))
+            {
+                this.FiniteDisplayScale.Add(scale);
+            }
             OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
         }
 
+        void ITileSetAbstract.RemoveAllScales()
+        {
+            this.FiniteDisplayScale.Clear();
+            OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
+        }
+
         [XmlIgnore]
         IEnumerable<double> ITileSetAbstract.FiniteDisplayScale
         {

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_3_0/MapDefinitionImpl.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_3_0/MapDefinitionImpl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_3_0/MapDefinitionImpl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -467,6 +467,15 @@
             }
         }
 
+        void IMapDefinition.AttachBaseMap(IBaseMapDefinition baseMap)
+        {
+            var bmd = baseMap as MapDefinitionTypeBaseMapDefinition;
+            if (bmd != null)
+            {
+                this.BaseMapDefinition = bmd;
+            }
+        }
+
         void IMapDefinition.InitBaseMap()
         {
             if (this.BaseMapDefinition == null)
@@ -751,12 +760,20 @@
             set;
         }
 
-        void IBaseMapDefinition.RemoveScaleAt(int index)
+        bool ITileSetAbstract.SupportsCustomFiniteDisplayScalesUnconditionally
         {
+            get
+            {
+                return true;
+            }
+        }
+
+        void ITileSetAbstract.RemoveScaleAt(int index)
+        {
             this.FiniteDisplayScale.RemoveAt(index);
         }
 
-        double IBaseMapDefinition.GetScaleAt(int index)
+        double ITileSetAbstract.GetScaleAt(int index)
         {
             return this.FiniteDisplayScale[index];
         }
@@ -773,7 +790,7 @@
         }
 
         [XmlIgnore]
-        int IBaseMapDefinition.ScaleCount
+        int ITileSetAbstract.ScaleCount
         {
             get { return this.FiniteDisplayScale.Count; }
         }
@@ -788,12 +805,22 @@
             this.FiniteDisplayScale.Remove(value);
         }
 
-        void IBaseMapDefinition.RemoveAllScales()
+        void ITileSetAbstract.SetFiniteDisplayScales(IEnumerable<double> scales)
         {
             this.FiniteDisplayScale.Clear();
+            foreach (double scale in scales.OrderBy(s => s))
+            {
+                this.FiniteDisplayScale.Add(scale);
+            }
             OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
         }
 
+        void ITileSetAbstract.RemoveAllScales()
+        {
+            this.FiniteDisplayScale.Clear();
+            OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
+        }
+
         [XmlIgnore]
         IEnumerable<double> ITileSetAbstract.FiniteDisplayScale
         {

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_4_0/MapDefinitionImpl.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_4_0/MapDefinitionImpl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v2_4_0/MapDefinitionImpl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -468,6 +468,15 @@
             }
         }
 
+        void IMapDefinition.AttachBaseMap(IBaseMapDefinition baseMap)
+        {
+            var bmd = baseMap as MapDefinitionTypeBaseMapDefinition;
+            if (bmd != null)
+            {
+                this.BaseMapDefinition = bmd;
+            }
+        }
+
         void IMapDefinition.InitBaseMap()
         {
             if (this.BaseMapDefinition == null)
@@ -752,12 +761,20 @@
             set;
         }
 
-        void IBaseMapDefinition.RemoveScaleAt(int index)
+        bool ITileSetAbstract.SupportsCustomFiniteDisplayScalesUnconditionally
         {
+            get
+            {
+                return true;
+            }
+        }
+
+        void ITileSetAbstract.RemoveScaleAt(int index)
+        {
             this.FiniteDisplayScale.RemoveAt(index);
         }
 
-        double IBaseMapDefinition.GetScaleAt(int index)
+        double ITileSetAbstract.GetScaleAt(int index)
         {
             return this.FiniteDisplayScale[index];
         }
@@ -774,7 +791,7 @@
         }
 
         [XmlIgnore]
-        int IBaseMapDefinition.ScaleCount
+        int ITileSetAbstract.ScaleCount
         {
             get { return this.FiniteDisplayScale.Count; }
         }
@@ -789,12 +806,22 @@
             this.FiniteDisplayScale.Remove(value);
         }
 
-        void IBaseMapDefinition.RemoveAllScales()
+        void ITileSetAbstract.SetFiniteDisplayScales(IEnumerable<double> scales)
         {
             this.FiniteDisplayScale.Clear();
+            foreach (double scale in scales.OrderBy(s => s))
+            {
+                this.FiniteDisplayScale.Add(scale);
+            }
             OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
         }
 
+        void ITileSetAbstract.RemoveAllScales()
+        {
+            this.FiniteDisplayScale.Clear();
+            OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
+        }
+
         [XmlIgnore]
         IEnumerable<double> ITileSetAbstract.FiniteDisplayScale
         {

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v3_0_0/MapDefinitionImpl.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v3_0_0/MapDefinitionImpl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/MapDefinition/v3_0_0/MapDefinitionImpl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -501,6 +501,15 @@
             }
         }
 
+        void IMapDefinition.AttachBaseMap(IBaseMapDefinition baseMap)
+        {
+            var bmd = baseMap as MapDefinitionTypeBaseMapDefinition;
+            if (bmd != null)
+            {
+                this.BaseMapDefinition = bmd;
+            }
+        }
+
         void IMapDefinition.InitBaseMap()
         {
             if (this.BaseMapDefinition == null)
@@ -784,12 +793,20 @@
             set;
         }
 
-        void IBaseMapDefinition.RemoveScaleAt(int index)
+        bool ITileSetAbstract.SupportsCustomFiniteDisplayScalesUnconditionally
         {
+            get
+            {
+                return true;
+            }
+        }
+
+        void ITileSetAbstract.RemoveScaleAt(int index)
+        {
             this.FiniteDisplayScale.RemoveAt(index);
         }
 
-        double IBaseMapDefinition.GetScaleAt(int index)
+        double ITileSetAbstract.GetScaleAt(int index)
         {
             return this.FiniteDisplayScale[index];
         }
@@ -806,27 +823,53 @@
         }
 
         [XmlIgnore]
-        int IBaseMapDefinition.ScaleCount
+        int ITileSetAbstract.ScaleCount
         {
             get { return this.FiniteDisplayScale.Count; }
         }
 
         public void AddFiniteDisplayScale(double value)
         {
-            this.FiniteDisplayScale.Add(value);
+            int index = 0;
+            var fds = this.FiniteDisplayScale;
+            if (fds.Count == 0)
+            {
+                fds.Add(value);
+            }
+            else
+            {
+                for (int i = fds.Count - 1; i >= 0; i--)
+                {
+                    if (value < fds[i])
+                        index = i;
+                }
+                fds.Insert(index, value);
+            }
+            OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
         }
 
         public void RemoveFiniteDisplayScale(double value)
         {
             this.FiniteDisplayScale.Remove(value);
+            OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
         }
 
-        void IBaseMapDefinition.RemoveAllScales()
+        void ITileSetAbstract.SetFiniteDisplayScales(IEnumerable<double> scales)
         {
             this.FiniteDisplayScale.Clear();
+            foreach (double scale in scales.OrderBy(s => s))
+            {
+                this.FiniteDisplayScale.Add(scale);
+            }
             OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
         }
 
+        void ITileSetAbstract.RemoveAllScales()
+        {
+            this.FiniteDisplayScale.Clear();
+            OnPropertyChanged("FiniteDisplayScale"); //NOXLATE
+        }
+
         [XmlIgnore]
         IEnumerable<double> ITileSetAbstract.FiniteDisplayScale
         {

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/TileSetInterfaces.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/TileSetInterfaces.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/TileSetInterfaces.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -55,8 +55,57 @@
 
     public interface ITileSetAbstract
     {
+        void SetFiniteDisplayScales(IEnumerable<double> scales);
+
+        /// <summary>
+        /// Adds the finite display scale. The implementation may internally sort after adding the added item
+        /// </summary>
+        /// <param name="value">The value.</param>
+        void AddFiniteDisplayScale(double value);
+
+        /// <summary>
+        /// Removes the finite display scale.
+        /// </summary>
+        /// <param name="value">The value.</param>
+        void RemoveFiniteDisplayScale(double value);
+
+        /// <summary>
+        /// Gets the scale count.
+        /// </summary>
+        /// <value>The scale count.</value>
+        int ScaleCount { get; }
+
+        /// <summary>
+        /// Removes the scale at the specified index
+        /// </summary>
+        /// <param name="index">The index.</param>
+        void RemoveScaleAt(int index);
+
+        /// <summary>
+        /// Gets the scale at the specified index
+        /// </summary>
+        /// <param name="index">The index.</param>
+        /// <returns></returns>
+        double GetScaleAt(int index);
+
+        /// <summary>
+        /// Removes all scales.
+        /// </summary>
+        void RemoveAllScales();
+
         IEnumerable<double> FiniteDisplayScale { get; }
 
+        /// <summary>
+        /// Gets whether this tile set supports under certain conditions. If false, the caller
+        /// should check if <see cref="SupportsCustomFiniteDisplayScales"/> is true in order to
+        /// safely invoke any scale based operations
+        /// </summary>
+        bool SupportsCustomFiniteDisplayScalesUnconditionally { get; }
+
+        /// <summary>
+        /// Gets whether this tile set supports custom finite display scales. If false, none
+        /// of the scale operations should be used
+        /// </summary>
         bool SupportsCustomFiniteDisplayScales { get; }
 
         IEnumerable<IBaseMapGroup> BaseMapLayerGroups { get; }
@@ -93,6 +142,214 @@
     public static class ExtensionMethods
     {
         /// <summary>
+        /// Gets the number of base layers
+        /// </summary>
+        /// <param name="map"></param>
+        /// <returns></returns>
+        public static int GetBaseLayerCount(this ITileSetAbstract map)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            return map.BaseMapLayerGroups.SelectMany(g => g.BaseMapLayer).Count();
+        }
+
+        /// <summary>
+        /// Gets the minimum finite display scale
+        /// </summary>
+        /// <param name="map"></param>
+        /// <returns></returns>
+        public static double GetMinScale(this ITileSetAbstract map)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            if (map.ScaleCount == 0)
+                return 0.0;
+
+            return map.FiniteDisplayScale.First();
+        }
+
+        /// <summary>
+        /// Gets the maximum finite display scale
+        /// </summary>
+        /// <param name="map"></param>
+        /// <returns></returns>
+        public static double GetMaxScale(this ITileSetAbstract map)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            if (map.ScaleCount == 0)
+                return 0.0;
+
+            return map.FiniteDisplayScale.Last();
+        }
+
+        /// <summary>
+        /// Gets the parent group for the specified layer
+        /// </summary>
+        /// <param name="map"></param>
+        /// <param name="layer"></param>
+        /// <returns></returns>
+        public static IBaseMapGroup GetGroupForLayer(this ITileSetAbstract map, IBaseMapLayer layer)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            foreach (var group in map.BaseMapLayerGroups)
+            {
+                foreach (var tl in group.BaseMapLayer)
+                {
+                    if (tl == layer)
+                        return group;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Gets whether this base map group has tiled layers
+        /// </summary>
+        /// <param name="grp"></param>
+        /// <returns></returns>
+        public static bool HasLayers(this IBaseMapGroup grp)
+        {
+            Check.ArgumentNotNull(grp, "grp"); //NOXLATE
+            return new List<IBaseMapLayer>(grp.BaseMapLayer).Count > 0;
+        }
+
+        /// <summary>
+        /// Gets whether this base map has tiled layers
+        /// </summary>
+        /// <param name="map"></param>
+        /// <returns></returns>
+        public static bool HasLayers(this ITileSetAbstract map)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            if (!map.HasGroups())
+                return false;
+
+            foreach (var group in map.BaseMapLayerGroups)
+            {
+                if (group.HasLayers())
+                    return true;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Gets whether this base map has groups
+        /// </summary>
+        /// <param name="map"></param>
+        /// <returns></returns>
+        public static bool HasGroups(this ITileSetAbstract map)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            return new List<IBaseMapGroup>(map.BaseMapLayerGroups).Count > 0;
+        }
+
+        /// <summary>
+        /// Gets the first base map group
+        /// </summary>
+        /// <param name="map"></param>
+        /// <returns></returns>
+        public static IBaseMapGroup GetFirstGroup(this ITileSetAbstract map)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            var list = new List<IBaseMapGroup>(map.BaseMapLayerGroups);
+            if (list.Count > 0)
+                return list[0];
+            return null;
+        }
+
+        /// <summary>
+        /// Gets the base layer of the specified name
+        /// </summary>
+        /// <param name="map"></param>
+        /// <param name="layerName"></param>
+        /// <returns></returns>
+        public static IBaseMapLayer GetBaseLayerByName(this ITileSetAbstract map, string layerName)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            Check.ArgumentNotEmpty(layerName, "layerName"); //NOXLATE
+
+            foreach (var group in map.BaseMapLayerGroups)
+            {
+                foreach (var layer in group.BaseMapLayer)
+                {
+                    if (layerName.Equals(layer.Name))
+                        return layer;
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Gets whether a base layer of the specified name exists.
+        /// </summary>
+        /// <param name="map"></param>
+        /// <param name="layerName"></param>
+        /// <returns></returns>
+        public static bool LayerExists(this ITileSetAbstract map, string layerName)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            Check.ArgumentNotEmpty(layerName, "layerName"); //NOXLATE
+
+            return map.GetBaseLayerByName(layerName) != null;
+        }
+
+        /// <summary>
+        /// Gets the base map group of the specified name
+        /// </summary>
+        /// <param name="map"></param>
+        /// <param name="groupName"></param>
+        /// <returns></returns>
+        public static IBaseMapGroup GetGroup(this ITileSetAbstract map, string groupName)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            Check.ArgumentNotEmpty(groupName, "groupName"); //NOXLATE
+            foreach (var group in map.BaseMapLayerGroups)
+            {
+                if (groupName.Equals(group.Name))
+                    return group;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Gets whether the specified base map group exists
+        /// </summary>
+        /// <param name="map"></param>
+        /// <param name="groupName"></param>
+        /// <returns></returns>
+        public static bool GroupExists(this ITileSetAbstract map, string groupName)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            Check.ArgumentNotEmpty(groupName, "groupName"); //NOXLATE
+            foreach (var group in map.BaseMapLayerGroups)
+            {
+                if (groupName.Equals(group.Name))
+                    return true;
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Gets the tiled layers for the specified base map group
+        /// </summary>
+        /// <param name="map"></param>
+        /// <param name="groupName"></param>
+        /// <returns></returns>
+        public static IEnumerable<IBaseMapLayer> GetLayersForGroup(this ITileSetAbstract map, string groupName)
+        {
+            Check.ArgumentNotNull(map, "map"); //NOXLATE
+            Check.ArgumentNotEmpty(groupName, "groupName"); //NOXLATE
+
+            foreach (var group in map.BaseMapLayerGroups)
+            {
+                if (groupName.Equals(group.Name))
+                {
+                    return group.BaseMapLayer;
+                }
+            }
+
+            return new IBaseMapLayer[0];
+        }
+
+        /// <summary>
         /// Removes the given base layer group from the Map Definition
         /// </summary>
         /// <param name="map"></param>
@@ -163,7 +420,7 @@
             Check.ArgumentNotNull(tileSet, "tileSet"); //NOXLATE
             Check.ArgumentNotEmpty(coordinateSystem, "coordinateSystem"); //NOXLATE
 
-            if (tileSet.TileStoreParameters.TileProvider == "Default") //NOXLATE
+            if (tileSet.TileStoreParameters.TileProvider != "Default") //NOXLATE
                 throw new InvalidOperationException(string.Format(Strings.ParameterNotApplicableForTileProvider, "CoordinateSystem", tileSet.TileStoreParameters.TileProvider));
 
             tileSet.TileStoreParameters.SetParameter("CoordinateSystem", coordinateSystem); //NOXLATE
@@ -178,8 +435,8 @@
         {
             Check.ArgumentNotNull(tileSet, "tileSet"); //NOXLATE
             var p = tileSet.GetParameter("FiniteScaleList"); //NOXLATE
-            if (p != null)
-                return p.Value.Split(',').Select(x => x.Trim()).Select(x => Convert.ToDouble(x)).ToArray();
+            if (p != null && !string.IsNullOrEmpty(p.Value))
+                return p.Value.Split(',').Select(x => x.Trim()).Select(x => Convert.ToDouble(x)).OrderBy(s => s).ToArray();
             return new double[0];
         }
 
@@ -193,7 +450,7 @@
             Check.ArgumentNotNull(tileSet, "tileSet"); //NOXLATE
             Check.ArgumentNotNull(scales, "scales"); //NOXLATE
 
-            if (tileSet.TileStoreParameters.TileProvider == "Default") //NOXLATE
+            if (tileSet.TileStoreParameters.TileProvider != "Default") //NOXLATE
                 throw new InvalidOperationException(string.Format(Strings.ParameterNotApplicableForTileProvider, "FiniteScaleList", tileSet.TileStoreParameters.TileProvider)); //NOXLATE
 
             string str = string.Join(",", scales.OrderByDescending(x => x).Select(x => x.ToString(CultureInfo.InvariantCulture)).ToArray());

Modified: trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/v3_0_0/TileSetImpl.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/v3_0_0/TileSetImpl.cs	2015-02-18 10:23:23 UTC (rev 8545)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.ObjectModels/TileSetDefinition/v3_0_0/TileSetImpl.cs	2015-02-18 13:36:04 UTC (rev 8546)
@@ -172,11 +172,14 @@
         {
             get
             {
+                if (!this.SupportsCustomFiniteDisplayScales)
+                    throw new InvalidOperationException();
+
                 return this.GetDefaultFiniteScaleList();
             }
         }
 
-        public bool SupportsCustomFiniteDisplayScales
+        public bool SupportsCustomFiniteDisplayScalesUnconditionally
         {
             get
             {
@@ -184,6 +187,14 @@
             }
         }
 
+        public bool SupportsCustomFiniteDisplayScales
+        {
+            get
+            {
+                return this.TileStoreParameters.TileProvider == "Default";
+            }
+        }
+
         public IEnumerable<IBaseMapGroup> BaseMapLayerGroups
         {
             get 
@@ -229,6 +240,68 @@
                 this.BaseMapLayerGroup.Remove(grp);
             }
         }
+
+        public void AddFiniteDisplayScale(double value)
+        {
+            if (!this.SupportsCustomFiniteDisplayScales)
+                throw new InvalidOperationException();
+
+            this.SetDefaultFiniteScaleList(this.GetDefaultFiniteScaleList().Concat(new double[] { value }));
+        }
+
+        public void RemoveFiniteDisplayScale(double value)
+        {
+            if (!this.SupportsCustomFiniteDisplayScales)
+                throw new InvalidOperationException();
+
+            var list = new List<double>(this.GetDefaultFiniteScaleList());
+            if (list.Remove(value))
+                this.SetDefaultFiniteScaleList(list);
+        }
+
+        public int ScaleCount
+        {
+            get 
+            {
+                if (!this.SupportsCustomFiniteDisplayScales)
+                    throw new InvalidOperationException();
+                return this.FiniteDisplayScale.Count(); 
+            }
+        }
+
+        public void RemoveScaleAt(int index)
+        {
+            if (!this.SupportsCustomFiniteDisplayScales)
+                throw new InvalidOperationException();
+
+            if (index >= this.ScaleCount)
+                throw new ArgumentOutOfRangeException("index");
+
+            var list = new List<double>(this.GetDefaultFiniteScaleList());
+            list.RemoveAt(index);
+            this.SetDefaultFiniteScaleList(list);
+        }
+
+        public double GetScaleAt(int index)
+        {
+            if (!this.SupportsCustomFiniteDisplayScales)
+                throw new InvalidOperationException();
+
+            return this.GetDefaultFiniteScaleList().ElementAt(index);
+        }
+
+        public void SetFiniteDisplayScales(IEnumerable<double> scales)
+        {
+            this.SetDefaultFiniteScaleList(scales.OrderBy(s => s));
+        }
+
+        public void RemoveAllScales()
+        {
+            if (!this.SupportsCustomFiniteDisplayScales)
+                throw new InvalidOperationException();
+
+            this.SetDefaultFiniteScaleList(Enumerable.Empty<double>());
+        }
     }
 
     partial class Box2DType : IEnvelope



More information about the mapguide-commits mailing list