[mapguide-commits] r5300 - in sandbox/maestro-3.0: Maestro.Base/Commands Maestro.Base/Editor Maestro.Base/Properties Maestro.Base/UI Maestro.Editors Maestro.Editors/FeatureSource/Extensions Maestro.Editors/MapDefinition Maestro.Editors/Properties Maestro.Editors/WebLayout Maestro.Editors/WebLayout/Commands OSGeo.MapGuide.MaestroAPI/ObjectModels

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Oct 20 04:09:21 EDT 2010


Author: jng
Date: 2010-10-20 01:09:21 -0700 (Wed, 20 Oct 2010)
New Revision: 5300

Added:
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuModel.cs
Modified:
   sandbox/maestro-3.0/Maestro.Base/Commands/PasteCommand.cs
   sandbox/maestro-3.0/Maestro.Base/Editor/FsEditorOptionPanel.cs
   sandbox/maestro-3.0/Maestro.Base/Editor/XmlEditorDialog.cs
   sandbox/maestro-3.0/Maestro.Base/Properties/Resources.Designer.cs
   sandbox/maestro-3.0/Maestro.Base/Properties/Resources.resx
   sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.Designer.cs
   sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.cs
   sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/ExtendedClassSettings.cs
   sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/JoinSettings.cs
   sandbox/maestro-3.0/Maestro.Editors/Maestro.Editors.csproj
   sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.resx
   sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.resx
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/InvokeURLCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/CustomCommandPropertyCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutCommandsCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutEditorCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.Designer.cs
   sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSource.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSourceInterfaces.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs
   sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayoutInterfaces.cs
Log:
3.0 sandbox changes:
 - Fix paste command failing on cut/copied folders
 - Implement drag/drop moving for Site Explorer
 - Feature Source editor changes:
   - Implement xml configuration support.
   - Fix extensions editor on back of recent interface additions. Join editor is broken atm. We'll fix that later.
 - Map Definition editor changes:
   - Implement drag/drop support for Map Definition editor (from Site Explorer and within)
   - Fix extent computation to include tiled layers
 - Web Layout editor changes:
   - Complete implementation of menu editors
   - Implement adding of menu items from command list
   - Fix Invoke URL, Invoke Script and Search Command editors


Modified: sandbox/maestro-3.0/Maestro.Base/Commands/PasteCommand.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/Commands/PasteCommand.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/Commands/PasteCommand.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -63,18 +63,25 @@
                 
                 //Keep testing until we find a target resource identifier that 
                 //doesn't already exists
-                var name = ResourceIdentifier.GetName(item.ResourceId) + "." + ResourceIdentifier.GetResourceType(item.ResourceId).ToString();
+                var rid = new ResourceIdentifier(item.ResourceId);
+                var name = rid.IsFolder ? (rid.Name + "/") : (rid.Name + "." + rid.ResourceType.ToString());
                 var resId = folder.ResourceId + name;
                 int counter = 0;
                 while (conn.ResourceService.ResourceExists(resId))
                 {
                     counter++;
-                    var rname = name.Substring(0, name.IndexOf("."));
-                    var type = name.Substring(name.IndexOf("."));
 
-                    rname += " (" + counter + ")";
-
-                    resId = folder.ResourceId + rname + type;
+                    if (rid.IsFolder)
+                    {
+                        resId = folder.ResourceId + rid.Name + " (" + counter + ")/";
+                    }
+                    else
+                    {
+                        var rname = name.Substring(0, name.IndexOf("."));
+                        var type = name.Substring(name.IndexOf("."));
+                        rname += " (" + counter + ")";
+                        resId = folder.ResourceId + rname + type;
+                    }
                 }
 
                 if (item.ClipboardState == RepositoryItem.ClipboardAction.Copy)

Modified: sandbox/maestro-3.0/Maestro.Base/Editor/FsEditorOptionPanel.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/Editor/FsEditorOptionPanel.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/Editor/FsEditorOptionPanel.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -29,6 +29,7 @@
 using OSGeo.MapGuide.ObjectModels.FeatureSource;
 using OSGeo.MapGuide.ObjectModels.Capabilities;
 using OSGeo.MapGuide.MaestroAPI.Services;
+using Maestro.Editors;
 
 namespace Maestro.Base.Editor
 {
@@ -43,8 +44,9 @@
         private FdoProviderCapabilities _caps;
         private IFeatureService _fsvc;
         private IResourceService _rsvc;
+        private IEditorService _edsvc;
 
-        public override void Bind(Maestro.Editors.IEditorService service)
+        public override void Bind(IEditorService service)
         {
             //Only available on MGOS 2.2 and above
             this.LocalPreviewEnabled = service.SiteVersion >= new Version(2, 2);
@@ -52,6 +54,7 @@
             _caps = service.FeatureService.GetProviderCapabilities(_fs.Provider);
             _fsvc = service.FeatureService;
             _rsvc = service.ResourceService;
+            _edsvc = service;
             this.ConfigEnabled = _caps.Connection.SupportsConfiguration;
         }
 
@@ -76,7 +79,14 @@
 
         private void btnEditConfiguration_Click(object sender, EventArgs e)
         {
-
+            var content = _fs.GetConfigurationContent();
+            var dlg = new XmlEditorDialog(_edsvc);
+            dlg.XmlContent = content;
+            if (dlg.ShowDialog() == DialogResult.OK)
+            {
+                content = dlg.XmlContent;
+                _fs.SetConfigurationContent(content);
+            }
         }
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Base/Editor/XmlEditorDialog.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/Editor/XmlEditorDialog.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/Editor/XmlEditorDialog.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -88,11 +88,14 @@
             //Test that this is serializable
             try
             {
-                //Test by simply attempting to deserialize the current xml content
-                using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(this.XmlContent)))
+                if (_enableResourceTypeValidation)
                 {
-                    //Use original resource type to determine how to deserialize
-                    var obj = ResourceTypeRegistry.Deserialize(this.ResourceType, ms);
+                    //Test by simply attempting to deserialize the current xml content
+                    using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(this.XmlContent)))
+                    {
+                        //Use original resource type to determine how to deserialize
+                        var obj = ResourceTypeRegistry.Deserialize(this.ResourceType, ms);
+                    }
                 }
             }
             catch (Exception ex)
@@ -104,15 +107,22 @@
             warnings = warn.ToArray();
         }
 
+        private bool _enableResourceTypeValidation = false;
+
         public void SetXmlContent(string xml, ResourceTypes type)
         {
             _ed.XmlContent = xml;
             this.ResourceType = type;
+            _enableResourceTypeValidation = true;
         }
 
+        /// <summary>
+        /// Gets or sets the XML content for this dialog.
+        /// </summary>
         public string XmlContent
         {
             get { return _ed.XmlContent; }
+            set { _ed.XmlContent = value; }
         }
 
         private void btnCancel_Click(object sender, EventArgs e)

Modified: sandbox/maestro-3.0/Maestro.Base/Properties/Resources.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/Properties/Resources.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/Properties/Resources.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -292,6 +292,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Are you sure you want to move the following resources?.
+        /// </summary>
+        internal static string ConfirmMove {
+            get {
+                return ResourceManager.GetString("ConfirmMove", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to You are about to reset all preferences to default values. Are you sure you want to do this?.
         /// </summary>
         internal static string ConfirmResetPrefs {

Modified: sandbox/maestro-3.0/Maestro.Base/Properties/Resources.resx
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/Properties/Resources.resx	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/Properties/Resources.resx	2010-10-20 08:09:21 UTC (rev 5300)
@@ -709,4 +709,7 @@
   <data name="TPL_LP_DWF_NAME" xml:space="preserve">
     <value>DWF Load Procedure</value>
   </data>
+  <data name="ConfirmMove" xml:space="preserve">
+    <value>Are you sure you want to move the following resources?</value>
+  </data>
 </root>
\ No newline at end of file

Modified: sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -44,6 +44,7 @@
             // 
             // trvResources
             // 
+            this.trvResources.AllowDrop = true;
             this.trvResources.AsyncExpanding = true;
             this.trvResources.BackColor = System.Drawing.SystemColors.Window;
             this.trvResources.BorderStyle = System.Windows.Forms.BorderStyle.None;
@@ -63,9 +64,13 @@
             this.trvResources.Size = new System.Drawing.Size(233, 458);
             this.trvResources.TabIndex = 2;
             this.trvResources.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.trvResources_MouseDoubleClick);
+            this.trvResources.DragOver += new System.Windows.Forms.DragEventHandler(this.trvResources_DragOver);
             this.trvResources.MouseClick += new System.Windows.Forms.MouseEventHandler(this.trvResources_MouseClick);
+            this.trvResources.DragDrop += new System.Windows.Forms.DragEventHandler(this.trvResources_DragDrop);
             this.trvResources.Expanding += new System.EventHandler<Aga.Controls.Tree.TreeViewAdvEventArgs>(this.trvResources_Expanding);
+            this.trvResources.DragEnter += new System.Windows.Forms.DragEventHandler(this.trvResources_DragEnter);
             this.trvResources.Expanded += new System.EventHandler<Aga.Controls.Tree.TreeViewAdvEventArgs>(this.trvResources_Expanded);
+            this.trvResources.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.trvResources_ItemDrag);
             // 
             // rdResourceIcon
             // 

Modified: sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Base/UI/SiteExplorer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -31,6 +31,7 @@
 using OSGeo.MapGuide.MaestroAPI.Resource;
 using ICSharpCode.Core;
 using Maestro.Base.UI.Preferences;
+using Maestro.Shared.UI;
 
 namespace Maestro.Base.UI
 {
@@ -317,5 +318,141 @@
             else if (item.IsOpen)
                 e.BackgroundBrush = new SolidBrush(ocolor);
         }
+
+        private void trvResources_ItemDrag(object sender, ItemDragEventArgs e)
+        {
+            var nodes = e.Item as TreeNodeAdv[];
+            if (nodes != null)
+            {
+                List<ResourceIdentifier> rids = new List<ResourceIdentifier>();
+                foreach (var n in nodes)
+                {
+                    rids.Add(new ResourceIdentifier(((RepositoryItem)n.Tag).ResourceId));
+                }
+                trvResources.DoDragDrop(rids.ToArray(), DragDropEffects.All);
+            }
+        }
+
+        private void trvResources_DragDrop(object sender, DragEventArgs e)
+        {
+            var data = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (data == null || data.Length == 0)
+                return;
+
+            //See if the mouse is currently over a node
+            var node = trvResources.GetNodeAt(trvResources.PointToClient(new Point(e.X, e.Y)));
+            if (node == null)
+                return;
+
+            //Can only drop in a folder
+            var item = node.Tag as RepositoryItem;
+            if (item != null && item.IsFolder)
+            {
+                string folderId = item.ResourceId;
+                List<string> resIds = new List<string>();
+                foreach (var n in data)
+                {
+                    resIds.Add(n.ToString());
+                }
+
+                //I think it's nice to ask for confirmation
+                if (resIds.Count > 0)
+                {
+                    if (!MessageService.AskQuestion(Properties.Resources.ConfirmMove))
+                        return;
+                }
+
+                string [] folders = MoveResources(resIds, folderId);
+
+                foreach (var fid in folders)
+                {
+                    LoggingService.Info("Refreshing: " + fid);
+                    RefreshModel(fid);
+                }
+            }
+        }
+
+        private void trvResources_DragOver(object sender, DragEventArgs e)
+        {
+            var data = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (data == null || data.Length == 0)
+            {
+                e.Effect = DragDropEffects.None;
+                return;
+            }
+
+            //See if the mouse is currently over a node
+            var node = trvResources.GetNodeAt(trvResources.PointToClient(new Point(e.X, e.Y)));
+            if (node == null)
+            {
+                e.Effect = DragDropEffects.None;
+                return;
+            }
+
+            //Is it a folder?
+            var item = node.Tag as RepositoryItem;
+            if (item != null && item.IsFolder)
+            {
+                e.Effect = DragDropEffects.Move;
+            }
+            else
+            {
+                e.Effect = DragDropEffects.None;
+            }
+        }
+
+        private void trvResources_DragEnter(object sender, DragEventArgs e)
+        {
+            //TODO: There is a whole lot of interesting things we can do here
+            // (eg. Create a Feature Source from a dragged SDF file)
+        }
+
+        private string [] MoveResources(ICollection<string> resIds, string folderId)
+        {
+            var wb = Workbench.Instance;
+            var dlg = new ProgressDialog();
+            var worker = new ProgressDialog.DoBackgroundWork((w, e, args) =>
+            {
+                LengthyOperationProgressCallBack cb = (sender, cbe) =>
+                {
+                    w.ReportProgress(cbe.Progress, cbe.StatusMessage);
+                };
+
+                var f = (string)args[0];
+                var resourceIds = (ICollection<string>)args[1];
+
+                foreach (var r in resourceIds)
+                {
+                    if (ResourceIdentifier.IsFolderResource(r))
+                    {
+                        //IMPORTANT: We need to tweak the target resource id
+                        //otherwise the content *inside* the source folder is
+                        //moved instead of the folder itself!
+                        var rid = new ResourceIdentifier(r);
+                        var target = folderId + rid.Name + "/";
+                        _conn.ResourceService.MoveFolderWithReferences(r, target, null, cb);
+                    }
+                    else
+                        _conn.ResourceService.MoveResourceWithReferences(r, folderId, null, cb);
+                    //string msg = string.Format("Moving {0} to {1}", r, folderId);
+                }
+
+                //Collect affected folders and refresh them
+                Dictionary<string, string> folders = new Dictionary<string, string>();
+                folders.Add(folderId, folderId);
+                foreach (var n in resourceIds)
+                {
+                    var ri = new ResourceIdentifier(n);
+                    var parent = ri.ParentFolder;
+                    if (parent != null && !folders.ContainsKey(parent))
+                        folders.Add(parent, parent);
+                }
+
+                return folders.Keys;
+            });
+
+            var affectedFolders = (IEnumerable<string>)dlg.RunOperationAsync(wb, worker, folderId, resIds);
+            return new List<string>(affectedFolders).ToArray();
+        }
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/ExtendedClassSettings.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/ExtendedClassSettings.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/ExtendedClassSettings.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -43,11 +43,14 @@
             cmbBaseClass.DisplayMember = "QualifiedNameDecoded";
             cmbBaseClass.ValueMember = "QualifiedNameDecoded";
             cmbBaseClass.DataSource = classes;
+            ext.PropertyChanged += (sender, e) => { OnResourceChanged(); };
+
+            //HACK
+            if (string.IsNullOrEmpty(ext.FeatureClass))
+                ext.FeatureClass = classes[0].QualifiedNameDecoded;
             
             TextBoxBinder.BindText(txtExtendedName, ext, "Name");
             ComboBoxBinder.BindSelectedIndexChanged(cmbBaseClass, "SelectedValue", ext, "FeatureClass");
-
-            ext.PropertyChanged += (sender, e) => { OnResourceChanged(); };
         }
 
         //private void txtExtendedName_TextChanged(object sender, EventArgs e)

Modified: sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/JoinSettings.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/JoinSettings.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/FeatureSource/Extensions/JoinSettings.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -45,20 +45,26 @@
         public JoinSettings(FeatureSetColumn[] primaryColumns, IAttributeRelation rel)
             : this()
         {
-            //FIXME: Initial load will set the correct secondary class, but not the correct
-            //secondary property list!!!
+            Check.NotNull(rel, "rel");
 
+            //FIXME: Everything :( This control is currently broken. I have learned the hard way that dependent comboboxes + Automated databinding = Recipe for trouble!
+            //So re-design this control to *not* use comboboxes for such cases.
+            
             _init = true;
             grdJoinKeys.AutoGenerateColumns = false;
             _rel = rel;
 
             TextBoxBinder.BindText(txtJoinName, _rel, "Name");
-            TextBoxBinder.BindText(txtFeatureSource, _rel, "ResourceId");
+            //TextBoxBinder.BindText(txtFeatureSource, _rel, "ResourceId");
             txtFeatureSource.TextChanged += new EventHandler(txtFeatureSource_TextChanged);
             //rb.ReadValue();
             UpdateJoinClass();
 
-            CheckBoxBinder.BindChecked(chkForceOneToOne, _rel, "ForceOneToOne");
+            //CheckBoxBinder.BindChecked(chkForceOneToOne, _rel, "ForceOneToOne");
+            //CheckBoxBinder is failing me here, so let's do it manually
+            chkForceOneToOne.Checked = _rel.ForceOneToOne;
+            chkForceOneToOne.CheckedChanged += (s, e) => { _rel.ForceOneToOne = chkForceOneToOne.Checked; };
+
             var bin = ComboBoxBinder.BindSelectedIndexChanged(cmbFeatureClass, "SelectedValue", _rel, "AttributeClass");
             bin.ReadValue();
 
@@ -80,6 +86,7 @@
 
         void txtFeatureSource_TextChanged(object sender, EventArgs e)
         {
+            _rel.ResourceId = txtFeatureSource.Text;
             UpdateJoinClass();
         }
 

Modified: sandbox/maestro-3.0/Maestro.Editors/Maestro.Editors.csproj
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/Maestro.Editors.csproj	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/Maestro.Editors.csproj	2010-10-20 08:09:21 UTC (rev 5300)
@@ -544,6 +544,7 @@
     <Compile Include="WebLayout\MenuEditorCtrl.Designer.cs">
       <DependentUpon>MenuEditorCtrl.cs</DependentUpon>
     </Compile>
+    <Compile Include="WebLayout\MenuModel.cs" />
     <Compile Include="WebLayout\WebLayoutCommandsCtrl.cs">
       <SubType>UserControl</SubType>
     </Compile>

Modified: sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -112,6 +112,7 @@
             // 
             // trvLayersGroup
             // 
+            this.trvLayersGroup.AllowDrop = true;
             this.trvLayersGroup.BackColor = System.Drawing.SystemColors.Window;
             this.trvLayersGroup.BorderStyle = System.Windows.Forms.BorderStyle.None;
             this.trvLayersGroup.DefaultToolTipProvider = null;
@@ -128,7 +129,11 @@
             this.trvLayersGroup.TabIndex = 1;
             this.trvLayersGroup.Text = "treeViewAdv1";
             this.trvLayersGroup.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.trvLayersGroup_MouseDoubleClick);
+            this.trvLayersGroup.DragOver += new System.Windows.Forms.DragEventHandler(this.trvLayersGroup_DragOver);
             this.trvLayersGroup.MouseClick += new System.Windows.Forms.MouseEventHandler(this.trvLayersGroup_MouseClick);
+            this.trvLayersGroup.DragDrop += new System.Windows.Forms.DragEventHandler(this.trvLayersGroup_DragDrop);
+            this.trvLayersGroup.DragEnter += new System.Windows.Forms.DragEventHandler(this.trvLayersGroup_DragEnter);
+            this.trvLayersGroup.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.trvLayersGroup_ItemDrag);
             // 
             // NODE_GROUP_ICON
             // 
@@ -234,6 +239,7 @@
             // 
             // trvLayerDrawingOrder
             // 
+            this.trvLayerDrawingOrder.AllowDrop = true;
             this.trvLayerDrawingOrder.BackColor = System.Drawing.SystemColors.Window;
             this.trvLayerDrawingOrder.BorderStyle = System.Windows.Forms.BorderStyle.None;
             this.trvLayerDrawingOrder.DefaultToolTipProvider = null;
@@ -250,7 +256,11 @@
             this.trvLayerDrawingOrder.TabIndex = 1;
             this.trvLayerDrawingOrder.Text = "treeViewAdv1";
             this.trvLayerDrawingOrder.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.trvLayerDrawingOrder_MouseDoubleClick);
+            this.trvLayerDrawingOrder.DragOver += new System.Windows.Forms.DragEventHandler(this.trvLayerDrawingOrder_DragOver);
             this.trvLayerDrawingOrder.MouseClick += new System.Windows.Forms.MouseEventHandler(this.trvLayerDrawingOrder_MouseClick);
+            this.trvLayerDrawingOrder.DragDrop += new System.Windows.Forms.DragEventHandler(this.trvLayerDrawingOrder_DragDrop);
+            this.trvLayerDrawingOrder.DragEnter += new System.Windows.Forms.DragEventHandler(this.trvLayerDrawingOrder_DragEnter);
+            this.trvLayerDrawingOrder.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.trvLayerDrawingOrder_ItemDrag);
             // 
             // NODE_DRAW_ICON
             // 
@@ -367,6 +377,7 @@
             // 
             // trvBaseLayers
             // 
+            this.trvBaseLayers.AllowDrop = true;
             this.trvBaseLayers.BackColor = System.Drawing.SystemColors.Window;
             this.trvBaseLayers.BorderStyle = System.Windows.Forms.BorderStyle.None;
             this.trvBaseLayers.DefaultToolTipProvider = null;
@@ -383,7 +394,11 @@
             this.trvBaseLayers.TabIndex = 1;
             this.trvBaseLayers.Text = "treeViewAdv1";
             this.trvBaseLayers.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.trvBaseLayers_MouseDoubleClick);
+            this.trvBaseLayers.DragOver += new System.Windows.Forms.DragEventHandler(this.trvBaseLayers_DragOver);
             this.trvBaseLayers.MouseClick += new System.Windows.Forms.MouseEventHandler(this.trvBaseLayers_MouseClick);
+            this.trvBaseLayers.DragDrop += new System.Windows.Forms.DragEventHandler(this.trvBaseLayers_DragDrop);
+            this.trvBaseLayers.DragEnter += new System.Windows.Forms.DragEventHandler(this.trvBaseLayers_DragEnter);
+            this.trvBaseLayers.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.trvBaseLayers_ItemDrag);
             // 
             // nodeIcon1
             // 

Modified: sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -384,6 +384,27 @@
             return name;
         }
 
+        private static string GenerateLayerName(string layerId, IMapDefinition baseMapDef)
+        {
+            Check.NotNull(baseMapDef, "baseMapDef");
+            Check.NotEmpty(layerId, "layerId");
+
+            int counter = 0;
+            string prefix = ResourceIdentifier.GetName(layerId);
+            string name = prefix;
+            if (baseMapDef.GetLayerByName(name) != null)
+            {
+                name = prefix + counter;
+            }
+            while (baseMapDef.GetLayerByName(name) != null)
+            {
+                counter++;
+                name = prefix + counter;
+            }
+
+            return name;
+        }
+
         private static string GenerateBaseLayerName(string layerId, IBaseMapDefinition baseMapDef)
         {
             Check.NotNull(baseMapDef, "baseMapDef");
@@ -487,5 +508,194 @@
                 }
             }
         }
+
+        private void trvLayersGroup_ItemDrag(object sender, ItemDragEventArgs e)
+        {
+            trvLayersGroup.DoDragDrop(e.Item, DragDropEffects.All);
+        }
+
+        private void trvLayersGroup_DragEnter(object sender, DragEventArgs e)
+        {
+            HandleDragEnter(e);
+        }
+
+        private static void HandleDragEnter(DragEventArgs e)
+        {
+            //Accepting all resource id drops
+            var rids = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (rids == null || rids.Length == 0)
+            {
+                e.Effect = DragDropEffects.None;
+                return;
+            }
+
+            //But only of the Layer Definition kind
+            if (rids.Length == 1 && rids[0].ResourceType != ResourceTypes.LayerDefinition)
+            {
+                e.Effect = DragDropEffects.None;
+                return;
+            }
+
+            //Even in multiples
+            foreach (var r in rids)
+            {
+                if (r.ResourceType != ResourceTypes.LayerDefinition)
+                {
+                    e.Effect = DragDropEffects.None;
+                    return;
+                }
+            }
+        }
+
+        private void trvLayersGroup_DragDrop(object sender, DragEventArgs e)
+        {
+            var rids = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (rids == null || rids.Length == 0)
+                return;
+
+            IMapLayerGroup parent = null;
+            var node = trvLayersGroup.GetNodeAt(trvLayersGroup.PointToClient(new Point(e.X, e.Y)));
+            if (node != null)
+            {
+                var gi = node.Tag as GroupItem;
+                if (gi != null)
+                    parent = gi.Tag;
+            }
+
+            int added = 0;
+            foreach (var rid in rids)
+            {
+                if (rid.ResourceType == ResourceTypes.LayerDefinition)
+                { 
+                    var name = GenerateLayerName(rid.ToString(), _map);
+                    var layer = _map.AddLayer(parent == null ? null : parent.Name, name, rid.ToString());
+                    added++;
+                }
+            }
+
+            if (added > 0)
+            {
+                //TODO: Fine-grain invalidation
+                RefreshModels();
+            }
+        }
+
+        private void trvLayersGroup_DragOver(object sender, DragEventArgs e)
+        {
+            HandleDragOver(e);
+        }
+
+        private static void HandleDragOver(DragEventArgs e)
+        {
+            var rids = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (rids == null || rids.Length == 0)
+            {
+                e.Effect = DragDropEffects.None;
+                return;
+            }
+
+            e.Effect = DragDropEffects.Copy;
+        }
+
+        private void trvLayerDrawingOrder_DragDrop(object sender, DragEventArgs e)
+        {
+            var rids = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (rids == null || rids.Length == 0)
+                return;
+
+            IMapLayer layer = null;
+            var node = trvLayersGroup.GetNodeAt(trvLayersGroup.PointToClient(new Point(e.X, e.Y)));
+            if (node != null)
+            {
+                var li = node.Tag as LayerItem;
+                if (li != null)
+                    layer = li.Tag;
+            }
+
+            int added = 0;
+            foreach (var rid in rids)
+            {
+                if (rid.ResourceType == ResourceTypes.LayerDefinition)
+                {
+                    var name = GenerateLayerName(rid.ToString(), _map);
+                    //var layer = _map.AddLayer(parent == null ? null : parent.Name, name, rid.ToString());
+                    var lyr = _map.AddLayer(layer, null, name, rid.ToString());
+                    added++;
+                }
+            }
+
+            if (added > 0)
+            {
+                //TODO: Fine-grain invalidation
+                RefreshModels();
+            }
+        }
+
+        private void trvLayerDrawingOrder_DragEnter(object sender, DragEventArgs e)
+        {
+            HandleDragEnter(e);
+        }
+
+        private void trvLayerDrawingOrder_DragOver(object sender, DragEventArgs e)
+        {
+            HandleDragOver(e);
+        }
+
+        private void trvLayerDrawingOrder_ItemDrag(object sender, ItemDragEventArgs e)
+        {
+            trvLayerDrawingOrder.DoDragDrop(e.Item, DragDropEffects.All);
+        }
+
+        private void trvBaseLayers_ItemDrag(object sender, ItemDragEventArgs e)
+        {
+            trvBaseLayers.DoDragDrop(e.Item, DragDropEffects.All);
+        }
+
+        private void trvBaseLayers_DragDrop(object sender, DragEventArgs e)
+        {
+            var rids = e.Data.GetData(typeof(ResourceIdentifier[])) as ResourceIdentifier[];
+            if (rids == null || rids.Length == 0)
+                return;
+
+            var node = trvLayersGroup.GetNodeAt(trvLayersGroup.PointToClient(new Point(e.X, e.Y)));
+
+            IBaseMapGroup group = null;
+            if (node != null && node.Tag is BaseLayerGroupItem)
+            {
+                group = ((BaseLayerGroupItem)node.Tag).Tag;
+            }
+
+            int added = 0;
+            //No group? Let's make one!
+            if (group == null)
+            {
+                _map.InitBaseMap();
+                group = _map.BaseMap.AddBaseLayerGroup(GenerateBaseGroupName(_map));
+
+                foreach (var rid in rids)
+                {
+                    if (rid.ResourceType == ResourceTypes.LayerDefinition)
+                    {
+                        group.AddLayer(GenerateBaseLayerName(rid.ToString(), _map.BaseMap), rid.ToString());
+                        added++;
+                    }
+                }
+            }
+
+            if (added > 0)
+            {
+                _tiledLayerModel.Invalidate();
+            }
+        }
+
+        private void trvBaseLayers_DragEnter(object sender, DragEventArgs e)
+        {
+            HandleDragEnter(e);
+        }
+
+        private void trvBaseLayers_DragOver(object sender, DragEventArgs e)
+        {
+            HandleDragOver(e);
+        }
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.resx
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.resx	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapLayersSectionCtrl.resx	2010-10-20 08:09:21 UTC (rev 5300)
@@ -129,7 +129,7 @@
   <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
-  <metadata name="toolStrip3.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>221, 17</value>
+  <metadata name="toolStrip2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>116, 17</value>
   </metadata>
 </root>
\ No newline at end of file

Modified: sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -115,7 +115,6 @@
             // 
             // btnSetZoom
             // 
-            this.btnSetZoom.Enabled = false;
             this.btnSetZoom.ImeMode = System.Windows.Forms.ImeMode.NoControl;
             this.btnSetZoom.Location = new System.Drawing.Point(403, 22);
             this.btnSetZoom.Name = "btnSetZoom";

Modified: sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/MapDefinition/MapSettingsSectionCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -87,10 +87,6 @@
                 {
                     cmbBackgroundColor.CurrentColor = _map.BackgroundColor;
                 }
-                else if (e.PropertyName == "MapLayer")
-                {
-                    btnSetZoom.Enabled = _map.GetLayerCount() > 0;
-                }
             };
 
             TextBoxBinder.BindText(txtLowerX, _map.Extents, "MinX");
@@ -119,6 +115,16 @@
                 {
                     layers.Add((ILayerDefinition)_service.ResourceService.GetResource(lyr.ResourceId));
                 }
+                if (_map.BaseMap != null)
+                {
+                    foreach (var group in _map.BaseMap.BaseMapLayerGroup)
+                    {
+                        foreach (var layer in group.BaseMapLayer)
+                        {
+                            layers.Add((ILayerDefinition)_service.ResourceService.GetResource(layer.ResourceId));
+                        }
+                    }
+                }
                 var env = Util.GetCombinedExtents(layers);
 
                 _map.SetExtents(env.MinX, env.MinY, env.MaxX, env.MaxY);

Modified: sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -1555,6 +1555,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to New Flyout.
+        /// </summary>
+        internal static string NewFlyout {
+            get {
+                return ResourceManager.GetString("NewFlyout", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to New folder.
         /// </summary>
         internal static string NewFolder {
@@ -1759,6 +1768,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Add this item to the flyout? Clicking &quot;No&quot; will add it before the flyout.
+        /// </summary>
+        internal static string QuestionAddItemToFlyout {
+            get {
+                return ResourceManager.GetString("QuestionAddItemToFlyout", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to RDBMS Feature Source.
         /// </summary>
         internal static string RdbmsFeatureSource {
@@ -1846,6 +1864,15 @@
         }
         
         /// <summary>
+        ///   Looks up a localized string similar to Select Layer.
+        /// </summary>
+        internal static string SelectLayer {
+            get {
+                return ResourceManager.GetString("SelectLayer", resourceCulture);
+            }
+        }
+        
+        /// <summary>
         ///   Looks up a localized string similar to Select the package file to edit.
         /// </summary>
         internal static string SelectPackageFile {
@@ -1886,6 +1913,15 @@
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Specify a map for this web layout.
+        /// </summary>
+        internal static string SpecifyMapForWebLayout {
+            get {
+                return ResourceManager.GetString("SpecifyMapForWebLayout", resourceCulture);
+            }
+        }
+        
         internal static System.Drawing.Bitmap sql {
             get {
                 object obj = ResourceManager.GetObject("sql", resourceCulture);

Modified: sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.resx
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.resx	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/Properties/Resources.resx	2010-10-20 08:09:21 UTC (rev 5300)
@@ -952,4 +952,17 @@
   <data name="FilterSqlite" xml:space="preserve">
     <value>SQLite files|*.sqlite;*.db;*.sdx;*.slt</value>
   </data>
+  <data name="NewFlyout" xml:space="preserve">
+    <value>New Flyout</value>
+  </data>
+  <data name="QuestionAddItemToFlyout" xml:space="preserve">
+    <value>Add this item to the flyout? Clicking "No" will add it before the flyout</value>
+    <comment>A question to confirm whether dropping a menu item on a flyout will add it to the flyout or before the flyout</comment>
+  </data>
+  <data name="SpecifyMapForWebLayout" xml:space="preserve">
+    <value>Specify a map for this web layout</value>
+  </data>
+  <data name="SelectLayer" xml:space="preserve">
+    <value>Select Layer</value>
+  </data>
 </root>
\ No newline at end of file

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/InvokeURLCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/InvokeURLCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/InvokeURLCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -44,6 +44,8 @@
             _edsvc = service;
         }
 
+        private BindingList<IParameterPair> _params = new BindingList<IParameterPair>();
+
         internal void Bind(IInvokeUrlCommand invokeUrlCommandType, IEditorService service)
         {
             cmbTargetFrame.DataSource = Enum.GetValues(typeof(TargetType));
@@ -54,18 +56,43 @@
             TextBoxBinder.BindText(txtFrame, invokeUrlCommandType, "TargetFrame");
             ComboBoxBinder.BindSelectedIndexChanged(cmbTargetFrame, "SelectedItem", invokeUrlCommandType, "Target");
             CheckBoxBinder.BindChecked(chkDisableIfEmpty, invokeUrlCommandType, "DisableIfSelectionEmpty");
-            grdParameters.DataSource = invokeUrlCommandType.AdditionalParameter;
-            lstLayers.DataSource = invokeUrlCommandType.LayerSet;
 
+            foreach (var p in invokeUrlCommandType.AdditionalParameter)
+            {
+                _params.Add(p);
+            }
+            grdParameters.DataSource = _params;
+            _params.ListChanged += OnParamsListChanged;
+            _params.AddingNew += OnAddingNew;
+            lstLayers.DataSource = invokeUrlCommandType.LayerSet.Layer;
+
             invokeUrlCommandType.PropertyChanged += OnCommandPropertyChanged;
             _cmd = invokeUrlCommandType;
         }
 
+        void OnAddingNew(object sender, AddingNewEventArgs e)
+        {
+            e.NewObject = _cmd.CreateParameter("", "");
+        }
+
+        void OnParamsListChanged(object sender, ListChangedEventArgs e)
+        {
+            switch (e.ListChangedType)
+            {
+                case ListChangedType.ItemAdded:
+                    _cmd.AddParameter(_params[e.NewIndex]);
+                    break;
+            }
+        }
+
         protected override void UnsubscribeEventHandlers()
         {
             if (_cmd != null)
                 _cmd.PropertyChanged -= OnCommandPropertyChanged;
 
+            _params.ListChanged -= OnParamsListChanged;
+            _params.AddingNew -= OnAddingNew;
+
             base.UnsubscribeEventHandlers();
         }
 

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -30,23 +30,28 @@
         {
             this.toolStrip1 = new System.Windows.Forms.ToolStrip();
             this.panel1 = new System.Windows.Forms.Panel();
-            this.label1 = new System.Windows.Forms.Label();
-            this.cmbLayers = new System.Windows.Forms.ComboBox();
-            this.label2 = new System.Windows.Forms.Label();
-            this.txtPrompt = new System.Windows.Forms.TextBox();
-            this.label3 = new System.Windows.Forms.Label();
-            this.txtFilter = new System.Windows.Forms.TextBox();
-            this.btnBrowse = new System.Windows.Forms.Button();
-            this.label4 = new System.Windows.Forms.Label();
-            this.numLimit = new System.Windows.Forms.NumericUpDown();
-            this.label5 = new System.Windows.Forms.Label();
-            this.label6 = new System.Windows.Forms.Label();
             this.grdOutputColumns = new System.Windows.Forms.DataGridView();
             this.COL_NAME = new System.Windows.Forms.DataGridViewTextBoxColumn();
             this.COL_PROPERTY = new System.Windows.Forms.DataGridViewComboBoxColumn();
+            this.label6 = new System.Windows.Forms.Label();
+            this.label5 = new System.Windows.Forms.Label();
+            this.numLimit = new System.Windows.Forms.NumericUpDown();
+            this.label4 = new System.Windows.Forms.Label();
+            this.btnBrowse = new System.Windows.Forms.Button();
+            this.txtFilter = new System.Windows.Forms.TextBox();
+            this.label3 = new System.Windows.Forms.Label();
+            this.txtPrompt = new System.Windows.Forms.TextBox();
+            this.label2 = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
+            this.txtLayer = new System.Windows.Forms.TextBox();
+            this.btnBrowseLayer = new System.Windows.Forms.Button();
+            this.txtFrame = new System.Windows.Forms.TextBox();
+            this.cmbTargetFrame = new System.Windows.Forms.ComboBox();
+            this.label7 = new System.Windows.Forms.Label();
+            this.label8 = new System.Windows.Forms.Label();
             this.panel1.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.grdOutputColumns)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.numLimit)).BeginInit();
-            ((System.ComponentModel.ISupportInitialize)(this.grdOutputColumns)).BeginInit();
             this.SuspendLayout();
             // 
             // toolStrip1
@@ -60,6 +65,12 @@
             // 
             // panel1
             // 
+            this.panel1.Controls.Add(this.txtFrame);
+            this.panel1.Controls.Add(this.cmbTargetFrame);
+            this.panel1.Controls.Add(this.label7);
+            this.panel1.Controls.Add(this.label8);
+            this.panel1.Controls.Add(this.btnBrowseLayer);
+            this.panel1.Controls.Add(this.txtLayer);
             this.panel1.Controls.Add(this.grdOutputColumns);
             this.panel1.Controls.Add(this.label6);
             this.panel1.Controls.Add(this.label5);
@@ -70,7 +81,6 @@
             this.panel1.Controls.Add(this.label3);
             this.panel1.Controls.Add(this.txtPrompt);
             this.panel1.Controls.Add(this.label2);
-            this.panel1.Controls.Add(this.cmbLayers);
             this.panel1.Controls.Add(this.label1);
             this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
             this.panel1.Location = new System.Drawing.Point(0, 0);
@@ -78,65 +88,78 @@
             this.panel1.Size = new System.Drawing.Size(332, 392);
             this.panel1.TabIndex = 1;
             // 
-            // label1
+            // grdOutputColumns
             // 
-            this.label1.AutoSize = true;
-            this.label1.Location = new System.Drawing.Point(14, 15);
-            this.label1.Name = "label1";
-            this.label1.Size = new System.Drawing.Size(100, 13);
-            this.label1.TabIndex = 0;
-            this.label1.Text = "Search on this layer";
+            this.grdOutputColumns.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.grdOutputColumns.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+            this.grdOutputColumns.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+            this.COL_NAME,
+            this.COL_PROPERTY});
+            this.grdOutputColumns.Location = new System.Drawing.Point(17, 242);
+            this.grdOutputColumns.Name = "grdOutputColumns";
+            this.grdOutputColumns.Size = new System.Drawing.Size(296, 133);
+            this.grdOutputColumns.TabIndex = 11;
             // 
-            // cmbLayers
+            // COL_NAME
             // 
-            this.cmbLayers.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-            this.cmbLayers.FormattingEnabled = true;
-            this.cmbLayers.Location = new System.Drawing.Point(17, 31);
-            this.cmbLayers.Name = "cmbLayers";
-            this.cmbLayers.Size = new System.Drawing.Size(296, 21);
-            this.cmbLayers.TabIndex = 1;
-            this.cmbLayers.SelectedIndexChanged += new System.EventHandler(this.cmbLayers_SelectedIndexChanged);
+            this.COL_NAME.DataPropertyName = "Name";
+            this.COL_NAME.HeaderText = "Name";
+            this.COL_NAME.Name = "COL_NAME";
+            this.COL_NAME.Resizable = System.Windows.Forms.DataGridViewTriState.True;
+            this.COL_NAME.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
             // 
-            // label2
+            // COL_PROPERTY
             // 
-            this.label2.AutoSize = true;
-            this.label2.Location = new System.Drawing.Point(14, 61);
-            this.label2.Name = "label2";
-            this.label2.Size = new System.Drawing.Size(77, 13);
-            this.label2.TabIndex = 2;
-            this.label2.Text = "Search Prompt";
+            this.COL_PROPERTY.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
+            this.COL_PROPERTY.DataPropertyName = "Property";
+            this.COL_PROPERTY.HeaderText = "Property";
+            this.COL_PROPERTY.Name = "COL_PROPERTY";
             // 
-            // txtPrompt
+            // label6
             // 
-            this.txtPrompt.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                        | System.Windows.Forms.AnchorStyles.Right)));
-            this.txtPrompt.Location = new System.Drawing.Point(17, 77);
-            this.txtPrompt.Name = "txtPrompt";
-            this.txtPrompt.Size = new System.Drawing.Size(296, 20);
-            this.txtPrompt.TabIndex = 3;
+            this.label6.AutoSize = true;
+            this.label6.Location = new System.Drawing.Point(14, 226);
+            this.label6.Name = "label6";
+            this.label6.Size = new System.Drawing.Size(82, 13);
+            this.label6.TabIndex = 10;
+            this.label6.Text = "Output Columns";
             // 
-            // label3
+            // label5
             // 
-            this.label3.AutoSize = true;
-            this.label3.Location = new System.Drawing.Point(14, 109);
-            this.label3.Name = "label3";
-            this.label3.Size = new System.Drawing.Size(60, 13);
-            this.label3.TabIndex = 4;
-            this.label3.Text = "Query Filter";
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(220, 199);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(37, 13);
+            this.label5.TabIndex = 9;
+            this.label5.Text = "results";
             // 
-            // txtFilter
+            // numLimit
             // 
-            this.txtFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
-                        | System.Windows.Forms.AnchorStyles.Right)));
-            this.txtFilter.Location = new System.Drawing.Point(17, 125);
-            this.txtFilter.Name = "txtFilter";
-            this.txtFilter.Size = new System.Drawing.Size(265, 20);
-            this.txtFilter.TabIndex = 5;
+            this.numLimit.Location = new System.Drawing.Point(153, 197);
+            this.numLimit.Maximum = new decimal(new int[] {
+            1000000,
+            0,
+            0,
+            0});
+            this.numLimit.Name = "numLimit";
+            this.numLimit.Size = new System.Drawing.Size(61, 20);
+            this.numLimit.TabIndex = 8;
             // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(14, 199);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(130, 13);
+            this.label4.TabIndex = 7;
+            this.label4.Text = "Restrict Search Results to";
+            // 
             // btnBrowse
             // 
             this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-            this.btnBrowse.Location = new System.Drawing.Point(286, 123);
+            this.btnBrowse.Location = new System.Drawing.Point(286, 163);
             this.btnBrowse.Name = "btnBrowse";
             this.btnBrowse.Size = new System.Drawing.Size(27, 23);
             this.btnBrowse.TabIndex = 6;
@@ -144,81 +167,124 @@
             this.btnBrowse.UseVisualStyleBackColor = true;
             this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
             // 
-            // label4
+            // txtFilter
             // 
-            this.label4.AutoSize = true;
-            this.label4.Location = new System.Drawing.Point(14, 161);
-            this.label4.Name = "label4";
-            this.label4.Size = new System.Drawing.Size(130, 13);
-            this.label4.TabIndex = 7;
-            this.label4.Text = "Restrict Search Results to";
+            this.txtFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtFilter.Location = new System.Drawing.Point(17, 165);
+            this.txtFilter.Name = "txtFilter";
+            this.txtFilter.Size = new System.Drawing.Size(265, 20);
+            this.txtFilter.TabIndex = 5;
             // 
-            // numLimit
+            // label3
             // 
-            this.numLimit.Location = new System.Drawing.Point(153, 159);
-            this.numLimit.Name = "numLimit";
-            this.numLimit.Size = new System.Drawing.Size(61, 20);
-            this.numLimit.TabIndex = 8;
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(14, 149);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(60, 13);
+            this.label3.TabIndex = 4;
+            this.label3.Text = "Query Filter";
             // 
-            // label5
+            // txtPrompt
             // 
-            this.label5.AutoSize = true;
-            this.label5.Location = new System.Drawing.Point(220, 161);
-            this.label5.Name = "label5";
-            this.label5.Size = new System.Drawing.Size(37, 13);
-            this.label5.TabIndex = 9;
-            this.label5.Text = "results";
+            this.txtPrompt.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtPrompt.Location = new System.Drawing.Point(17, 126);
+            this.txtPrompt.Name = "txtPrompt";
+            this.txtPrompt.Size = new System.Drawing.Size(296, 20);
+            this.txtPrompt.TabIndex = 3;
             // 
-            // label6
+            // label2
             // 
-            this.label6.AutoSize = true;
-            this.label6.Location = new System.Drawing.Point(14, 190);
-            this.label6.Name = "label6";
-            this.label6.Size = new System.Drawing.Size(82, 13);
-            this.label6.TabIndex = 10;
-            this.label6.Text = "Output Columns";
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(14, 110);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(77, 13);
+            this.label2.TabIndex = 2;
+            this.label2.Text = "Search Prompt";
             // 
-            // grdOutputColumns
+            // label1
             // 
-            this.grdOutputColumns.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
-                        | System.Windows.Forms.AnchorStyles.Left)
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(14, 71);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(100, 13);
+            this.label1.TabIndex = 0;
+            this.label1.Text = "Search on this layer";
+            // 
+            // txtLayer
+            // 
+            this.txtLayer.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
                         | System.Windows.Forms.AnchorStyles.Right)));
-            this.grdOutputColumns.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
-            this.grdOutputColumns.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
-            this.COL_NAME,
-            this.COL_PROPERTY});
-            this.grdOutputColumns.Location = new System.Drawing.Point(17, 206);
-            this.grdOutputColumns.Name = "grdOutputColumns";
-            this.grdOutputColumns.Size = new System.Drawing.Size(296, 169);
-            this.grdOutputColumns.TabIndex = 11;
+            this.txtLayer.Location = new System.Drawing.Point(17, 87);
+            this.txtLayer.Name = "txtLayer";
+            this.txtLayer.ReadOnly = true;
+            this.txtLayer.Size = new System.Drawing.Size(265, 20);
+            this.txtLayer.TabIndex = 12;
+            this.txtLayer.TextChanged += new System.EventHandler(this.txtLayer_TextChanged);
             // 
-            // COL_NAME
+            // btnBrowseLayer
             // 
-            this.COL_NAME.DataPropertyName = "Name";
-            this.COL_NAME.HeaderText = "Name";
-            this.COL_NAME.Name = "COL_NAME";
-            this.COL_NAME.Resizable = System.Windows.Forms.DataGridViewTriState.True;
-            this.COL_NAME.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable;
+            this.btnBrowseLayer.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+            this.btnBrowseLayer.Location = new System.Drawing.Point(286, 85);
+            this.btnBrowseLayer.Name = "btnBrowseLayer";
+            this.btnBrowseLayer.Size = new System.Drawing.Size(27, 23);
+            this.btnBrowseLayer.TabIndex = 13;
+            this.btnBrowseLayer.Text = "...";
+            this.btnBrowseLayer.UseVisualStyleBackColor = true;
+            this.btnBrowseLayer.Click += new System.EventHandler(this.btnBrowseLayer_Click);
             // 
-            // COL_PROPERTY
+            // txtFrame
             // 
-            this.COL_PROPERTY.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
-            this.COL_PROPERTY.DataPropertyName = "Property";
-            this.COL_PROPERTY.HeaderText = "Property";
-            this.COL_PROPERTY.Name = "COL_PROPERTY";
+            this.txtFrame.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.txtFrame.Location = new System.Drawing.Point(74, 40);
+            this.txtFrame.Name = "txtFrame";
+            this.txtFrame.Size = new System.Drawing.Size(239, 20);
+            this.txtFrame.TabIndex = 17;
             // 
+            // cmbTargetFrame
+            // 
+            this.cmbTargetFrame.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+                        | System.Windows.Forms.AnchorStyles.Right)));
+            this.cmbTargetFrame.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+            this.cmbTargetFrame.FormattingEnabled = true;
+            this.cmbTargetFrame.Location = new System.Drawing.Point(74, 13);
+            this.cmbTargetFrame.Name = "cmbTargetFrame";
+            this.cmbTargetFrame.Size = new System.Drawing.Size(239, 21);
+            this.cmbTargetFrame.TabIndex = 16;
+            // 
+            // label7
+            // 
+            this.label7.AutoSize = true;
+            this.label7.Location = new System.Drawing.Point(14, 43);
+            this.label7.Name = "label7";
+            this.label7.Size = new System.Drawing.Size(36, 13);
+            this.label7.TabIndex = 15;
+            this.label7.Text = "Frame";
+            // 
+            // label8
+            // 
+            this.label8.AutoSize = true;
+            this.label8.Location = new System.Drawing.Point(14, 16);
+            this.label8.Name = "label8";
+            this.label8.Size = new System.Drawing.Size(38, 13);
+            this.label8.TabIndex = 14;
+            this.label8.Text = "Target";
+            // 
             // SearchCmdCtrl
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.AutoScroll = true;
             this.Controls.Add(this.panel1);
             this.Controls.Add(this.toolStrip1);
             this.Name = "SearchCmdCtrl";
             this.Size = new System.Drawing.Size(332, 392);
             this.panel1.ResumeLayout(false);
             this.panel1.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.grdOutputColumns)).EndInit();
             ((System.ComponentModel.ISupportInitialize)(this.numLimit)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.grdOutputColumns)).EndInit();
             this.ResumeLayout(false);
             this.PerformLayout();
 
@@ -228,7 +294,6 @@
 
         private System.Windows.Forms.ToolStrip toolStrip1;
         private System.Windows.Forms.Panel panel1;
-        private System.Windows.Forms.ComboBox cmbLayers;
         private System.Windows.Forms.Label label1;
         private System.Windows.Forms.DataGridView grdOutputColumns;
         private System.Windows.Forms.Label label6;
@@ -242,5 +307,11 @@
         private System.Windows.Forms.Label label2;
         private System.Windows.Forms.DataGridViewTextBoxColumn COL_NAME;
         private System.Windows.Forms.DataGridViewComboBoxColumn COL_PROPERTY;
+        private System.Windows.Forms.Button btnBrowseLayer;
+        private System.Windows.Forms.TextBox txtLayer;
+        private System.Windows.Forms.TextBox txtFrame;
+        private System.Windows.Forms.ComboBox cmbTargetFrame;
+        private System.Windows.Forms.Label label7;
+        private System.Windows.Forms.Label label8;
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/Commands/SearchCmdCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -30,6 +30,7 @@
 using OSGeo.MapGuide.ObjectModels.LayerDefinition;
 using OSGeo.MapGuide.ObjectModels.FeatureSource;
 using OSGeo.MapGuide.MaestroAPI;
+using Maestro.Editors.Common;
 
 namespace Maestro.Editors.WebLayout.Commands
 {
@@ -53,8 +54,11 @@
             _edsvc = service;
         }
 
+        private BindingList<IResultColumn> _columns = new BindingList<IResultColumn>();
+
         internal void Bind(ISearchCommand searchCommandType, IEditorService service)
         {
+            cmbTargetFrame.DataSource = Enum.GetValues(typeof(TargetType));
             _init = true;
             Bind(service);
             _cmd = searchCommandType;
@@ -64,32 +68,88 @@
 
             LoadLayers();
 
-            ComboBoxBinder.BindSelectedIndexChanged(cmbLayers, "Text", _cmd, "Layer");
+            if (!string.IsNullOrEmpty(_cmd.Layer))
+            {
+                foreach (var lyr in _layers)
+                {
+                    if (lyr.Name == _cmd.Layer)
+                    {
+                        txtLayer.Text = _cmd.Layer;
+                        txtLayer.Tag = lyr.ResourceId;
+                    }
+                }
+            }
+
+            TextBoxBinder.BindText(txtFrame, _cmd, "TargetFrame");
+            ComboBoxBinder.BindSelectedIndexChanged(cmbTargetFrame, "SelectedItem", _cmd, "Target");
+            TextBoxBinder.BindText(txtLayer, _cmd, "Layer");
             TextBoxBinder.BindText(txtFilter, _cmd, "Filter");
             TextBoxBinder.BindText(txtPrompt, _cmd, "Prompt");
 
             NumericBinder.BindValueChanged(numLimit, _cmd, "MatchLimit");
 
             UpdateColumns();
-            grdOutputColumns.DataSource = _cmd.ResultColumns;
+            foreach (var col in _cmd.ResultColumns.Column)
+            {
+                _columns.Add(col);
+            }
+            grdOutputColumns.DataSource = _columns;
+            _columns.AddingNew += OnAddingNewColumn;
+            _columns.ListChanged += OnColumnsChanged;
+        }
 
+        protected override void OnLoad(EventArgs e)
+        {
             _init = false;
         }
 
+        void OnAddingNewColumn(object sender, AddingNewEventArgs e)
+        {
+            e.NewObject = _cmd.ResultColumns.CreateColumn("MyProperty", _cls.Columns[0].Name);
+        }
+
+        void OnColumnsChanged(object sender, ListChangedEventArgs e)
+        {
+            switch (e.ListChangedType)
+            {
+                case ListChangedType.ItemAdded:
+                    {
+                        _cmd.ResultColumns.AddResultColumn(_columns[e.NewIndex]);
+                    }
+                    break;
+                case ListChangedType.Reset:
+                    {
+                        if (_cleanup)
+                            return;
+
+                        _cmd.ResultColumns.Clear();
+                    }
+                    break;
+            }
+        }
+
+        private bool _cleanup = false;
+
         protected override void UnsubscribeEventHandlers()
         {
+            _cleanup = true;
+
             if (_wl != null && _wl.Map != null)
                 _wl.Map.PropertyChanged -= OnWebLayoutPropertyChanged;
 
+            _columns.AddingNew -= OnAddingNewColumn;
+            _columns.ListChanged -= OnColumnsChanged;
+
             base.UnsubscribeEventHandlers();
         }
 
+        private List<MapLayerType> _layers;
+
         private void LoadLayers()
         {
             var map = (OSGeo.MapGuide.ObjectModels.MapDefinition.MapDefinition)_edsvc.ResourceService.GetResource(_wl.Map.ResourceId);
 
-            cmbLayers.DisplayMember = "Name";
-            cmbLayers.DataSource = map.MapLayer;
+            _layers = new List<MapLayerType>(map.MapLayer);
         }
 
         void OnWebLayoutPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -102,10 +162,9 @@
 
         private void btnBrowse_Click(object sender, EventArgs e)
         {
-            var layer = cmbLayers.SelectedItem as MapLayerType;
-            if (layer != null)
+            if (txtLayer.Tag != null)
             {
-                var ldf = (ILayerDefinition)_edsvc.ResourceService.GetResource(layer.ResourceId);
+                var ldf = (ILayerDefinition)_edsvc.ResourceService.GetResource(txtLayer.Tag.ToString());
                 var vl = (IVectorLayerDefinition)ldf.SubLayer;
 
                 var fs = (IFeatureSource)_edsvc.ResourceService.GetResource(vl.ResourceId);
@@ -118,22 +177,13 @@
             }
         }
 
-        private void cmbLayers_SelectedIndexChanged(object sender, EventArgs e)
-        {
-            if (_init)
-                return;
-
-            UpdateColumns();
-        }
-
         private void UpdateColumns()
         {
-            var layer = cmbLayers.SelectedItem as MapLayerType;
-            if (layer != null)
+            if (txtLayer.Tag != null)
             {
-                _cmd.ResultColumns.Clear();
+                _columns.Clear();
 
-                var ldf = (ILayerDefinition)_edsvc.ResourceService.GetResource(layer.ResourceId);
+                var ldf = (ILayerDefinition)_edsvc.ResourceService.GetResource(txtLayer.Tag.ToString());
                 var vl = (IVectorLayerDefinition)ldf.SubLayer;
 
                 _cls = _edsvc.FeatureService.GetFeatureSourceSchema(vl.ResourceId, vl.FeatureName);
@@ -142,5 +192,23 @@
                 COL_PROPERTY.DataSource = _cls.Columns;
             }
         }
+
+        private void txtLayer_TextChanged(object sender, EventArgs e)
+        {
+            if (_init)
+                return;
+
+            UpdateColumns();
+        }
+
+        private void btnBrowseLayer_Click(object sender, EventArgs e)
+        {
+            var layer = GenericItemSelectionDialog.SelectItem(Properties.Resources.SelectLayer, Properties.Resources.SelectLayer, _layers.ToArray(), "Name", "Name");
+            if (layer != null)
+            {
+                txtLayer.Tag = layer.ResourceId;
+                txtLayer.Text = layer.Name;
+            }
+        }
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/CustomCommandPropertyCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/CustomCommandPropertyCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/CustomCommandPropertyCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -44,8 +44,6 @@
             _edsvc = service;
         }
 
-        private ICommand _command;
-
         internal void Bind(ICommand command, IEditorService service)
         {
             Bind(service);

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -40,8 +40,8 @@
             this.btnMoveUp = new System.Windows.Forms.ToolStripButton();
             this.btnMoveDown = new System.Windows.Forms.ToolStripButton();
             this.trvMenuItems = new Aga.Controls.Tree.TreeViewAdv();
+            this.nodeIcon1 = new Aga.Controls.Tree.NodeControls.NodeIcon();
             this.nodeTextBox1 = new Aga.Controls.Tree.NodeControls.NodeTextBox();
-            this.nodeIcon1 = new Aga.Controls.Tree.NodeControls.NodeIcon();
             this.toolStrip2.SuspendLayout();
             this.SuspendLayout();
             // 
@@ -77,25 +77,25 @@
             // mnuBuiltin
             // 
             this.mnuBuiltin.Name = "mnuBuiltin";
-            this.mnuBuiltin.Size = new System.Drawing.Size(160, 22);
+            this.mnuBuiltin.Size = new System.Drawing.Size(176, 22);
             this.mnuBuiltin.Text = "Built-In Command";
             // 
             // mnuCustom
             // 
             this.mnuCustom.Name = "mnuCustom";
-            this.mnuCustom.Size = new System.Drawing.Size(160, 22);
+            this.mnuCustom.Size = new System.Drawing.Size(176, 22);
             this.mnuCustom.Text = "Custom Command";
             // 
             // toolStripSeparator3
             // 
             this.toolStripSeparator3.Name = "toolStripSeparator3";
-            this.toolStripSeparator3.Size = new System.Drawing.Size(157, 6);
+            this.toolStripSeparator3.Size = new System.Drawing.Size(173, 6);
             // 
             // toolStripMenuItem3
             // 
             this.toolStripMenuItem3.Image = global::Maestro.Editors.Properties.Resources.ui_splitter_horizontal;
             this.toolStripMenuItem3.Name = "toolStripMenuItem3";
-            this.toolStripMenuItem3.Size = new System.Drawing.Size(160, 22);
+            this.toolStripMenuItem3.Size = new System.Drawing.Size(176, 22);
             this.toolStripMenuItem3.Text = "Separator";
             this.toolStripMenuItem3.Click += new System.EventHandler(this.addSeparator_Click);
             // 
@@ -103,7 +103,7 @@
             // 
             this.toolStripMenuItem4.Image = global::Maestro.Editors.Properties.Resources.ui_menu;
             this.toolStripMenuItem4.Name = "toolStripMenuItem4";
-            this.toolStripMenuItem4.Size = new System.Drawing.Size(160, 22);
+            this.toolStripMenuItem4.Size = new System.Drawing.Size(176, 22);
             this.toolStripMenuItem4.Text = "Flyout Menu";
             this.toolStripMenuItem4.Click += new System.EventHandler(this.addFlyout_Click);
             // 
@@ -115,7 +115,8 @@
             this.btnDelete.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.btnDelete.Name = "btnDelete";
             this.btnDelete.Size = new System.Drawing.Size(23, 22);
-            this.btnDelete.Text = "toolStripButton2";
+            this.btnDelete.ToolTipText = "Delete selected item";
+            this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
             // 
             // toolStripSeparator4
             // 
@@ -130,7 +131,8 @@
             this.btnMoveUp.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.btnMoveUp.Name = "btnMoveUp";
             this.btnMoveUp.Size = new System.Drawing.Size(23, 22);
-            this.btnMoveUp.Text = "toolStripButton3";
+            this.btnMoveUp.ToolTipText = "Move selected item up";
+            this.btnMoveUp.Click += new System.EventHandler(this.btnMoveUp_Click);
             // 
             // btnMoveDown
             // 
@@ -140,10 +142,12 @@
             this.btnMoveDown.ImageTransparentColor = System.Drawing.Color.Magenta;
             this.btnMoveDown.Name = "btnMoveDown";
             this.btnMoveDown.Size = new System.Drawing.Size(23, 22);
-            this.btnMoveDown.Text = "toolStripButton4";
+            this.btnMoveDown.ToolTipText = "Move selected item down";
+            this.btnMoveDown.Click += new System.EventHandler(this.btnMoveDown_Click);
             // 
             // trvMenuItems
             // 
+            this.trvMenuItems.AllowDrop = true;
             this.trvMenuItems.BackColor = System.Drawing.SystemColors.Window;
             this.trvMenuItems.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
             this.trvMenuItems.DefaultToolTipProvider = null;
@@ -159,7 +163,17 @@
             this.trvMenuItems.Size = new System.Drawing.Size(150, 125);
             this.trvMenuItems.TabIndex = 2;
             this.trvMenuItems.SelectionChanged += new System.EventHandler(this.trvMenuItems_SelectionChanged);
+            this.trvMenuItems.DragOver += new System.Windows.Forms.DragEventHandler(this.trvMenuItems_DragOver);
+            this.trvMenuItems.DragDrop += new System.Windows.Forms.DragEventHandler(this.trvMenuItems_DragDrop);
+            this.trvMenuItems.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.trvMenuItems_ItemDrag);
             // 
+            // nodeIcon1
+            // 
+            this.nodeIcon1.DataPropertyName = "Icon";
+            this.nodeIcon1.LeftMargin = 1;
+            this.nodeIcon1.ParentColumn = null;
+            this.nodeIcon1.ScaleMode = Aga.Controls.Tree.ImageScaleMode.Clip;
+            // 
             // nodeTextBox1
             // 
             this.nodeTextBox1.DataPropertyName = "Label";
@@ -167,13 +181,6 @@
             this.nodeTextBox1.LeftMargin = 3;
             this.nodeTextBox1.ParentColumn = null;
             // 
-            // nodeIcon1
-            // 
-            this.nodeIcon1.DataPropertyName = "Icon";
-            this.nodeIcon1.LeftMargin = 1;
-            this.nodeIcon1.ParentColumn = null;
-            this.nodeIcon1.ScaleMode = Aga.Controls.Tree.ImageScaleMode.Clip;
-            // 
             // MenuEditorCtrl
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuEditorCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -50,41 +50,49 @@
 
         protected override void UnsubscribeEventHandlers()
         {
-            if (_wl != null && _wl.CommandSet != null)
-                //_wl.CommandSet.ListChanged -= CommandSet_ListChanged;
+            _wl.CommandSet.CustomCommandAdded -= OnCustomCommandAdded;
+            _wl.CommandSet.CustomCommandRemoved -= OnCustomCommandRemoved;
 
             base.UnsubscribeEventHandlers();
         }
 
         private IWebLayout _wl;
+        private IMenu _rootMenu;
+        private MenuTreeModel _model;
 
-        public void Bind(IEditorService service, IWebLayout wl)
+        public void Bind(IEditorService service, IWebLayout wl, IMenu menu)
         {
             Bind(service);
             _wl = wl;
-            //_wl.CommandSet.ListChanged += CommandSet_ListChanged;
-
+            _wl.CommandSet.CustomCommandAdded += OnCustomCommandAdded;
+            _wl.CommandSet.CustomCommandRemoved += OnCustomCommandRemoved;
+            _rootMenu = menu;
+            this.Model = _model = new MenuTreeModel(menu, wl);
+            
             InitBuiltinCommandMenu();
             InitCustomCommandMenu();
         }
 
-        void CommandSet_ListChanged(object sender, ListChangedEventArgs e)
+        public void AddCommand(ICommand cmd)
         {
-            switch (e.ListChangedType)
-            {
-                case ListChangedType.ItemAdded:
-                    {
+            var item = _wl.CreateCommandItem(cmd.Name);
+            _rootMenu.AddItem(item);
+            _model.Refresh();
+        }
 
-                    }
-                    break;
-                case ListChangedType.ItemDeleted:
-                    {
+        void OnCustomCommandRemoved(ICommand cmd)
+        {
+            RemoveCustomCommandEntry(mnuCustom, cmd);
 
-                    }
-                    break;
-            }
+            //Might have invalidated (and removed) some menu items, so refresh
+            _model.Refresh();
         }
 
+        void OnCustomCommandAdded(ICommand cmd)
+        {
+            AddCustomCommandEntry(mnuCustom, cmd);
+        }
+
         private void InitCustomCommandMenu()
         {
             foreach (var cmd in _wl.GetCustomCommands())
@@ -117,9 +125,18 @@
             if (find != null)
             {
                 tsi.DropDown.Items.Remove(find);
+                //Unreg property listener
+                if (_customCommandListeners.ContainsKey(find))
+                {
+                    var handler = _customCommandListeners[find];
+                    cmd.PropertyChanged -= handler;
+                    _customCommandListeners.Remove(find);
+                }
             }
         }
 
+        private Dictionary<ToolStripItem, PropertyChangedEventHandler> _customCommandListeners = new Dictionary<ToolStripItem, PropertyChangedEventHandler>();
+
         private void AddCustomCommandEntry(ToolStripMenuItem tsi, ICommand cmd)
         {
             var icon = CommandIconCache.GetStandardCommandIcon(cmd.ImageURL);
@@ -127,6 +144,14 @@
                 icon = Properties.Resources.question;
 
             ToolStripMenuItem mi = new ToolStripMenuItem(cmd.Name, icon, new EventHandler(OnAddCustomCommand));
+            //Reg property listener
+            PropertyChangedEventHandler handler = (sender, e) =>
+            {
+                if (e.PropertyName == "Name")
+                    mi.Text = cmd.Name;
+            };
+            _customCommandListeners[mi] = handler;
+            cmd.PropertyChanged += handler;
             mi.Tag = cmd;
             tsi.DropDown.Items.Add(mi);
         }
@@ -139,6 +164,28 @@
                 BuiltInCommandType cmdType = (BuiltInCommandType)tsi.Tag;
 
                 //Append to end of model of active treeview
+                var cmd = _wl.GetCommandByName(cmdType.ToString());
+                if (cmd != null)
+                {
+                    var ci = _wl.CreateCommandItem(cmd.Name);
+                    if (trvMenuItems.SelectedNode != null)
+                    {
+                        var fly = trvMenuItems.SelectedNode.Tag as FlyoutItem;
+                        if (fly != null)
+                        {
+                            fly.Tag.AddItem(ci);
+                        }
+                        else
+                        {
+                            _rootMenu.AddItem(ci);
+                        }
+                    }
+                    else
+                    {
+                        _rootMenu.AddItem(ci);
+                    }
+                    _model.Refresh();
+                }
             }
         }
 
@@ -149,177 +196,231 @@
             {
                 var cmd = (ICommand)tsi.Tag;
 
-                //Append to end of model of active treeview
+                var ci = _wl.CreateCommandItem(cmd.Name);
+
+                if (trvMenuItems.SelectedNode != null)
+                {
+                    var fly = trvMenuItems.SelectedNode.Tag as FlyoutItem;
+                    if (fly != null)
+                    {
+                        fly.Tag.AddItem(ci);
+                    }
+                    else
+                    {
+                        _rootMenu.AddItem(ci);
+                    }
+                }
+                else
+                {
+                    _rootMenu.AddItem(ci);
+                }
+                _model.Refresh();
             }
         }
 
         private void addSeparator_Click(object sender, EventArgs e)
         {
+            var sep = _wl.CreateSeparator();
+            if (trvMenuItems.SelectedNode != null)
+            {
+                var obj = trvMenuItems.SelectedNode.Tag;
 
+                var flyout = obj as FlyoutItem;
+                if (flyout != null)
+                {
+                    flyout.Tag.AddItem(sep);
+                }
+                else
+                {
+                    _rootMenu.AddItem(sep);
+                }
+                _model.Refresh();
+            }
+            else
+            {
+                _rootMenu.AddItem(sep);
+                _model.Refresh();
+            }
         }
 
         private void addFlyout_Click(object sender, EventArgs e)
         {
+            var fly = _wl.CreateFlyout(
+                Properties.Resources.NewFlyout,
+                Properties.Resources.NewFlyout,
+                Properties.Resources.NewFlyout,
+                null, null);
+            if (trvMenuItems.SelectedNode != null)
+            {
+                var obj = trvMenuItems.SelectedNode.Tag;
 
+                var flyout = obj as FlyoutItem;
+                if (flyout != null)
+                {
+                    flyout.Tag.AddItem(fly);
+                }
+                else
+                {
+                    _rootMenu.AddItem(fly);
+                }
+                _model.Refresh();
+            }
+            else
+            {
+                _rootMenu.AddItem(fly);
+                _model.Refresh();
+            }
         }
 
         private void trvMenuItems_SelectionChanged(object sender, EventArgs e)
         {
-        
+            EvaluateCommandState();
         }
-    }
 
-    internal abstract class ItemBase
-    {
-        public abstract string Label { get; }
-
-        public abstract Image Icon { get; }
-    }
-
-    internal class CommandItem : ItemBase
-    {
-        private ICommandItem _cmd;
-
-        public CommandItem(ICommandItem item, Image icon)
+        private void EvaluateCommandState()
         {
-            _cmd = item;
-            if (icon == null)
-                _icon = Properties.Resources.question;
-            else
-                _icon = icon;
+            btnDelete.Enabled = btnMoveDown.Enabled = btnMoveUp.Enabled =
+                (trvMenuItems.SelectedNode != null || (trvMenuItems.SelectedNodes != null && trvMenuItems.SelectedNodes.Count > 0));
         }
 
-        public override string Label
+        private void btnDelete_Click(object sender, EventArgs e)
         {
-            get
+            int removed = 0;
+            if (trvMenuItems.SelectedNode != null) 
             {
-                return _cmd.Command;
+                var it = trvMenuItems.SelectedNode.Tag as ItemBase;
+                if (it != null)
+                {
+                    var menu = it.Item.Parent ?? _rootMenu;
+                    menu.RemoveItem(it.Item);
+                    removed++;
+                }
             }
-        }
+            else if (trvMenuItems.SelectedNodes != null)
+            {
+                foreach (var node in trvMenuItems.SelectedNodes)
+                {
+                    var it = node.Tag as ItemBase;
+                    if (it != null)
+                    {
+                        var menu = it.Item.Parent ?? _rootMenu;
+                        menu.RemoveItem(it.Item);
+                        removed++;
+                    }
+                }
+            }
 
-        private Image _icon;
-
-        public override Image Icon
-        {
-            get { return _icon; }
+            if (removed > 0)
+            {
+                _model.Refresh();
+                EvaluateCommandState();
+            }
         }
-    }
 
-    internal class SeparatorItem : ItemBase
-    {
-        private ISeparatorItem _sep;
-
-        public SeparatorItem(ISeparatorItem sep)
+        private void btnMoveUp_Click(object sender, EventArgs e)
         {
-            _sep = sep;
+            if (trvMenuItems.SelectedNode != null)
+            {
+                var it = trvMenuItems.SelectedNode.Tag as ItemBase;
+                if (it != null)
+                {
+                    var parent = it.Item.Parent ?? _rootMenu;
+                    if (parent.MoveUp(it.Item))
+                    {
+                        _model.Refresh();
+                        EvaluateCommandState();
+                    }
+                }
+            }
         }
 
-        public override string Label
+        private void btnMoveDown_Click(object sender, EventArgs e)
         {
-            get { return _sep.Function.ToString(); }
+            if (trvMenuItems.SelectedNode != null)
+            {
+                var it = trvMenuItems.SelectedNode.Tag as ItemBase;
+                if (it != null)
+                {
+                    var parent = it.Item.Parent ?? _rootMenu;
+                    if (parent.MoveDown(it.Item))
+                    {
+                        _model.Refresh();
+                        EvaluateCommandState();
+                    }
+                }
+            }
         }
 
-        public override Image Icon
+        private void trvMenuItems_ItemDrag(object sender, ItemDragEventArgs e)
         {
-            get { return Properties.Resources.ui_splitter_horizontal; }
+            trvMenuItems.DoDragDrop(((TreeNodeAdv[])e.Item)[0], DragDropEffects.All);
         }
-    }
 
-    internal class FlyoutItem : ItemBase
-    {
-        private IFlyoutItem _fly;
-
-        public FlyoutItem(IFlyoutItem fly)
+        private void trvMenuItems_DragDrop(object sender, DragEventArgs e)
         {
-            _fly = fly;
-        }
+            var dragNode = e.Data.GetData(typeof(TreeNodeAdv)) as TreeNodeAdv;
+            if (dragNode == null)
+                return;
 
-        public override string Label
-        {
-            get { return _fly.Label; }
-        }
+            var item = ((ItemBase)dragNode.Tag).Item;
 
-        public override Image Icon
-        {
-            get { return Properties.Resources.ui_menu; }
-        }
+            //Detach from parent first
+            if (item.Parent != null)
+            {
+                var m = item.Parent;
+                m.RemoveItem(item);
+            }
+            else
+            {
+                _rootMenu.RemoveItem(item);
+            }
 
-        public IEnumerable<IUIItem> SubItem
-        {
-            get { return _fly.Items; }
-        }
-    }
+            var dropNode = trvMenuItems.GetNodeAt(trvMenuItems.PointToClient(new Point(e.X, e.Y)));
+            if (dropNode != null)
+            {
+                var dropItem = ((ItemBase)dropNode.Tag).Item;
 
-    internal class MenuTreeModel : ITreeModel
-    {
-        private IMenu _menu;
-        private IWebLayout _wl;
-
-        public MenuTreeModel(IMenu menu, IWebLayout wl)
-        {
-            _menu = menu;
-            _wl = wl;
-        }
-
-        public System.Collections.IEnumerable GetChildren(TreePath treePath)
-        {
-            if (treePath.IsEmpty())
-            {
-                foreach (var item in _menu.Items)
+                //Attach to new location
+                var menu = dropItem as IMenu;
+                if (menu != null)
                 {
-                    if (item.Function == UIItemFunctionType.Command)
+                    if (MessageBox.Show(Properties.Resources.QuestionAddItemToFlyout, "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                     {
-                        var ci = (ICommandItem)item;
-                        var cmd = _wl.GetCommandByName(ci.Command);
-                        Debug.Assert(cmd != null);
-
-                        yield return new CommandItem(ci, CommandIconCache.GetStandardCommandIcon(cmd.ImageURL));
+                        menu.AddItem(item);
                     }
-                    else if (item.Function == UIItemFunctionType.Flyout)
-                        yield return new FlyoutItem((IFlyoutItem)item);
                     else
-                        yield return new SeparatorItem((ISeparatorItem)item);
-                }
-            }
-            else
-            {
-                var flyout = treePath.LastNode as FlyoutItem;
-                if (flyout != null)
-                {
-                    foreach (var item in flyout.SubItem)
                     {
-                        if (item.Function == UIItemFunctionType.Command)
-                        {
-                            var ci = (ICommandItem)item;
-                            var cmd = _wl.GetCommandByName(ci.Command);
-                            Debug.Assert(cmd != null);
-
-                            yield return new CommandItem(ci, CommandIconCache.GetStandardCommandIcon(cmd.ImageURL));
-                        }
-                        else if (item.Function == UIItemFunctionType.Flyout)
-                            yield return new FlyoutItem((IFlyoutItem)item);
-                        else
-                            yield return new SeparatorItem((ISeparatorItem)item);
+                        //Add to same level as dropped item
+                        var pm = dropItem.Parent ?? _rootMenu;
+                        var idx = pm.GetIndex(dropItem);
+                        pm.Insert(item, idx);
                     }
                 }
                 else
                 {
-                    yield break;
+                    //Add to same level as dropped item
+                    var pm = dropItem.Parent ?? _rootMenu;
+                    var idx = pm.GetIndex(dropItem);
+                    pm.Insert(item, idx);
                 }
             }
+            else
+            {
+                _rootMenu.AddItem(item);
+            }
+            _model.Refresh();
         }
 
-        public bool IsLeaf(TreePath treePath)
+        private void trvMenuItems_DragOver(object sender, DragEventArgs e)
         {
-            return (treePath.LastNode as FlyoutItem) == null;
+            var node = e.Data.GetData(typeof(TreeNodeAdv)) as TreeNodeAdv;
+            if (node == null)
+            {
+                e.Effect = DragDropEffects.None;
+                return;
+            }
+
+            e.Effect = DragDropEffects.Move;
         }
-
-        public event EventHandler<TreeModelEventArgs> NodesChanged;
-
-        public event EventHandler<TreeModelEventArgs> NodesInserted;
-
-        public event EventHandler<TreeModelEventArgs> NodesRemoved;
-
-        public event EventHandler<TreePathEventArgs> StructureChanged;
     }
 }

Added: sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuModel.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuModel.cs	                        (rev 0)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/MenuModel.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -0,0 +1,200 @@
+#region Disclaimer / License
+// Copyright (C) 2010, Jackie Ng
+// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie at gmail.com
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// 
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+// 
+#endregion
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Aga.Controls.Tree;
+using OSGeo.MapGuide.ObjectModels.WebLayout;
+using System.Diagnostics;
+using System.Drawing;
+
+namespace Maestro.Editors.WebLayout
+{
+    internal abstract class ItemBase
+    {
+        public abstract string Label { get; }
+
+        public abstract Image Icon { get; }
+
+        public abstract IUIItem Item { get; }
+    }
+
+    internal abstract class ItemBase<T> : ItemBase where T : IUIItem
+    {
+        protected ItemBase(T item) { this.Tag = item; }
+
+        public T Tag
+        {
+            get;
+            private set;
+        }
+
+        public override IUIItem Item
+        {
+            get { return this.Tag; }
+        }
+    }
+
+    internal class CommandItem : ItemBase<ICommandItem>
+    {
+        public CommandItem(ICommandItem item, Image icon)
+            : base(item)
+        {
+            if (icon == null)
+                _icon = Properties.Resources.question;
+            else
+                _icon = icon;
+        }
+
+        public override string Label
+        {
+            get
+            {
+                return this.Tag.Command;
+            }
+        }
+
+        private Image _icon;
+
+        public override Image Icon
+        {
+            get { return _icon; }
+        }
+    }
+
+    internal class SeparatorItem : ItemBase<ISeparatorItem>
+    {
+        public SeparatorItem(ISeparatorItem sep)
+            : base(sep)
+        { }
+
+        public override string Label
+        {
+            get { return this.Tag.Function.ToString(); }
+        }
+
+        public override Image Icon
+        {
+            get { return Properties.Resources.ui_splitter_horizontal; }
+        }
+    }
+
+    internal class FlyoutItem : ItemBase<IFlyoutItem>
+    {
+        public FlyoutItem(IFlyoutItem fly)
+            : base(fly)
+        { }
+
+        public override string Label
+        {
+            get { return this.Tag.Label; }
+        }
+
+        public override Image Icon
+        {
+            get { return Properties.Resources.ui_menu; }
+        }
+
+        public IEnumerable<IUIItem> SubItem
+        {
+            get { return this.Tag.Items; }
+        }
+    }
+
+    internal class MenuTreeModel : ITreeModel
+    {
+        private IMenu _menu;
+        private IWebLayout _wl;
+
+        public MenuTreeModel(IMenu menu, IWebLayout wl)
+        {
+            _menu = menu;
+            _wl = wl;
+        }
+
+        public System.Collections.IEnumerable GetChildren(TreePath treePath)
+        {
+            if (treePath.IsEmpty())
+            {
+                foreach (var item in _menu.Items)
+                {
+                    if (item.Function == UIItemFunctionType.Command)
+                    {
+                        var ci = (ICommandItem)item;
+                        var cmd = _wl.GetCommandByName(ci.Command);
+                        Debug.Assert(cmd != null);
+
+                        yield return new CommandItem(ci, CommandIconCache.GetStandardCommandIcon(cmd.ImageURL));
+                    }
+                    else if (item.Function == UIItemFunctionType.Flyout)
+                        yield return new FlyoutItem((IFlyoutItem)item);
+                    else
+                        yield return new SeparatorItem((ISeparatorItem)item);
+                }
+            }
+            else
+            {
+                var flyout = treePath.LastNode as FlyoutItem;
+                if (flyout != null)
+                {
+                    foreach (var item in flyout.SubItem)
+                    {
+                        if (item.Function == UIItemFunctionType.Command)
+                        {
+                            var ci = (ICommandItem)item;
+                            var cmd = _wl.GetCommandByName(ci.Command);
+                            Debug.Assert(cmd != null);
+
+                            yield return new CommandItem(ci, CommandIconCache.GetStandardCommandIcon(cmd.ImageURL));
+                        }
+                        else if (item.Function == UIItemFunctionType.Flyout)
+                            yield return new FlyoutItem((IFlyoutItem)item);
+                        else
+                            yield return new SeparatorItem((ISeparatorItem)item);
+                    }
+                }
+                else
+                {
+                    yield break;
+                }
+            }
+        }
+
+        public bool IsLeaf(TreePath treePath)
+        {
+            return (treePath.LastNode as FlyoutItem) == null;
+        }
+
+        internal void Refresh()
+        {
+            var handler = this.StructureChanged;
+            if (handler != null)
+                handler(this, new TreePathEventArgs(TreePath.Empty));
+        }
+
+        public event EventHandler<TreeModelEventArgs> NodesChanged;
+
+        public event EventHandler<TreeModelEventArgs> NodesInserted;
+
+        public event EventHandler<TreeModelEventArgs> NodesRemoved;
+
+        public event EventHandler<TreePathEventArgs> StructureChanged;
+    }
+}

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutCommandsCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutCommandsCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutCommandsCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -38,7 +38,6 @@
         {
             InitializeComponent();
             _commands = new BindingList<ICommand>();
-            _commands.ListChanged += OnCommandSetListChanged;
             grdCommands.DataSource = _commands;
         }
 
@@ -58,6 +57,7 @@
             {
                 _commands.Add(cmd);
             }
+            _commands.ListChanged += OnCommandSetListChanged;
         }
 
         protected override void UnsubscribeEventHandlers()
@@ -69,6 +69,14 @@
 
         void OnCommandSetListChanged(object sender, ListChangedEventArgs e)
         {
+            switch (e.ListChangedType)
+            {
+                case ListChangedType.ItemAdded:
+                    {
+                        _wl.CommandSet.AddCommand(_commands[e.NewIndex]);
+                    }
+                    break;
+            }
             OnResourceChanged();
         }
 
@@ -127,21 +135,30 @@
         {
             var cmd = _wl.CreateInvokeUrlCommand();
             cmd.Description = cmd.Label = cmd.Tooltip = Properties.Resources.InvokeUrlCmdDescription;
-            _wl.CommandSet.AddCommand(cmd);
+            //_wl.CommandSet.AddCommand(cmd);
+            _commands.Add(cmd);
         }
 
         private void invokeScriptToolStripMenuItem_Click(object sender, EventArgs e)
         {
             var cmd = _wl.CreateInvokeScriptCommand();
             cmd.Description = cmd.Label = cmd.Tooltip = Properties.Resources.InvokeScriptCmdDescription;
-            _wl.CommandSet.AddCommand(cmd);
+            //_wl.CommandSet.AddCommand(cmd);
+            _commands.Add(cmd);
         }
 
         private void searchToolStripMenuItem_Click(object sender, EventArgs e)
         {
+            if (string.IsNullOrEmpty(_wl.Map.ResourceId))
+            {
+                MessageBox.Show(Properties.Resources.SpecifyMapForWebLayout);
+                return;
+            }
+
             var cmd = _wl.CreateSearchCommand();
             cmd.Description = cmd.Label = cmd.Tooltip = Properties.Resources.SearchCmdDescription;
-            _wl.CommandSet.AddCommand(cmd);
+            //_wl.CommandSet.AddCommand(cmd);
+            _commands.Add(cmd);
         }
 
         private void grdCommands_CellContentClick(object sender, DataGridViewCellEventArgs e)
@@ -197,6 +214,7 @@
                     using (new WaitCursor(this))
                     {
                         _wl.CommandSet.RemoveCommand(iurl);
+                        _commands.Remove(iurl);
                         int deleted = _wl.RemoveAllReferences(iurl.Name);
                         ClearCommandUI();
                     }
@@ -212,6 +230,7 @@
                     using (new WaitCursor(this))
                     {
                         _wl.CommandSet.RemoveCommand(iscr);
+                        _commands.Remove(iurl);
                         _wl.RemoveAllReferences(iscr.Name);
                         ClearCommandUI();
                     }
@@ -227,6 +246,7 @@
                     using (new WaitCursor(this))
                     {
                         _wl.CommandSet.RemoveCommand(srch);
+                        _commands.Remove(iurl);
                         _wl.RemoveAllReferences(srch.Name);
                         ClearCommandUI();
                     }

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutEditorCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutEditorCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutEditorCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -42,7 +42,7 @@
             this.webLayoutSettingsCtrl.HeaderText = "General Settings";
             this.webLayoutSettingsCtrl.Location = new System.Drawing.Point(0, 0);
             this.webLayoutSettingsCtrl.Name = "webLayoutSettingsCtrl";
-            this.webLayoutSettingsCtrl.Size = new System.Drawing.Size(574, 425);
+            this.webLayoutSettingsCtrl.Size = new System.Drawing.Size(540, 455);
             this.webLayoutSettingsCtrl.TabIndex = 0;
             // 
             // webLayoutMenusCtrl
@@ -52,9 +52,9 @@
             this.webLayoutMenusCtrl.HeaderBackgroundColor = System.Drawing.Color.LightSteelBlue;
             this.webLayoutMenusCtrl.HeaderFont = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
             this.webLayoutMenusCtrl.HeaderText = "Menus and Toolbars";
-            this.webLayoutMenusCtrl.Location = new System.Drawing.Point(0, 425);
+            this.webLayoutMenusCtrl.Location = new System.Drawing.Point(0, 455);
             this.webLayoutMenusCtrl.Name = "webLayoutMenusCtrl";
-            this.webLayoutMenusCtrl.Size = new System.Drawing.Size(574, 319);
+            this.webLayoutMenusCtrl.Size = new System.Drawing.Size(540, 289);
             this.webLayoutMenusCtrl.TabIndex = 1;
             // 
             // webLayoutCommandsCtrl
@@ -66,7 +66,7 @@
             this.webLayoutCommandsCtrl.HeaderText = "Commands";
             this.webLayoutCommandsCtrl.Location = new System.Drawing.Point(0, 744);
             this.webLayoutCommandsCtrl.Name = "webLayoutCommandsCtrl";
-            this.webLayoutCommandsCtrl.Size = new System.Drawing.Size(574, 319);
+            this.webLayoutCommandsCtrl.Size = new System.Drawing.Size(540, 449);
             this.webLayoutCommandsCtrl.TabIndex = 2;
             // 
             // WebLayoutEditorCtrl
@@ -78,7 +78,7 @@
             this.Controls.Add(this.webLayoutMenusCtrl);
             this.Controls.Add(this.webLayoutSettingsCtrl);
             this.Name = "WebLayoutEditorCtrl";
-            this.Size = new System.Drawing.Size(574, 496);
+            this.Size = new System.Drawing.Size(540, 500);
             this.ResumeLayout(false);
 
         }

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -37,14 +37,15 @@
             this.grdCommands = new System.Windows.Forms.DataGridView();
             this.groupBox1 = new System.Windows.Forms.GroupBox();
             this.TAB_CONTEXT_MENU = new System.Windows.Forms.TabPage();
+            this.edContextMenu = new Maestro.Editors.WebLayout.MenuEditorCtrl();
             this.nodeIcon4 = new Aga.Controls.Tree.NodeControls.NodeIcon();
             this.nodeTextBox4 = new Aga.Controls.Tree.NodeControls.NodeTextBox();
             this.TAB_TOOLBAR = new System.Windows.Forms.TabPage();
+            this.edToolbar = new Maestro.Editors.WebLayout.MenuEditorCtrl();
             this.tabMenus = new System.Windows.Forms.TabControl();
             this.TAB_TASK_MENU = new System.Windows.Forms.TabPage();
-            this.edToolbar = new Maestro.Editors.WebLayout.MenuEditorCtrl();
-            this.edContextMenu = new Maestro.Editors.WebLayout.MenuEditorCtrl();
             this.edTaskMenu = new Maestro.Editors.WebLayout.MenuEditorCtrl();
+            this.btnAddFromCmdSet = new System.Windows.Forms.Button();
             this.contentPanel.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.grdCommands)).BeginInit();
             this.groupBox1.SuspendLayout();
@@ -56,6 +57,7 @@
             // 
             // contentPanel
             // 
+            this.contentPanel.Controls.Add(this.btnAddFromCmdSet);
             this.contentPanel.Controls.Add(this.groupBox1);
             this.contentPanel.Controls.Add(this.tabMenus);
             this.contentPanel.Size = new System.Drawing.Size(682, 292);
@@ -110,8 +112,11 @@
             this.grdCommands.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
             this.grdCommands.Location = new System.Drawing.Point(14, 19);
             this.grdCommands.Name = "grdCommands";
-            this.grdCommands.Size = new System.Drawing.Size(393, 227);
+            this.grdCommands.Size = new System.Drawing.Size(343, 227);
             this.grdCommands.TabIndex = 1;
+            this.grdCommands.CellClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.grdCommands_CellClick);
+            this.grdCommands.DragLeave += new System.EventHandler(this.grdCommands_DragLeave);
+            this.grdCommands.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(this.grdCommands_CellClick);
             // 
             // groupBox1
             // 
@@ -119,9 +124,9 @@
                         | System.Windows.Forms.AnchorStyles.Left)
                         | System.Windows.Forms.AnchorStyles.Right)));
             this.groupBox1.Controls.Add(this.grdCommands);
-            this.groupBox1.Location = new System.Drawing.Point(250, 19);
+            this.groupBox1.Location = new System.Drawing.Point(300, 19);
             this.groupBox1.Name = "groupBox1";
-            this.groupBox1.Size = new System.Drawing.Size(420, 252);
+            this.groupBox1.Size = new System.Drawing.Size(370, 252);
             this.groupBox1.TabIndex = 2;
             this.groupBox1.TabStop = false;
             this.groupBox1.Text = "Available Commands";
@@ -136,6 +141,15 @@
             this.TAB_CONTEXT_MENU.Text = "Context Menu";
             this.TAB_CONTEXT_MENU.UseVisualStyleBackColor = true;
             // 
+            // edContextMenu
+            // 
+            this.edContextMenu.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.edContextMenu.Location = new System.Drawing.Point(0, 0);
+            this.edContextMenu.Model = null;
+            this.edContextMenu.Name = "edContextMenu";
+            this.edContextMenu.Size = new System.Drawing.Size(220, 226);
+            this.edContextMenu.TabIndex = 0;
+            // 
             // nodeIcon4
             // 
             this.nodeIcon4.DataPropertyName = "Icon";
@@ -160,6 +174,15 @@
             this.TAB_TOOLBAR.Text = "Toolbar";
             this.TAB_TOOLBAR.UseVisualStyleBackColor = true;
             // 
+            // edToolbar
+            // 
+            this.edToolbar.Dock = System.Windows.Forms.DockStyle.Fill;
+            this.edToolbar.Location = new System.Drawing.Point(0, 0);
+            this.edToolbar.Model = null;
+            this.edToolbar.Name = "edToolbar";
+            this.edToolbar.Size = new System.Drawing.Size(220, 226);
+            this.edToolbar.TabIndex = 0;
+            // 
             // tabMenus
             // 
             this.tabMenus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
@@ -184,24 +207,6 @@
             this.TAB_TASK_MENU.Text = "Task Menu";
             this.TAB_TASK_MENU.UseVisualStyleBackColor = true;
             // 
-            // edToolbar
-            // 
-            this.edToolbar.Dock = System.Windows.Forms.DockStyle.Fill;
-            this.edToolbar.Location = new System.Drawing.Point(0, 0);
-            this.edToolbar.Model = null;
-            this.edToolbar.Name = "edToolbar";
-            this.edToolbar.Size = new System.Drawing.Size(220, 226);
-            this.edToolbar.TabIndex = 0;
-            // 
-            // edContextMenu
-            // 
-            this.edContextMenu.Dock = System.Windows.Forms.DockStyle.Fill;
-            this.edContextMenu.Location = new System.Drawing.Point(0, 0);
-            this.edContextMenu.Model = null;
-            this.edContextMenu.Name = "edContextMenu";
-            this.edContextMenu.Size = new System.Drawing.Size(220, 226);
-            this.edContextMenu.TabIndex = 0;
-            // 
             // edTaskMenu
             // 
             this.edTaskMenu.Dock = System.Windows.Forms.DockStyle.Fill;
@@ -211,6 +216,17 @@
             this.edTaskMenu.Size = new System.Drawing.Size(214, 220);
             this.edTaskMenu.TabIndex = 0;
             // 
+            // btnAddFromCmdSet
+            // 
+            this.btnAddFromCmdSet.Enabled = false;
+            this.btnAddFromCmdSet.Location = new System.Drawing.Point(250, 132);
+            this.btnAddFromCmdSet.Name = "btnAddFromCmdSet";
+            this.btnAddFromCmdSet.Size = new System.Drawing.Size(44, 23);
+            this.btnAddFromCmdSet.TabIndex = 3;
+            this.btnAddFromCmdSet.Text = "<<";
+            this.btnAddFromCmdSet.UseVisualStyleBackColor = true;
+            this.btnAddFromCmdSet.Click += new System.EventHandler(this.btnAddFromCmdSet_Click);
+            // 
             // WebLayoutMenusCtrl
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -248,5 +264,6 @@
         private MenuEditorCtrl edToolbar;
         private MenuEditorCtrl edContextMenu;
         private MenuEditorCtrl edTaskMenu;
+        private System.Windows.Forms.Button btnAddFromCmdSet;
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutMenusCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -35,29 +35,95 @@
     [ToolboxItem(true)]
     public partial class WebLayoutMenusCtrl : EditorBindableCollapsiblePanel
     {
-        
-
         public WebLayoutMenusCtrl()
         {
             InitializeComponent();
         }
 
         private IWebLayout _wl;
+        private BindingList<ICommand> _cmds = new BindingList<ICommand>();
 
         public override void Bind(IEditorService service)
         {
             _wl = (IWebLayout)service.GetEditedResource();
+            _wl.CommandSet.CustomCommandAdded += OnCommandAdded;
+            _wl.CommandSet.CustomCommandRemoved += OnCommandRemoved;
 
-            edContextMenu.Bind(service, _wl);
-            edTaskMenu.Bind(service, _wl);
-            edToolbar.Bind(service, _wl);
+            edContextMenu.Bind(service, _wl, _wl.ContextMenu);
+            edTaskMenu.Bind(service, _wl, _wl.TaskPane.TaskBar);
+            edToolbar.Bind(service, _wl, _wl.ToolBar);
 
-            edContextMenu.Model = new MenuTreeModel(_wl.ContextMenu, _wl);
-            edTaskMenu.Model = new MenuTreeModel(_wl.TaskPane.TaskBar, _wl);
-            edToolbar.Model = new MenuTreeModel(_wl.ToolBar, _wl);
+            foreach (var cmd in _wl.CommandSet.Commands)
+            {
+                _cmds.Add(cmd);
+            }
+            grdCommands.DataSource = _cmds;
+        }
 
-            grdCommands.DataSource = _wl.CommandSet;
+        protected override void UnsubscribeEventHandlers()
+        {
+            base.UnsubscribeEventHandlers();
+
+            _wl.CommandSet.CustomCommandAdded -= OnCommandAdded;
+            _wl.CommandSet.CustomCommandRemoved -= OnCommandRemoved;
         }
 
+        void OnCommandRemoved(ICommand cmd)
+        {
+            _cmds.Remove(cmd);
+        }
+
+        void OnCommandAdded(ICommand cmd)
+        {
+            _cmds.Add(cmd);
+        }
+
+        private void grdCommands_DragLeave(object sender, EventArgs e)
+        {
+            ICommand cmd = GetSelectedCommand();
+
+            if (cmd != null)
+                grdCommands.DoDragDrop(cmd, DragDropEffects.All);
+        }
+
+        private ICommand GetSelectedCommand()
+        {
+            ICommand cmd = null;
+            if (grdCommands.SelectedRows.Count == 1)
+                cmd = grdCommands.SelectedRows[0].DataBoundItem as ICommand;
+            else if (grdCommands.SelectedCells.Count == 1)
+                cmd = grdCommands.Rows[grdCommands.SelectedCells[0].RowIndex].DataBoundItem as ICommand;
+            return cmd;
+        }
+
+        private void grdCommands_CellClick(object sender, DataGridViewCellEventArgs e)
+        {
+            if (grdCommands.SelectedCells.Count == 1)
+            {
+                var cell = grdCommands.SelectedCells[0];
+                grdCommands.ClearSelection();
+                grdCommands.Rows[cell.RowIndex].Selected = true;
+                btnAddFromCmdSet.Enabled = true;
+            }
+            else
+            {
+                btnAddFromCmdSet.Enabled = false;
+            }
+        }
+
+        private void btnAddFromCmdSet_Click(object sender, EventArgs e)
+        {
+            var cmd = GetSelectedCommand();
+            if (cmd != null && tabMenus.SelectedIndex >= 0)
+            {
+                var tab = tabMenus.TabPages[tabMenus.SelectedIndex];
+                if (tab == TAB_CONTEXT_MENU)
+                    edContextMenu.AddCommand(cmd);
+                else if (tab == TAB_TASK_MENU)
+                    edTaskMenu.AddCommand(cmd);
+                else if (tab == TAB_TOOLBAR)
+                    edToolbar.AddCommand(cmd);
+            }
+        }
     }
 }

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.Designer.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.Designer.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.Designer.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -141,6 +141,7 @@
             this.btnBrowse.TabIndex = 4;
             this.btnBrowse.Text = "...";
             this.btnBrowse.UseVisualStyleBackColor = true;
+            this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
             // 
             // groupBox1
             // 

Modified: sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.cs
===================================================================
--- sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/Maestro.Editors/WebLayout/WebLayoutSettingsCtrl.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -28,6 +28,8 @@
 using Maestro.Editors.Common;
 using OSGeo.MapGuide.ObjectModels.WebLayout;
 using OSGeo.MapGuide.MaestroAPI.ObjectModels;
+using Maestro.Editors.Generic;
+using OSGeo.MapGuide.MaestroAPI;
 
 namespace Maestro.Editors.WebLayout
 {
@@ -154,5 +156,16 @@
 
             txtHyperlinkFrame.Enabled = (((TargetType)cmbHyperlinkTarget.SelectedItem) == TargetType.SpecifiedFrame);
         }
+
+        private void btnBrowse_Click(object sender, EventArgs e)
+        {
+            using (var picker = new ResourcePicker(_edsvc.ResourceService, ResourceTypes.MapDefinition, ResourcePickerMode.OpenResource))
+            {
+                if (picker.ShowDialog() == DialogResult.OK)
+                {
+                    _wl.Map.ResourceId = picker.ResourceID;
+                }
+            }
+        }
     }
 }

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSource.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSource.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSource.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -370,15 +370,16 @@
 
     partial class AttributeRelateType : IAttributeRelation
     {
-        bool? IAttributeRelation.ForceOneToOne
+        bool IAttributeRelation.ForceOneToOne
         {
             get
             {
-                throw new NotImplementedException();
+                return this.ForceOneToOne;
             }
             set
             {
-                throw new NotImplementedException();
+                this.ForceOneToOne = value;
+                this.ForceOneToOneSpecified = true;
             }
         }
 

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSourceInterfaces.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSourceInterfaces.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/FeatureSourceInterfaces.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -24,6 +24,7 @@
 using OSGeo.MapGuide.ObjectModels.Common;
 using OSGeo.MapGuide.MaestroAPI;
 using System.ComponentModel;
+using System.IO;
 
 namespace OSGeo.MapGuide.ObjectModels.FeatureSource
 {
@@ -74,6 +75,8 @@
         void AddExtension(IFeatureSourceExtension ext);
 
         void RemoveExtension(IFeatureSourceExtension ext);
+
+        string ConfigurationDocument { get; set; }
     }
 
     public interface ISpatialContextInfo
@@ -131,7 +134,7 @@
         /// <summary>
         /// Gets or sets whether to force 1:1 cardinality
         /// </summary>
-        bool? ForceOneToOne { get; set; }
+        bool ForceOneToOne { get; set; }
 
         /// <summary>
         /// Gets the type of join
@@ -176,6 +179,35 @@
 
     public static class FeatureSourceExtensions
     {
+        public static string GetConfigurationContent(this IFeatureSource fs)
+        {
+            Check.NotNull(fs, "fs");
+            if (string.IsNullOrEmpty(fs.ConfigurationDocument))
+                return string.Empty;
+
+            var content = fs.GetResourceData(fs.ConfigurationDocument);
+            if (content != null)
+            {
+                using (var sr = new StreamReader(content))
+                {
+                    return sr.ReadToEnd();
+                }
+            }
+            return string.Empty;
+        }
+
+        public static void SetConfigurationContent(this IFeatureSource fs, string xmlContent)
+        {
+            Check.NotNull(fs, "fs");
+            if (string.IsNullOrEmpty(fs.ConfigurationDocument))
+                fs.ConfigurationDocument = "config.xml";
+
+            using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlContent)))
+            {
+                fs.SetResourceData(fs.ConfigurationDocument, ResourceDataType.Stream, ms);
+            }
+        }
+
         /// <summary>
         /// Convenience method to return the description of this feature source
         /// </summary>

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinition.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -200,6 +200,66 @@
             return layer;
         }
 
+
+        public IMapLayer AddLayer(IMapLayer layerToInsertAbove, string groupName, string layerName, string resourceId)
+        {
+            var layer = new MapLayerType()
+            {
+                Parent = this,
+                ExpandInLegend = true,
+                LegendLabel = layerName,
+                Name = layerName,
+                ResourceId = resourceId,
+                ShowInLegend = true,
+                Visible = true,
+                Selectable = true
+            };
+            //TODO: Throw exception if adding to non-existent group?
+            layer.Group = string.IsNullOrEmpty(groupName) ? string.Empty : groupName;
+
+            if (layerToInsertAbove != null)
+            {
+                var clayerToInsertAbove = layerToInsertAbove as MapLayerType;
+                if (clayerToInsertAbove != null)
+                {
+                    var idx = this.MapLayer.IndexOf(clayerToInsertAbove);
+                    if (idx >= 0)
+                    {
+                        this.MapLayer.Insert(idx, layer);
+                    }
+                    else
+                    {
+                        this.MapLayer.Add(layer);
+                    }
+                }
+                else
+                {
+                    this.MapLayer.Add(layer);
+                }
+            }
+            else
+            {
+                this.MapLayer.Add(layer);
+            }
+            OnPropertyChanged("MapLayer");
+
+            if (this.MapLayer.Count == 1) //First one
+            {
+                var ldf = (ILayerDefinition)this.CurrentConnection.ResourceService.GetResource(layer.ResourceId);
+                if (string.IsNullOrEmpty(this.CoordinateSystem))
+                {
+                    this.CoordinateSystem = ldf.GetCoordinateSystemWkt();
+                }
+                if (IsEmpty(this.Extents))
+                {
+                    var env = ldf.GetSpatialExtent(true);
+                    ((IMapDefinition)this).SetExtents(env.MinX, env.MinY, env.MaxX, env.MaxY);
+                }
+            }
+
+            return layer;
+        }
+
         private static bool IsEmpty(Box2DType box2DType)
         {
             return box2DType == null ||

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/MapDefinitionInterfaces.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -73,6 +73,18 @@
         /// <returns></returns>
         IMapLayer AddLayer(string groupName, string layerName, string resourceId);
 
+        /// <summary>
+        /// Adds a layer to this map. If this is the first layer to be added, the coordinate system 
+        /// of this map and its extents will be set to the coordinate system and extents of this layer
+        /// if this has not been set already.
+        /// </summary>
+        /// <param name="layerToInsertAbove">The layer to insert above in the draw order</param>
+        /// <param name="groupName"></param>
+        /// <param name="layerName"></param>
+        /// <param name="resourceId"></param>
+        /// <returns></returns>
+        IMapLayer AddLayer(IMapLayer layerToInsertAbove, string groupName, string layerName, string resourceId);
+
         void RemoveLayer(IMapLayer layer);
 
         int GetIndex(IMapLayer layer);
@@ -96,6 +108,26 @@
 
     public static class BaseMapDefinitionExtensions
     {
+        public static bool HasLayers(this IBaseMapGroup grp)
+        {
+            Check.NotNull(grp, "grp");
+            return new List<IBaseMapLayer>(grp.BaseMapLayer).Count > 0;
+        }
+
+        public static bool HasLayers(this IBaseMapDefinition map)
+        {
+            Check.NotNull(map, "map");
+            if (!map.HasGroups())
+                return false;
+
+            foreach (var group in map.BaseMapLayerGroup)
+            {
+                if (group.HasLayers())
+                    return true;
+            }
+            return false;
+        }
+
         public static bool HasGroups(this IBaseMapDefinition map)
         {
             Check.NotNull(map, "map");

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/ObjectFactory.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -439,7 +439,10 @@
 
         public static IAttributeRelation CreateAttributeRelation()
         {
-            return new AttributeRelateType() { RelateProperty = new System.ComponentModel.BindingList<RelatePropertyType>() };
+            return new AttributeRelateType() 
+            { 
+                RelateProperty = new System.ComponentModel.BindingList<RelatePropertyType>(),
+            };
         }
     }
 }

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayout.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -227,63 +227,63 @@
         private static void CreateDefaultToolbar(IWebLayout wl)
         {
             wl.ToolBar.AddItems(
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Print.ToString()),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.GetPrintablePage.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.Print.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.GetPrintablePage.ToString()),
             wl.CreateSeparator(),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Measure.ToString()),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Buffer.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.Measure.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.Buffer.ToString()),
             wl.CreateSeparator(),
             wl.CreateFlyout("Zoom", null, null, null, null,
-                wl.CreateCommand<CommandItemType>(BuiltInCommandType.PreviousView.ToString()),
-                wl.CreateCommand<CommandItemType>(BuiltInCommandType.NextView.ToString()),
-                wl.CreateCommand<CommandItemType>(BuiltInCommandType.RestoreView.ToString())
+                wl.CreateCommandItem(BuiltInCommandType.PreviousView.ToString()),
+                wl.CreateCommandItem(BuiltInCommandType.NextView.ToString()),
+                wl.CreateCommandItem(BuiltInCommandType.RestoreView.ToString())
             ),
             wl.CreateSeparator(),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomRectangle.ToString()),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomIn.ToString()),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomOut.ToString()),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Zoom.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.ZoomRectangle.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.ZoomIn.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.ZoomOut.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.Zoom.ToString()),
             wl.CreateSeparator(),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Select.ToString()),
-            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Pan.ToString())
+            wl.CreateCommandItem(BuiltInCommandType.Select.ToString()),
+            wl.CreateCommandItem(BuiltInCommandType.Pan.ToString())
             );
         }
         private static void CreateDefaultContextMenu(IWebLayout wl)
         {
             wl.ContextMenu.AddItems(
-                            wl.CreateCommand<CommandItemType>(BuiltInCommandType.Select.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.ClearSelection.ToString()),
+                            wl.CreateCommandItem(BuiltInCommandType.Select.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.ClearSelection.ToString()),
                                 wl.CreateFlyout("Select More", null, null, null, null,
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.SelectRadius.ToString()),
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.SelectPolygon.ToString()),
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.SelectWithin.ToString())
+                                    wl.CreateCommandItem(BuiltInCommandType.SelectRadius.ToString()),
+                                    wl.CreateCommandItem(BuiltInCommandType.SelectPolygon.ToString()),
+                                    wl.CreateCommandItem(BuiltInCommandType.SelectWithin.ToString())
                                 ),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Pan.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.Pan.ToString()),
                                 wl.CreateSeparator(),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomRectangle.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomIn.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomOut.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Zoom.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.ZoomRectangle.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.ZoomIn.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.ZoomOut.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.Zoom.ToString()),
                                 wl.CreateFlyout("Zoom", null, null, null, null,
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.PreviousView.ToString()),
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.NextView.ToString()),
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.FitToWindow.ToString()),
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.RestoreView.ToString()),
-                                    wl.CreateCommand<CommandItemType>(BuiltInCommandType.ZoomToSelection.ToString())
+                                    wl.CreateCommandItem(BuiltInCommandType.PreviousView.ToString()),
+                                    wl.CreateCommandItem(BuiltInCommandType.NextView.ToString()),
+                                    wl.CreateCommandItem(BuiltInCommandType.FitToWindow.ToString()),
+                                    wl.CreateCommandItem(BuiltInCommandType.RestoreView.ToString()),
+                                    wl.CreateCommandItem(BuiltInCommandType.ZoomToSelection.ToString())
                                 ),
                                 wl.CreateSeparator(),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Measure.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Buffer.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.Measure.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.Buffer.ToString()),
                                 wl.CreateSeparator(),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Refresh.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.CopyMap.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.Refresh.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.CopyMap.ToString()),
                                 wl.CreateSeparator(),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Print.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.GetPrintablePage.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.ViewOptions.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.Print.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.GetPrintablePage.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.ViewOptions.ToString()),
                                 wl.CreateSeparator(),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.Help.ToString()),
-                                wl.CreateCommand<CommandItemType>(BuiltInCommandType.About.ToString())
+                                wl.CreateCommandItem(BuiltInCommandType.Help.ToString()),
+                                wl.CreateCommandItem(BuiltInCommandType.About.ToString())
                                 );
         }
 
@@ -658,7 +658,9 @@
                 DisableIfSelectionEmpty = false,
                 ImageURL = "../stdicons/icon_invokeurl.gif",
                 DisabledImageURL = "../stdicons/icon_invokeurl_disabled.gif",
-                TargetViewer = TargetViewerType.All
+                TargetViewer = TargetViewerType.All,
+                AdditionalParameter = new BindingList<ParameterPairType>(),
+                LayerSet = new BindingList<string>()
             };
         }
 
@@ -670,7 +672,10 @@
                 Target = TargetType.TaskPane,
                 TargetViewer = TargetViewerType.All,
                 DisabledImageURL = "../stdicons/icon_search_disabled.gif",
-                ImageURL = "../stdicons/icon_search.gif"
+                ImageURL = "../stdicons/icon_search.gif",
+                Filter = string.Empty,
+                MatchLimit = "100",
+                Prompt = string.Empty
             };
         }
 
@@ -732,9 +737,9 @@
             return flyout;
         }
 
-        public T CreateCommand<T>(string cmdName) where T : ICommandItem, new()
+        public ICommandItem CreateCommandItem(string cmdName) 
         {
-            return new T() { Function = UIItemFunctionType.Command, Command = cmdName };
+            return new CommandItemType() { Function = UIItemFunctionType.Command, Command = cmdName };
         }
 
         public ISeparatorItem CreateSeparator()
@@ -769,6 +774,10 @@
             }
         }
 
+        public event CommandEventHandler CustomCommandAdded;
+
+        public event CommandEventHandler CustomCommandRemoved;
+
         void ICommandSet.AddCommand(ICommand cmd)
         {
             var c = cmd as CommandType;
@@ -776,6 +785,12 @@
             {
                 this.CommandSet.Add(c);
                 OnPropertyChanged("CommandSet");
+                if (cmd is IInvokeUrlCommand || cmd is IInvokeScriptCommand || cmd is ISearchCommand)
+                {
+                    var handler = this.CustomCommandAdded;
+                    if (handler != null)
+                        handler(cmd);
+                }
             }
         }
 
@@ -786,6 +801,12 @@
             {
                 this.CommandSet.Remove(c);
                 OnPropertyChanged("CommandSet");
+                if (cmd is IInvokeUrlCommand || cmd is IInvokeScriptCommand || cmd is ISearchCommand)
+                {
+                    var handler = this.CustomCommandRemoved;
+                    if (handler != null)
+                        handler(cmd);
+                }
             }
         }
 
@@ -893,6 +914,7 @@
             if (it != null)
             {
                 this.Button.Add(it);
+                it.Parent = this;
                 OnPropertyChanged("Button");
             }
         }
@@ -903,9 +925,76 @@
             if (it != null)
             {
                 this.Button.Remove(it);
+                it.Parent = null;
                 OnPropertyChanged("Button");
             }
         }
+
+
+        public bool MoveUp(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.Button.IndexOf(it);
+                if (isrc > 0)
+                {
+                    var idst = isrc - 1;
+                    var src = this.Button[isrc];
+                    var dst = this.Button[idst];
+
+                    this.Button[isrc] = dst;
+                    this.Button[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        public bool MoveDown(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.Button.IndexOf(it);
+                if (isrc < this.Button.Count - 1)
+                {
+                    var idst = isrc + 1;
+                    var src = this.Button[isrc];
+                    var dst = this.Button[idst];
+
+                    this.Button[isrc] = dst;
+                    this.Button[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int GetIndex(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                return this.Button.IndexOf(it);
+            }
+            return -1;
+        }
+
+        public void Insert(IUIItem item, int index)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                it.Parent = this;
+                this.Button.Insert(index, it);
+            }
+        }
     }
 
     partial class InformationPaneType : IInformationPane
@@ -937,6 +1026,7 @@
             if (it != null)
             {
                 this.MenuItem.Add(it);
+                it.Parent = this;
                 OnPropertyChanged("MenuItem");
             }
         }
@@ -947,9 +1037,74 @@
             if (it != null)
             {
                 this.MenuItem.Remove(it);
+                it.Parent = null;
                 OnPropertyChanged("MenuItem");
             }
         }
+
+        public bool MoveUp(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.MenuItem.IndexOf(it);
+                if (isrc > 0)
+                {
+                    var idst = isrc - 1;
+                    var src = this.MenuItem[isrc];
+                    var dst = this.MenuItem[idst];
+
+                    this.MenuItem[isrc] = dst;
+                    this.MenuItem[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public bool MoveDown(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.MenuItem.IndexOf(it);
+                if (isrc < this.MenuItem.Count - 1)
+                {
+                    var idst = isrc + 1;
+                    var src = this.MenuItem[isrc];
+                    var dst = this.MenuItem[idst];
+
+                    this.MenuItem[isrc] = dst;
+                    this.MenuItem[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int GetIndex(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                return this.MenuItem.IndexOf(it);
+            }
+            return -1;
+        }
+
+        public void Insert(IUIItem item, int index)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                it.Parent = this;
+                this.MenuItem.Insert(index, it);
+            }
+        }
     }
 
     partial class TaskBarType : ITaskBar
@@ -976,6 +1131,7 @@
             if (it != null)
             {
                 this.MenuButton.Add(it);
+                it.Parent = this;
                 OnPropertyChanged("MenuButton");
             }
         }
@@ -986,10 +1142,75 @@
             if (it != null)
             {
                 this.MenuButton.Remove(it);
+                it.Parent = null;
                 OnPropertyChanged("MenuButton");
             }
         }
 
+        public bool MoveUp(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.MenuButton.IndexOf(it);
+                if (isrc > 0)
+                {
+                    var idst = isrc - 1;
+                    var src = this.MenuButton[isrc];
+                    var dst = this.MenuButton[idst];
+
+                    this.MenuButton[isrc] = dst;
+                    this.MenuButton[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public bool MoveDown(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.MenuButton.IndexOf(it);
+                if (isrc < this.MenuButton.Count - 1)
+                {
+                    var idst = isrc + 1;
+                    var src = this.MenuButton[isrc];
+                    var dst = this.MenuButton[idst];
+
+                    this.MenuButton[isrc] = dst;
+                    this.MenuButton[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int GetIndex(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                return this.MenuButton.IndexOf(it);
+            }
+            return -1;
+        }
+
+        public void Insert(IUIItem item, int index)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                it.Parent = this;
+                this.MenuButton.Insert(index, it);
+            }
+        }
+
         ITaskButton ITaskBar.Home
         {
             get { return this.Home; }
@@ -1112,6 +1333,7 @@
             if (i != null)
             {
                 this.SubItem.Add(i);
+                i.Parent = this;
                 OnPropertyChanged("SubItem");
             }
         }
@@ -1122,14 +1344,84 @@
             if (i != null)
             {
                 this.SubItem.Remove(i);
+                i.Parent = null;
                 OnPropertyChanged("SubItem");
             };
         }
+
+        public bool MoveUp(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.SubItem.IndexOf(it);
+                if (isrc > 0)
+                {
+                    var idst = isrc - 1;
+                    var src = this.SubItem[isrc];
+                    var dst = this.SubItem[idst];
+
+                    this.SubItem[isrc] = dst;
+                    this.SubItem[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public bool MoveDown(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                var isrc = this.SubItem.IndexOf(it);
+                if (isrc < this.SubItem.Count - 1)
+                {
+                    var idst = isrc + 1;
+                    var src = this.SubItem[isrc];
+                    var dst = this.SubItem[idst];
+
+                    this.SubItem[isrc] = dst;
+                    this.SubItem[idst] = src;
+
+                    OnPropertyChanged("Button");
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public int GetIndex(IUIItem item)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                return this.SubItem.IndexOf(it);
+            }
+            return -1;
+        }
+
+        public void Insert(IUIItem item, int index)
+        {
+            var it = item as UIItemType;
+            if (it != null)
+            {
+                it.Parent = this;
+                this.SubItem.Insert(index, it);
+            }
+        }
     }
 
     partial class UIItemType : IUIItem
     {
-        
+        [XmlIgnore]
+        public IMenu Parent
+        {
+            get;
+            set;
+        }
     }
 
     partial class CommandItemType : ICommandItem
@@ -1184,6 +1476,7 @@
             }
         }
 
+        [XmlIgnore]
         public BindingList<string> Layer
         {
             get 
@@ -1199,6 +1492,11 @@
 
     partial class SearchCommandType : ISearchCommand, IResultColumnSet
     {
+        IResultColumn IResultColumnSet.CreateColumn(string name, string property)
+        {
+            return new ResultColumnType() { Name = name, Property = property };
+        }
+
         IResultColumnSet ISearchCommand.ResultColumns
         {
             get 
@@ -1207,26 +1505,21 @@
             }
         }
 
-        int? ISearchCommand.MatchLimit
+        int ISearchCommand.MatchLimit
         {
             get
             {
                 int i;
-                if (int.TryParse(this.MatchLimit, out i))
-                    return i;
-
-                return null;
+                if (!int.TryParse(this.MatchLimit, out i))
+                {
+                    i = 100;
+                    this.MatchLimit = i.ToString();
+                }
+                return i;
             }
             set
             {
-                if (value.HasValue)
-                {
-                    this.MatchLimit = value.Value.ToString();
-                }
-                else
-                {
-                    this.MatchLimit = string.Empty;
-                }
+                this.MatchLimit = value.ToString();
             }
         }
 

Modified: sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayoutInterfaces.cs
===================================================================
--- sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayoutInterfaces.cs	2010-10-19 23:15:22 UTC (rev 5299)
+++ sandbox/maestro-3.0/OSGeo.MapGuide.MaestroAPI/ObjectModels/WebLayoutInterfaces.cs	2010-10-20 08:09:21 UTC (rev 5300)
@@ -202,7 +202,7 @@
 
         T CreateTargetedCommand<T>(string name, string label, string tooltip, string description, string iconName, TargetViewerType targets, TargetType target, string targetFrame) where T : ITargetedCommand, new();
 
-        T CreateCommand<T>(string cmdName) where T : ICommandItem, new();
+        ICommandItem CreateCommandItem(string cmdName);
 
         IInvokeUrlCommand CreateInvokeUrlCommand();
 
@@ -250,6 +250,8 @@
 
     public interface IUIItem
     {
+        IMenu Parent { get; }
+
         UIItemFunctionType Function { get; set; }
     }
 
@@ -282,6 +284,14 @@
 
         IEnumerable<IUIItem> Items { get; }
 
+        bool MoveUp(IUIItem item);
+
+        bool MoveDown(IUIItem item);
+
+        int GetIndex(IUIItem item);
+
+        void Insert(IUIItem item, int index);
+
         void AddItem(IUIItem item);
 
         void RemoveItem(IUIItem item);
@@ -347,6 +357,8 @@
     {
     }
 
+    public delegate void CommandEventHandler(ICommand cmd);
+
     public interface ICommandSet
     {
         int CommandCount { get; }
@@ -358,6 +370,10 @@
         void AddCommand(ICommand cmd);
 
         void RemoveCommand(ICommand cmd);
+
+        event CommandEventHandler CustomCommandAdded;
+
+        event CommandEventHandler CustomCommandRemoved;
     }
 
     public interface ICommand : ILocalizable, INotifyPropertyChanged
@@ -396,7 +412,7 @@
         
         string Filter { get; set; }
 
-        int? MatchLimit { get; set; }
+        int MatchLimit { get; set; }
     }
 
     public interface IResultColumnSet
@@ -405,6 +421,8 @@
 
         IEnumerable<IResultColumn> Column { get; }
 
+        IResultColumn CreateColumn(string name, string property);
+
         void AddResultColumn(IResultColumn col);
 
         void RemoveResultColumn(IResultColumn col);



More information about the mapguide-commits mailing list