diff --git a/mRemoteV1/Properties/Resources.Designer.cs b/mRemoteV1/Properties/Resources.Designer.cs index a76bf5d6..84b6fe23 100644 --- a/mRemoteV1/Properties/Resources.Designer.cs +++ b/mRemoteV1/Properties/Resources.Designer.cs @@ -270,6 +270,16 @@ namespace mRemoteNG { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ConnectedOverlay { + get { + object obj = ResourceManager.GetObject("ConnectedOverlay", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/mRemoteV1/Properties/Resources.resx b/mRemoteV1/Properties/Resources.resx index 3dcd32c7..dda31e5f 100644 --- a/mRemoteV1/Properties/Resources.resx +++ b/mRemoteV1/Properties/Resources.resx @@ -523,4 +523,7 @@ ..\Resources\Images\FamFamFam\exclamation.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Images\ConnectedOverlay.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/mRemoteV1/Resources/Images/ConnectedOverlay.png b/mRemoteV1/Resources/Images/ConnectedOverlay.png new file mode 100644 index 00000000..4baac4bb Binary files /dev/null and b/mRemoteV1/Resources/Images/ConnectedOverlay.png differ diff --git a/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs b/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs index 46347eea..b36aff7a 100644 --- a/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs +++ b/mRemoteV1/Tools/ConnectionsTreeToMenuItemsConverter.cs @@ -6,15 +6,16 @@ using mRemoteNG.App; using mRemoteNG.Connection; using mRemoteNG.Container; using mRemoteNG.Tree; +using mRemoteNG.UI.Controls; namespace mRemoteNG.Tools { public class ConnectionsTreeToMenuItemsConverter { + private readonly StatusImageList _statusImageList = new StatusImageList(); public MouseEventHandler MouseUpEventHandler { get; set; } - public IEnumerable CreateToolStripDropDownItems(ConnectionTreeModel connectionTreeModel) { var rootNodes = connectionTreeModel.RootNodes; @@ -49,26 +50,15 @@ namespace mRemoteNG.Tools var menuItem = new ToolStripMenuItem { Text = node.Name, - Tag = node + Tag = node, + Image = _statusImageList.GetImage(node) }; var nodeAsContainer = node as ContainerInfo; if (nodeAsContainer != null) { - menuItem.Image = Resources.Folder; - menuItem.Tag = nodeAsContainer; AddSubMenuNodes(nodeAsContainer.Children, menuItem); } - else if (node.GetTreeNodeType() == TreeNodeType.PuttySession) - { - menuItem.Image = Resources.PuttySessions; - menuItem.Tag = node; - } - else if (node.GetTreeNodeType() == TreeNodeType.Connection) - { - menuItem.Image = Resources.Pause; - menuItem.Tag = node; - } menuItem.MouseUp += MouseUpEventHandler; return menuItem; diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs index 2c3c0b1c..637ff174 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.Designer.cs @@ -7,19 +7,6 @@ /// private System.ComponentModel.IContainer components = null; - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - #region Component Designer generated code /// diff --git a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs index 574d74db..337ff811 100644 --- a/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs +++ b/mRemoteV1/UI/Controls/ConnectionTree/ConnectionTree.cs @@ -20,6 +20,7 @@ namespace mRemoteNG.UI.Controls private ConnectionTreeModel _connectionTreeModel; private readonly ConnectionTreeDragAndDropHandler _dragAndDropHandler = new ConnectionTreeDragAndDropHandler(); private readonly PuttySessionsManager _puttySessionsManager = PuttySessionsManager.Instance; + private readonly StatusImageList _statusImageList = new StatusImageList(); public ConnectionInfo SelectedNode { @@ -46,7 +47,6 @@ namespace mRemoteNG.UI.Controls } } - public ConnectionTree() { InitializeComponent(); @@ -54,12 +54,22 @@ namespace mRemoteNG.UI.Controls UseOverlays = false; } + protected override void Dispose(bool disposing) + { + if (disposing) + { + components?.Dispose(); + _statusImageList?.Dispose(); + } + base.Dispose(disposing); + } + + #region ConnectionTree Setup private void SetupConnectionTreeView() { - var imageList = new StatusImageList(); - SmallImageList = imageList.GetImageList(); - AddColumns(imageList.ImageGetter); + SmallImageList = _statusImageList.ImageList; + AddColumns(_statusImageList.ImageGetter); LinkModelToView(); SetupDropSink(); SetEventHandlers(); @@ -144,7 +154,13 @@ namespace mRemoteNG.UI.Controls { //TODO for some reason property changed events are getting triggered twice for each changed property. should be just once. cant find source of duplication var property = propertyChangedEventArgs.PropertyName; - if (property != "Name" && property != "OpenConnections") return; + if (property != nameof(ConnectionInfo.Name) + && property != nameof(ConnectionInfo.OpenConnections) + && property != nameof(ConnectionInfo.Icon)) + { + return; + } + var senderAsConnectionInfo = sender as ConnectionInfo; if (senderAsConnectionInfo != null) RefreshObject(senderAsConnectionInfo); diff --git a/mRemoteV1/UI/Controls/StatusImageList.cs b/mRemoteV1/UI/Controls/StatusImageList.cs index b5a2413d..aa8f073e 100644 --- a/mRemoteV1/UI/Controls/StatusImageList.cs +++ b/mRemoteV1/UI/Controls/StatusImageList.cs @@ -9,49 +9,104 @@ using mRemoteNG.Tree.Root; namespace mRemoteNG.UI.Controls { - public class StatusImageList + public class StatusImageList : IDisposable { - public ImageList GetImageList() + public ImageList ImageList { get; } + + public StatusImageList() { - var imageList = new ImageList + ImageList = new ImageList { ColorDepth = ColorDepth.Depth32Bit, ImageSize = new Size(16, 16), TransparentColor = Color.Transparent }; - FillImageList(imageList); - return imageList; + + FillImageList(ImageList); } public object ImageGetter(object rowObject) { - if (rowObject is RootPuttySessionsNodeInfo) return "PuttySessions"; - if (rowObject is RootNodeInfo) return "Root"; - if (rowObject is ContainerInfo) return "Folder"; - var connection = rowObject as ConnectionInfo; - if (connection == null) return ""; - return connection.OpenConnections.Count > 0 ? "Play" : "Pause"; + return GetKey(rowObject as ConnectionInfo); } - private void FillImageList(ImageList imageList) + public Image GetImage(ConnectionInfo connectionInfo) + { + var key = GetKey(connectionInfo); + return ImageList.Images.ContainsKey(key) + ? ImageList.Images[key] + : null; + } + + public string GetKey(ConnectionInfo connectionInfo) + { + if (connectionInfo == null) return ""; + if (connectionInfo is RootPuttySessionsNodeInfo) return "PuttySessions"; + if (connectionInfo is RootNodeInfo) return "Root"; + if (connectionInfo is ContainerInfo) return "Folder"; + + return GetConnectionIcon(connectionInfo); + } + + private static string BuildConnectionIconName(string icon, bool connected) + { + var status = connected ? "Play" : "Default"; + return $"Connection_{icon}_{status}"; + } + + private const string DefaultConnectionIcon = ""; + + private string GetConnectionIcon(ConnectionInfo connection) + { + if (string.IsNullOrEmpty(connection.Icon)) + { + return DefaultConnectionIcon; + } + + var connected = connection.OpenConnections.Count > 0; + var name = BuildConnectionIconName(connection.Icon, connected); + if (!ImageList.Images.ContainsKey(name)) + { + var image = ConnectionIcon.FromString(connection.Icon); + if (image == null) + { + return DefaultConnectionIcon; + } + + ImageList.Images.Add(BuildConnectionIconName(connection.Icon, false), image); + ImageList.Images.Add(BuildConnectionIconName(connection.Icon, true), Overlay(image, Resources.ConnectedOverlay)); + + } + return name; + } + + private static Bitmap Overlay(Icon background, Image foreground) + { + var result = background.ToBitmap(); + using (var gr = Graphics.FromImage(result)) + { + gr.DrawImage(foreground, new Rectangle(0, 0, foreground.Width, foreground.Height)); + } + return result; + } + + private static void FillImageList(ImageList imageList) { try { - imageList.Images.Add(Resources.Root); - imageList.Images.SetKeyName(0, "Root"); - imageList.Images.Add(Resources.Folder); - imageList.Images.SetKeyName(1, "Folder"); - imageList.Images.Add(Resources.Play); - imageList.Images.SetKeyName(2, "Play"); - imageList.Images.Add(Resources.Pause); - imageList.Images.SetKeyName(3, "Pause"); - imageList.Images.Add(Resources.PuttySessions); - imageList.Images.SetKeyName(4, "PuttySessions"); + imageList.Images.Add("Root", Resources.Root); + imageList.Images.Add("Folder", Resources.Folder); + imageList.Images.Add("PuttySessions", Resources.PuttySessions); } catch (Exception ex) { Runtime.MessageCollector.AddExceptionStackTrace($"Unable to fill the image list of type {nameof(StatusImageList)}", ex); } } + + public void Dispose() + { + ImageList?.Dispose(); + } } } \ No newline at end of file diff --git a/mRemoteV1/mRemoteV1.csproj b/mRemoteV1/mRemoteV1.csproj index b3474d7f..bde11ba6 100644 --- a/mRemoteV1/mRemoteV1.csproj +++ b/mRemoteV1/mRemoteV1.csproj @@ -1194,6 +1194,7 @@ +