#region Disclaimer / License // Copyright (C) 2010, Jackie Ng // http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@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.ComponentModel; using System.Drawing; using System.Data; using System.Text; using System.Windows.Forms; using ICSharpCode.Core.WinForms; using Aga.Controls.Tree; using Maestro.Base.Services; using OSGeo.MapGuide.MaestroAPI; using OSGeo.MapGuide.MaestroAPI.Resource; using ICSharpCode.Core; using Maestro.Base.UI.Preferences; using Maestro.Shared.UI; using Maestro.Base.Commands.SiteExplorer; using Maestro.Base.Commands; namespace Maestro.Base.UI { public partial class SiteExplorer : ViewContentBase, ISiteExplorer { private IServerConnection _conn; /// /// Internal use only. Do not invoke directly. Use for that /// public SiteExplorer() { InitializeComponent(); Application.Idle += new EventHandler(OnIdle); ndResource.ToolTipProvider = new RepositoryItemToolTipProvider(); ndResource.DrawText += new EventHandler(OnNodeDrawText); } void OnIdle(object sender, EventArgs e) { foreach (var item in tsSiteExplorer.Items) { if (item is IStatusUpdate) ((IStatusUpdate)item).UpdateStatus(); } } public string ConnectionName { get; private set; } public SiteExplorer(string name) : this() { this.ConnectionName = name; } private RepositoryTreeModel _model; protected override void OnLoad(EventArgs e) { this.Title = Properties.Resources.Content_SiteExplorer; this.Description = string.Format("{0}: {1}", Properties.Resources.Content_SiteExplorer, this.ConnectionName); var ts = ToolbarService.CreateToolStripItems("/Maestro/Shell/SiteExplorer/Toolbar", this, true); tsSiteExplorer.Items.AddRange(ts); var mgr = ServiceRegistry.GetService(); _conn = mgr.GetConnection(this.ConnectionName); var omgr = ServiceRegistry.GetService(); var clip = ServiceRegistry.GetService(); _model = new RepositoryTreeModel(_conn, trvResources, this.ConnectionName, omgr, clip); trvResources.Model = _model; } public override bool AllowUserClose { get { return false; } } public override ViewRegion DefaultRegion { get { return ViewRegion.Left; } } public void RefreshModel() { RefreshModel(null); } public void RefreshModel(string resId) { if (!string.IsNullOrEmpty(resId)) { var rid = new ResourceIdentifier(resId); if (!rid.IsFolder) resId = rid.ParentFolder; //If this node is not initially expanded, we get NRE on refresh ExpandNode(resId); var path = _model.GetPathFromResourceId(resId); var node = trvResources.FindNode(path, true); if (node != null) { //Walk back up until node has children. We want to refresh from this node down while (node.Children.Count == 0 && node != trvResources.Root) node = node.Parent; } trvResources.SelectedNode = node; } _model.Refresh(); trvResources.Root.Children[0].Expand(); } private void trvResources_MouseDoubleClick(object sender, MouseEventArgs e) { TreeNodeAdv node = trvResources.GetNodeAt(new Point(e.X, e.Y)); if (node != null) { var item = node.Tag as RepositoryItem; if (item != null && !item.IsFolder) { var resMgr = ServiceRegistry.GetService(); resMgr.Open(item.ResourceId, _conn, false, this); } } } private void trvResources_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { var items = this.SelectedItems; if (items.Length > 0) { if (items.Length == 1) //Single select { RepositoryItem item = items[0]; if (item.IsFolder) MenuService.ShowContextMenu(this, "/Maestro/Shell/SiteExplorer/SelectedFolder", trvResources, e.X, e.Y); else MenuService.ShowContextMenu(this, "/Maestro/Shell/SiteExplorer/SelectedDocument", trvResources, e.X, e.Y); } else //Multi select { //All must be uniform type int folderCount = 0; foreach (var item in items) { if (item.IsFolder) folderCount++; } if (folderCount == 0) //All selected documents { MenuService.ShowContextMenu(this, "/Maestro/Shell/SiteExplorer/SelectedDocuments", trvResources, e.X, e.Y); } else if (folderCount == items.Length) //All selected folders { MenuService.ShowContextMenu(this, "/Maestro/Shell/SiteExplorer/SelectedFolders", trvResources, e.X, e.Y); } else //Mixed selection { MenuService.ShowContextMenu(this, "/Maestro/Shell/SiteExplorer/SelectedMixedResources", trvResources, e.X, e.Y); } } } } } public RepositoryItem[] SelectedItems { get { List items = new List(); if (trvResources.SelectedNodes.Count > 0) { foreach (var node in trvResources.SelectedNodes) { items.Add((RepositoryItem)node.Tag); } } return items.ToArray(); } } private void trvResources_Expanding(object sender, TreeViewAdvEventArgs e) { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { this.Cursor = Cursors.WaitCursor; })); } else { this.Cursor = Cursors.WaitCursor; } } private void trvResources_Expanded(object sender, TreeViewAdvEventArgs e) { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { this.Cursor = Cursors.Default; })); } else { this.Cursor = Cursors.Default; } } public void ExpandNode(string folderId) { if ("Library://".Equals(folderId)) return; var path = _model.GetPathFromResourceId(folderId); if (path != null) { var node = trvResources.FindNode(path, true); if (node != null) { node.IsExpanded = true; } } } public void SelectNode(string resourceId) { var path = _model.GetPathFromResourceId(resourceId); if (path != null) { var node = trvResources.FindNode(path, true); if (node != null) { trvResources.SelectedNode = node; } } } public void FlagNode(string resourceId, NodeFlagAction action) { var path = _model.GetPathFromResourceId(resourceId); if (path != null) { var node = trvResources.FindNode(path, true); if (node != null) { var item = (RepositoryItem)node.Tag; switch (action) { //case NodeFlagAction.IndicateCopy: //case NodeFlagAction.IndicateCut: // item.IsClipboarded = true; // break; case NodeFlagAction.HighlightDirty: item.IsDirty = true; break; case NodeFlagAction.HighlightOpen: item.IsOpen = true; break; case NodeFlagAction.None: item.Reset(); break; } } } } void OnNodeDrawText(object sender, Aga.Controls.Tree.NodeControls.DrawEventArgs e) { if (e.Node.Tag == null) return; var ocolor = PropertyService.Get(ConfigProperties.OpenColor, Color.LightGreen); var dcolor = PropertyService.Get(ConfigProperties.DirtyColor, Color.Pink); var item = (RepositoryItem)e.Node.Tag; var ctx = e.Context; if (item.ClipboardState != RepositoryItem.ClipboardAction.None) { var oldFont = e.Font; e.Font = new Font(oldFont.FontFamily, oldFont.Size, oldFont.Style | FontStyle.Italic); } if (item.IsDirty) e.BackgroundBrush = new SolidBrush(dcolor); 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 rids = new List(); 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) { //See if the mouse is currently over a node var node = trvResources.GetNodeAt(trvResources.PointToClient(new Point(e.X, e.Y))); SiteExplorerDragDropHandler.OnDragDrop(this, e, node); } else { //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 resIds = new List(); 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) { SiteExplorerDragDropHandler.OnDragEnter(this, e); } else { //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 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)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); _conn.ResourceService.MoveResourceWithReferences(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 folders = new Dictionary(); 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)dlg.RunOperationAsync(wb, worker, folderId, resIds); return new List(affectedFolders).ToArray(); } private void trvResources_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Delete) { new DeleteSelectedItemsCommand().Run(); } } } }